claude-mpm 4.0.23__py3-none-any.whl → 4.0.28__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/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +4 -1
- claude_mpm/agents/BASE_PM.md +3 -0
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/cli/commands/agents.py +453 -113
- claude_mpm/cli/commands/aggregate.py +107 -15
- claude_mpm/cli/commands/cleanup.py +142 -10
- claude_mpm/cli/commands/config.py +358 -224
- claude_mpm/cli/commands/info.py +184 -75
- claude_mpm/cli/commands/mcp_command_router.py +5 -76
- claude_mpm/cli/commands/mcp_install_commands.py +68 -36
- claude_mpm/cli/commands/mcp_server_commands.py +30 -37
- claude_mpm/cli/commands/memory.py +331 -61
- claude_mpm/cli/commands/monitor.py +101 -7
- claude_mpm/cli/commands/run.py +368 -8
- claude_mpm/cli/commands/tickets.py +206 -24
- claude_mpm/cli/parsers/mcp_parser.py +3 -0
- claude_mpm/cli/shared/__init__.py +40 -0
- claude_mpm/cli/shared/argument_patterns.py +212 -0
- claude_mpm/cli/shared/command_base.py +234 -0
- claude_mpm/cli/shared/error_handling.py +238 -0
- claude_mpm/cli/shared/output_formatters.py +231 -0
- claude_mpm/config/agent_config.py +29 -8
- claude_mpm/core/container.py +6 -4
- claude_mpm/core/service_registry.py +4 -2
- claude_mpm/core/shared/__init__.py +17 -0
- claude_mpm/core/shared/config_loader.py +320 -0
- claude_mpm/core/shared/path_resolver.py +277 -0
- claude_mpm/core/shared/singleton_manager.py +208 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +14 -3
- claude_mpm/hooks/memory_integration_hook.py +11 -2
- claude_mpm/services/agents/deployment/agent_deployment.py +49 -23
- claude_mpm/services/agents/deployment/deployment_wrapper.py +71 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +1 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +43 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +4 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +11 -3
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +14 -5
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +89 -28
- claude_mpm/services/mcp_gateway/config/configuration.py +29 -0
- claude_mpm/services/mcp_gateway/registry/service_registry.py +22 -5
- claude_mpm/services/memory/builder.py +6 -1
- claude_mpm/services/response_tracker.py +3 -1
- claude_mpm/services/runner_configuration_service.py +15 -6
- claude_mpm/services/shared/__init__.py +20 -0
- claude_mpm/services/shared/async_service_base.py +219 -0
- claude_mpm/services/shared/config_service_base.py +292 -0
- claude_mpm/services/shared/lifecycle_service_base.py +317 -0
- claude_mpm/services/shared/manager_base.py +303 -0
- claude_mpm/services/shared/service_factory.py +308 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/METADATA +19 -13
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/RECORD +60 -44
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.28.dist-info}/top_level.txt +0 -0
claude_mpm/cli/commands/run.py
CHANGED
|
@@ -5,6 +5,12 @@ Run command implementation for claude-mpm.
|
|
|
5
5
|
|
|
6
6
|
WHY: This module handles the main 'run' command which starts Claude sessions.
|
|
7
7
|
It's the most commonly used command and handles both interactive and non-interactive modes.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISIONS:
|
|
10
|
+
- Use BaseCommand for consistent CLI patterns
|
|
11
|
+
- Leverage shared utilities for argument parsing and output formatting
|
|
12
|
+
- Maintain backward compatibility with existing functionality
|
|
13
|
+
- Support multiple output formats (json, yaml, table, text)
|
|
8
14
|
"""
|
|
9
15
|
|
|
10
16
|
import logging
|
|
@@ -14,13 +20,16 @@ import sys
|
|
|
14
20
|
import time
|
|
15
21
|
import webbrowser
|
|
16
22
|
from datetime import datetime
|
|
23
|
+
from typing import Dict, Any, Optional
|
|
17
24
|
|
|
18
25
|
from ...constants import LogLevel
|
|
19
26
|
from ...core.config import Config
|
|
20
27
|
from ...core.logger import get_logger
|
|
28
|
+
from ...core.shared.config_loader import ConfigLoader
|
|
21
29
|
from ...core.unified_paths import get_package_root, get_scripts_dir
|
|
22
30
|
from ...services.port_manager import PortManager
|
|
23
31
|
from ...utils.dependency_manager import ensure_socketio_dependencies
|
|
32
|
+
from ..shared import BaseCommand, CommandResult
|
|
24
33
|
from ..utils import get_user_input, list_agent_versions_at_startup
|
|
25
34
|
|
|
26
35
|
|
|
@@ -175,12 +184,363 @@ You are resuming session {session_id[:8]}... which was:
|
|
|
175
184
|
return base_context + session_info
|
|
176
185
|
|
|
177
186
|
|
|
187
|
+
class RunCommand(BaseCommand):
|
|
188
|
+
"""Run command using shared utilities."""
|
|
189
|
+
|
|
190
|
+
def __init__(self):
|
|
191
|
+
super().__init__("run")
|
|
192
|
+
|
|
193
|
+
def validate_args(self, args) -> Optional[str]:
|
|
194
|
+
"""Validate command arguments."""
|
|
195
|
+
# Run command has minimal validation requirements
|
|
196
|
+
# Most validation is handled by the ClaudeRunner and related services
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
def run(self, args) -> CommandResult:
|
|
200
|
+
"""Execute the run command."""
|
|
201
|
+
try:
|
|
202
|
+
# Execute the main run logic
|
|
203
|
+
success = self._execute_run_session(args)
|
|
204
|
+
|
|
205
|
+
if success:
|
|
206
|
+
return CommandResult.success_result("Claude session completed successfully")
|
|
207
|
+
else:
|
|
208
|
+
return CommandResult.error_result("Claude session failed", exit_code=1)
|
|
209
|
+
|
|
210
|
+
except KeyboardInterrupt:
|
|
211
|
+
self.logger.info("Session interrupted by user")
|
|
212
|
+
return CommandResult.error_result("Session cancelled by user", exit_code=130)
|
|
213
|
+
except Exception as e:
|
|
214
|
+
self.logger.error(f"Error running Claude session: {e}", exc_info=True)
|
|
215
|
+
return CommandResult.error_result(f"Error running Claude session: {e}")
|
|
216
|
+
|
|
217
|
+
def _execute_run_session(self, args) -> bool:
|
|
218
|
+
"""Execute the main run session logic."""
|
|
219
|
+
# For now, delegate to the legacy function to maintain compatibility
|
|
220
|
+
# TODO: Gradually migrate logic into the individual helper methods
|
|
221
|
+
try:
|
|
222
|
+
run_session_legacy(args)
|
|
223
|
+
return True
|
|
224
|
+
except Exception as e:
|
|
225
|
+
self.logger.error(f"Run session failed: {e}")
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
def _execute_run_session_new(self, args) -> bool:
|
|
229
|
+
"""Execute the main run session logic using new pattern."""
|
|
230
|
+
try:
|
|
231
|
+
# Log session start
|
|
232
|
+
if args.logging != LogLevel.OFF.value:
|
|
233
|
+
self.logger.info("Starting Claude MPM session")
|
|
234
|
+
|
|
235
|
+
# Perform startup checks
|
|
236
|
+
self._check_configuration_health()
|
|
237
|
+
self._check_claude_json_memory(args)
|
|
238
|
+
|
|
239
|
+
# Handle session management
|
|
240
|
+
session_manager, resume_session_id, resume_context = self._setup_session_management(args)
|
|
241
|
+
|
|
242
|
+
# Handle dependency checking
|
|
243
|
+
self._handle_dependency_checking(args)
|
|
244
|
+
|
|
245
|
+
# Setup monitoring if requested
|
|
246
|
+
monitor_mode, websocket_port = self._setup_monitoring(args)
|
|
247
|
+
|
|
248
|
+
# Configure Claude runner
|
|
249
|
+
runner = self._setup_claude_runner(args, monitor_mode, websocket_port)
|
|
250
|
+
|
|
251
|
+
# Create context and run session
|
|
252
|
+
context = self._create_session_context(args, session_manager, resume_session_id, resume_context)
|
|
253
|
+
|
|
254
|
+
# Execute the session
|
|
255
|
+
return self._execute_session(args, runner, context)
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
self.logger.error(f"Run session failed: {e}")
|
|
259
|
+
return False
|
|
260
|
+
|
|
261
|
+
def _check_configuration_health(self):
|
|
262
|
+
"""Check configuration health at startup."""
|
|
263
|
+
from .run_config_checker import RunConfigChecker
|
|
264
|
+
checker = RunConfigChecker(self.logger)
|
|
265
|
+
checker.check_configuration_health()
|
|
266
|
+
|
|
267
|
+
def _check_claude_json_memory(self, args):
|
|
268
|
+
"""Check .claude.json file size and warn about memory issues."""
|
|
269
|
+
from .run_config_checker import RunConfigChecker
|
|
270
|
+
checker = RunConfigChecker(self.logger)
|
|
271
|
+
checker.check_claude_json_memory(args)
|
|
272
|
+
|
|
273
|
+
def _setup_session_management(self, args):
|
|
274
|
+
"""Setup session management and handle resumption."""
|
|
275
|
+
try:
|
|
276
|
+
from ...core.session_manager import SessionManager
|
|
277
|
+
except ImportError:
|
|
278
|
+
from claude_mpm.core.session_manager import SessionManager
|
|
279
|
+
|
|
280
|
+
session_manager = SessionManager()
|
|
281
|
+
resume_session_id = None
|
|
282
|
+
resume_context = None
|
|
283
|
+
|
|
284
|
+
if hasattr(args, "mpm_resume") and args.mpm_resume:
|
|
285
|
+
if args.mpm_resume == "last":
|
|
286
|
+
# Resume the last interactive session
|
|
287
|
+
resume_session_id = session_manager.get_last_interactive_session()
|
|
288
|
+
if resume_session_id:
|
|
289
|
+
session_data = session_manager.get_session_by_id(resume_session_id)
|
|
290
|
+
if session_data:
|
|
291
|
+
resume_context = session_data.get("context", "default")
|
|
292
|
+
self.logger.info(f"Resuming session {resume_session_id} (context: {resume_context})")
|
|
293
|
+
print(f"🔄 Resuming session {resume_session_id[:8]}... (created: {session_data.get('created_at', 'unknown')})")
|
|
294
|
+
else:
|
|
295
|
+
self.logger.warning(f"Session {resume_session_id} not found")
|
|
296
|
+
else:
|
|
297
|
+
self.logger.info("No recent interactive sessions found")
|
|
298
|
+
print("ℹ️ No recent interactive sessions found to resume")
|
|
299
|
+
else:
|
|
300
|
+
# Resume specific session by ID
|
|
301
|
+
resume_session_id = args.mpm_resume
|
|
302
|
+
session_data = session_manager.get_session_by_id(resume_session_id)
|
|
303
|
+
if session_data:
|
|
304
|
+
resume_context = session_data.get("context", "default")
|
|
305
|
+
self.logger.info(f"Resuming session {resume_session_id} (context: {resume_context})")
|
|
306
|
+
print(f"🔄 Resuming session {resume_session_id[:8]}... (context: {resume_context})")
|
|
307
|
+
else:
|
|
308
|
+
self.logger.error(f"Session {resume_session_id} not found")
|
|
309
|
+
print(f"❌ Session {resume_session_id} not found")
|
|
310
|
+
print("💡 Use 'claude-mpm sessions' to list available sessions")
|
|
311
|
+
raise RuntimeError(f"Session {resume_session_id} not found")
|
|
312
|
+
|
|
313
|
+
return session_manager, resume_session_id, resume_context
|
|
314
|
+
|
|
315
|
+
def _handle_dependency_checking(self, args):
|
|
316
|
+
"""Handle smart dependency checking."""
|
|
317
|
+
# Smart dependency checking - only when needed
|
|
318
|
+
if getattr(args, "check_dependencies", True): # Default to checking
|
|
319
|
+
try:
|
|
320
|
+
from ...utils.agent_dependency_loader import AgentDependencyLoader
|
|
321
|
+
from ...utils.dependency_cache import SmartDependencyChecker
|
|
322
|
+
from ...utils.environment_context import should_prompt_for_dependencies
|
|
323
|
+
|
|
324
|
+
# Initialize smart checker
|
|
325
|
+
smart_checker = SmartDependencyChecker()
|
|
326
|
+
loader = AgentDependencyLoader(auto_install=False)
|
|
327
|
+
|
|
328
|
+
# Check if agents have changed
|
|
329
|
+
has_changed, deployment_hash = loader.has_agents_changed()
|
|
330
|
+
|
|
331
|
+
# Determine if we should check dependencies
|
|
332
|
+
should_check, check_reason = smart_checker.should_check_dependencies(
|
|
333
|
+
force_check=getattr(args, "force_check_dependencies", False),
|
|
334
|
+
deployment_hash=deployment_hash,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
if should_check:
|
|
338
|
+
self.logger.info(f"Checking dependencies: {check_reason}")
|
|
339
|
+
|
|
340
|
+
# Check if we should prompt for dependencies
|
|
341
|
+
should_prompt = should_prompt_for_dependencies()
|
|
342
|
+
|
|
343
|
+
if should_prompt:
|
|
344
|
+
# Check dependencies and prompt for installation if needed
|
|
345
|
+
missing_deps = loader.check_dependencies()
|
|
346
|
+
if missing_deps:
|
|
347
|
+
self.logger.info(f"Found {len(missing_deps)} missing dependencies")
|
|
348
|
+
|
|
349
|
+
# Prompt user for installation
|
|
350
|
+
print(f"\n📦 Found {len(missing_deps)} missing dependencies:")
|
|
351
|
+
for dep in missing_deps[:5]: # Show first 5
|
|
352
|
+
print(f" • {dep}")
|
|
353
|
+
if len(missing_deps) > 5:
|
|
354
|
+
print(f" ... and {len(missing_deps) - 5} more")
|
|
355
|
+
|
|
356
|
+
response = input("\nInstall missing dependencies? (y/N): ").strip().lower()
|
|
357
|
+
if response in ['y', 'yes']:
|
|
358
|
+
loader.auto_install = True
|
|
359
|
+
loader.install_dependencies(missing_deps)
|
|
360
|
+
print("✅ Dependencies installed successfully")
|
|
361
|
+
else:
|
|
362
|
+
print("⚠️ Continuing without installing dependencies")
|
|
363
|
+
else:
|
|
364
|
+
# Just check without prompting
|
|
365
|
+
missing_deps = loader.check_dependencies()
|
|
366
|
+
if missing_deps:
|
|
367
|
+
self.logger.warning(f"Found {len(missing_deps)} missing dependencies")
|
|
368
|
+
print(f"⚠️ Found {len(missing_deps)} missing dependencies. Use --force-check-dependencies to install.")
|
|
369
|
+
|
|
370
|
+
# Update cache
|
|
371
|
+
smart_checker.update_cache(deployment_hash)
|
|
372
|
+
else:
|
|
373
|
+
self.logger.debug(f"Skipping dependency check: {check_reason}")
|
|
374
|
+
|
|
375
|
+
except ImportError as e:
|
|
376
|
+
self.logger.warning(f"Dependency checking not available: {e}")
|
|
377
|
+
except Exception as e:
|
|
378
|
+
self.logger.warning(f"Dependency check failed: {e}")
|
|
379
|
+
|
|
380
|
+
def _setup_monitoring(self, args):
|
|
381
|
+
"""Setup monitoring configuration."""
|
|
382
|
+
monitor_mode = getattr(args, "monitor", False)
|
|
383
|
+
websocket_port = 8765 # Default port
|
|
384
|
+
|
|
385
|
+
if monitor_mode:
|
|
386
|
+
# Ensure Socket.IO dependencies are available
|
|
387
|
+
if not ensure_socketio_dependencies():
|
|
388
|
+
self.logger.warning("Socket.IO dependencies not available, disabling monitor mode")
|
|
389
|
+
monitor_mode = False
|
|
390
|
+
else:
|
|
391
|
+
# Get available port
|
|
392
|
+
port_manager = PortManager()
|
|
393
|
+
websocket_port = port_manager.get_available_port(8765)
|
|
394
|
+
|
|
395
|
+
# Start Socket.IO server if not running
|
|
396
|
+
if not self._is_socketio_server_running(websocket_port):
|
|
397
|
+
if not _start_socketio_server(websocket_port, self.logger):
|
|
398
|
+
self.logger.warning("Failed to start Socket.IO server, disabling monitor mode")
|
|
399
|
+
monitor_mode = False
|
|
400
|
+
else:
|
|
401
|
+
# Give server time to start
|
|
402
|
+
time.sleep(2)
|
|
403
|
+
|
|
404
|
+
if monitor_mode:
|
|
405
|
+
# Open browser to monitoring interface
|
|
406
|
+
monitor_url = f"http://localhost:{websocket_port}"
|
|
407
|
+
self.logger.info(f"Opening monitor interface: {monitor_url}")
|
|
408
|
+
try:
|
|
409
|
+
webbrowser.open(monitor_url)
|
|
410
|
+
args._browser_opened_by_cli = True
|
|
411
|
+
except Exception as e:
|
|
412
|
+
self.logger.warning(f"Could not open browser: {e}")
|
|
413
|
+
print(f"💡 Monitor interface available at: {monitor_url}")
|
|
414
|
+
|
|
415
|
+
return monitor_mode, websocket_port
|
|
416
|
+
|
|
417
|
+
def _setup_claude_runner(self, args, monitor_mode: bool, websocket_port: int):
|
|
418
|
+
"""Setup and configure the Claude runner."""
|
|
419
|
+
try:
|
|
420
|
+
from ...core.claude_runner import ClaudeRunner
|
|
421
|
+
except ImportError:
|
|
422
|
+
from claude_mpm.core.claude_runner import ClaudeRunner
|
|
423
|
+
|
|
424
|
+
# Configure tickets
|
|
425
|
+
enable_tickets = not getattr(args, "no_tickets", False)
|
|
426
|
+
|
|
427
|
+
# Configure launch method
|
|
428
|
+
launch_method = "exec" # Default
|
|
429
|
+
if getattr(args, "subprocess", False):
|
|
430
|
+
launch_method = "subprocess"
|
|
431
|
+
|
|
432
|
+
# Configure WebSocket
|
|
433
|
+
enable_websocket = monitor_mode
|
|
434
|
+
|
|
435
|
+
# Build Claude arguments
|
|
436
|
+
claude_args = []
|
|
437
|
+
if hasattr(args, "claude_args") and args.claude_args:
|
|
438
|
+
claude_args.extend(args.claude_args)
|
|
439
|
+
|
|
440
|
+
# Create runner
|
|
441
|
+
runner = ClaudeRunner(
|
|
442
|
+
enable_tickets=enable_tickets,
|
|
443
|
+
log_level=args.logging,
|
|
444
|
+
claude_args=claude_args,
|
|
445
|
+
launch_method=launch_method,
|
|
446
|
+
enable_websocket=enable_websocket,
|
|
447
|
+
websocket_port=websocket_port,
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# Set browser opening flag for monitor mode
|
|
451
|
+
if monitor_mode:
|
|
452
|
+
runner._should_open_monitor_browser = True
|
|
453
|
+
runner._browser_opened_by_cli = getattr(args, "_browser_opened_by_cli", False)
|
|
454
|
+
|
|
455
|
+
return runner
|
|
456
|
+
|
|
457
|
+
def _create_session_context(self, args, session_manager, resume_session_id, resume_context):
|
|
458
|
+
"""Create session context."""
|
|
459
|
+
try:
|
|
460
|
+
from ...core.claude_runner import create_simple_context
|
|
461
|
+
except ImportError:
|
|
462
|
+
from claude_mpm.core.claude_runner import create_simple_context
|
|
463
|
+
|
|
464
|
+
if resume_session_id and resume_context:
|
|
465
|
+
# For resumed sessions, create enhanced context with session information
|
|
466
|
+
context = create_session_context(resume_session_id, session_manager)
|
|
467
|
+
# Update session usage
|
|
468
|
+
session_manager.active_sessions[resume_session_id]["last_used"] = datetime.now().isoformat()
|
|
469
|
+
session_manager.active_sessions[resume_session_id]["use_count"] += 1
|
|
470
|
+
session_manager._save_sessions()
|
|
471
|
+
else:
|
|
472
|
+
# Create a new session for tracking
|
|
473
|
+
new_session_id = session_manager.create_session("default")
|
|
474
|
+
context = create_simple_context()
|
|
475
|
+
self.logger.info(f"Created new session {new_session_id}")
|
|
476
|
+
|
|
477
|
+
return context
|
|
478
|
+
|
|
479
|
+
def _execute_session(self, args, runner, context) -> bool:
|
|
480
|
+
"""Execute the Claude session."""
|
|
481
|
+
try:
|
|
482
|
+
# Run session based on mode
|
|
483
|
+
non_interactive = getattr(args, "non_interactive", False)
|
|
484
|
+
input_arg = getattr(args, "input", None)
|
|
485
|
+
|
|
486
|
+
if non_interactive or input_arg:
|
|
487
|
+
# Non-interactive mode
|
|
488
|
+
user_input = get_user_input(input_arg, self.logger)
|
|
489
|
+
success = runner.run_oneshot(user_input, context)
|
|
490
|
+
if not success:
|
|
491
|
+
self.logger.error("Session failed")
|
|
492
|
+
return False
|
|
493
|
+
else:
|
|
494
|
+
# Interactive mode
|
|
495
|
+
if getattr(args, "intercept_commands", False):
|
|
496
|
+
wrapper_path = get_scripts_dir() / "interactive_wrapper.py"
|
|
497
|
+
if wrapper_path.exists():
|
|
498
|
+
print("Starting interactive session with command interception...")
|
|
499
|
+
subprocess.run([sys.executable, str(wrapper_path)])
|
|
500
|
+
else:
|
|
501
|
+
self.logger.warning("Interactive wrapper not found, falling back to normal mode")
|
|
502
|
+
runner.run_interactive(context)
|
|
503
|
+
else:
|
|
504
|
+
runner.run_interactive(context)
|
|
505
|
+
|
|
506
|
+
return True
|
|
507
|
+
|
|
508
|
+
except Exception as e:
|
|
509
|
+
self.logger.error(f"Session execution failed: {e}")
|
|
510
|
+
return False
|
|
511
|
+
|
|
512
|
+
def _is_socketio_server_running(self, port: int) -> bool:
|
|
513
|
+
"""Check if Socket.IO server is running on the specified port."""
|
|
514
|
+
try:
|
|
515
|
+
import socket
|
|
516
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
517
|
+
s.settimeout(1)
|
|
518
|
+
result = s.connect_ex(('localhost', port))
|
|
519
|
+
return result == 0
|
|
520
|
+
except Exception:
|
|
521
|
+
return False
|
|
522
|
+
|
|
523
|
+
|
|
178
524
|
def run_session(args):
|
|
179
525
|
"""
|
|
180
|
-
|
|
526
|
+
Main entry point for run command.
|
|
527
|
+
|
|
528
|
+
This function maintains backward compatibility while using the new BaseCommand pattern.
|
|
529
|
+
"""
|
|
530
|
+
command = RunCommand()
|
|
531
|
+
result = command.execute(args)
|
|
181
532
|
|
|
182
|
-
|
|
183
|
-
|
|
533
|
+
# For run command, we don't typically need structured output
|
|
534
|
+
# but we should respect the exit code
|
|
535
|
+
return result.exit_code
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def run_session_legacy(args):
|
|
539
|
+
"""
|
|
540
|
+
Legacy run session implementation.
|
|
541
|
+
|
|
542
|
+
WHY: This contains the original run_session logic, preserved during migration
|
|
543
|
+
to BaseCommand pattern. Will be gradually refactored into the RunCommand class.
|
|
184
544
|
|
|
185
545
|
DESIGN DECISION: We use ClaudeRunner to handle the complexity of
|
|
186
546
|
subprocess management and hook integration, keeping this function focused
|
|
@@ -779,9 +1139,8 @@ def _check_claude_json_memory(args, logger):
|
|
|
779
1139
|
|
|
780
1140
|
# Get thresholds from configuration
|
|
781
1141
|
try:
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
config = Config()
|
|
1142
|
+
config_loader = ConfigLoader()
|
|
1143
|
+
config = config_loader.load_main_config()
|
|
785
1144
|
memory_config = config.get("memory_management", {})
|
|
786
1145
|
warning_threshold = (
|
|
787
1146
|
memory_config.get("claude_json_warning_threshold_kb", 500) * 1024
|
|
@@ -874,8 +1233,9 @@ def _check_configuration_health(logger):
|
|
|
874
1233
|
logger: Logger instance for output
|
|
875
1234
|
"""
|
|
876
1235
|
try:
|
|
877
|
-
# Load configuration
|
|
878
|
-
|
|
1236
|
+
# Load configuration using ConfigLoader
|
|
1237
|
+
config_loader = ConfigLoader()
|
|
1238
|
+
config = config_loader.load_main_config()
|
|
879
1239
|
|
|
880
1240
|
# Validate configuration
|
|
881
1241
|
is_valid, errors, warnings = config.validate_configuration()
|