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.
Files changed (84) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/commands/commander.py +7 -7
  3. claude_mpm/cli/parsers/commander_parser.py +2 -2
  4. claude_mpm/cli/startup.py +36 -19
  5. claude_mpm/commander/chat/cli.py +38 -3
  6. claude_mpm/commander/config.py +5 -3
  7. claude_mpm/commander/daemon.py +9 -0
  8. claude_mpm/commander/frameworks/base.py +4 -1
  9. claude_mpm/commander/instance_manager.py +124 -11
  10. claude_mpm/core/claude_runner.py +22 -13
  11. claude_mpm/core/config.py +3 -3
  12. claude_mpm/core/config_constants.py +74 -9
  13. claude_mpm/core/constants.py +56 -12
  14. claude_mpm/core/interactive_session.py +5 -4
  15. claude_mpm/core/logging_utils.py +4 -2
  16. claude_mpm/core/network_config.py +148 -0
  17. claude_mpm/core/oneshot_session.py +7 -6
  18. claude_mpm/core/output_style_manager.py +5 -2
  19. claude_mpm/core/socketio_pool.py +13 -5
  20. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  21. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  22. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  23. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  24. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  25. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +1 -1
  26. claude_mpm/hooks/claude_hooks/event_handlers.py +262 -89
  27. claude_mpm/hooks/claude_hooks/hook_handler.py +81 -32
  28. claude_mpm/hooks/claude_hooks/installer.py +90 -28
  29. claude_mpm/hooks/claude_hooks/memory_integration.py +1 -1
  30. claude_mpm/hooks/claude_hooks/response_tracking.py +1 -1
  31. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  32. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  33. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  34. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  35. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  36. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  37. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  38. claude_mpm/hooks/claude_hooks/services/connection_manager.py +2 -2
  39. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +2 -2
  40. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  41. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  42. claude_mpm/hooks/claude_hooks/services/state_manager.py +2 -2
  43. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +2 -2
  44. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  45. claude_mpm/hooks/templates/pre_tool_use_template.py +6 -6
  46. claude_mpm/scripts/claude-hook-handler.sh +3 -3
  47. claude_mpm/scripts/start_activity_logging.py +0 -0
  48. claude_mpm/services/command_deployment_service.py +44 -26
  49. claude_mpm/services/hook_installer_service.py +77 -8
  50. claude_mpm/services/pm_skills_deployer.py +3 -2
  51. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/METADATA +1 -1
  52. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/RECORD +56 -78
  53. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
  54. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  55. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
  56. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
  57. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  63. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  64. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
  65. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  66. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
  67. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
  68. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
  69. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
  70. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
  71. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  72. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  73. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
  74. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
  75. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
  76. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
  80. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/WHEEL +0 -0
  81. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/entry_points.txt +0 -0
  82. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE +0 -0
  83. {claude_mpm-5.6.17.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  84. {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
- "socketio_default": 8765,
50
- "socketio_range_start": 8765,
51
- "socketio_range_end": 8775,
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 config.network.socketio_port
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 config.network.socketio_port_range[0]
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 config.network.socketio_port_range[1]
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
- return cls.DEFAULT_VALUES["ports"].get(port_type, 8765)
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")
@@ -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
- # Port ranges
44
- SOCKETIO_PORT_RANGE: Tuple[int, int] = (8765, 8785)
45
- DEFAULT_SOCKETIO_PORT = 8765
46
- DEFAULT_DASHBOARD_PORT = 8765
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
- # Use existing values from NetworkConfig
309
- DEFAULT_SOCKETIO = NetworkConfig.DEFAULT_SOCKETIO_PORT
310
- DEFAULT_DASHBOARD = NetworkConfig.DEFAULT_DASHBOARD_PORT
311
- PORT_RANGE_START = NetworkConfig.SOCKETIO_PORT_RANGE[0]
312
- PORT_RANGE_END = NetworkConfig.SOCKETIO_PORT_RANGE[1]
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 range(cls.PORT_RANGE_START, cls.PORT_RANGE_END + 1)
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
- # Deploy system agents
147
- if not self.runner.setup_agents():
148
- print("Continuing without native agents...")
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
@@ -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
- # Remove existing handlers
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
- # Deploy system agents
90
- if not self.runner.setup_agents():
91
- print("Continuing without native agents...")
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. This is a fresh install (file didn't exist before deployment)
362
- should_activate = current_style is None or is_fresh_install
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
@@ -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 = 8765
45
+ DEFAULT_DASHBOARD_PORT = 8767
38
46
  SOCKETIO_PORT_RANGE = (8765, 8785)
39
- DEFAULT_SOCKETIO_PORT = 8765
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):
@@ -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", "true").lower() != "false"
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 = {