claude-mpm 3.7.8__py3-none-any.whl → 3.9.0__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 (100) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +0 -106
  3. claude_mpm/agents/INSTRUCTIONS.md +0 -96
  4. claude_mpm/agents/MEMORY.md +94 -0
  5. claude_mpm/agents/WORKFLOW.md +86 -0
  6. claude_mpm/agents/templates/code_analyzer.json +2 -2
  7. claude_mpm/agents/templates/data_engineer.json +1 -1
  8. claude_mpm/agents/templates/documentation.json +1 -1
  9. claude_mpm/agents/templates/engineer.json +1 -1
  10. claude_mpm/agents/templates/ops.json +1 -1
  11. claude_mpm/agents/templates/qa.json +1 -1
  12. claude_mpm/agents/templates/research.json +1 -1
  13. claude_mpm/agents/templates/security.json +1 -1
  14. claude_mpm/agents/templates/ticketing.json +3 -8
  15. claude_mpm/agents/templates/version_control.json +1 -1
  16. claude_mpm/agents/templates/web_qa.json +2 -2
  17. claude_mpm/agents/templates/web_ui.json +2 -2
  18. claude_mpm/cli/__init__.py +2 -2
  19. claude_mpm/cli/commands/__init__.py +2 -1
  20. claude_mpm/cli/commands/agents.py +8 -3
  21. claude_mpm/cli/commands/tickets.py +596 -19
  22. claude_mpm/cli/parser.py +217 -5
  23. claude_mpm/config/__init__.py +30 -39
  24. claude_mpm/config/socketio_config.py +8 -5
  25. claude_mpm/constants.py +13 -0
  26. claude_mpm/core/__init__.py +8 -18
  27. claude_mpm/core/cache.py +596 -0
  28. claude_mpm/core/claude_runner.py +166 -622
  29. claude_mpm/core/config.py +7 -3
  30. claude_mpm/core/constants.py +339 -0
  31. claude_mpm/core/container.py +548 -38
  32. claude_mpm/core/exceptions.py +392 -0
  33. claude_mpm/core/framework_loader.py +249 -93
  34. claude_mpm/core/interactive_session.py +479 -0
  35. claude_mpm/core/interfaces.py +424 -0
  36. claude_mpm/core/lazy.py +467 -0
  37. claude_mpm/core/logging_config.py +444 -0
  38. claude_mpm/core/oneshot_session.py +465 -0
  39. claude_mpm/core/optimized_agent_loader.py +485 -0
  40. claude_mpm/core/optimized_startup.py +490 -0
  41. claude_mpm/core/service_registry.py +52 -26
  42. claude_mpm/core/socketio_pool.py +162 -5
  43. claude_mpm/core/types.py +292 -0
  44. claude_mpm/core/typing_utils.py +477 -0
  45. claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
  46. claude_mpm/init.py +2 -1
  47. claude_mpm/services/__init__.py +78 -14
  48. claude_mpm/services/agent/__init__.py +24 -0
  49. claude_mpm/services/agent/deployment.py +2548 -0
  50. claude_mpm/services/agent/management.py +598 -0
  51. claude_mpm/services/agent/registry.py +813 -0
  52. claude_mpm/services/agents/deployment/agent_deployment.py +728 -308
  53. claude_mpm/services/agents/memory/agent_memory_manager.py +160 -4
  54. claude_mpm/services/async_session_logger.py +8 -3
  55. claude_mpm/services/communication/__init__.py +21 -0
  56. claude_mpm/services/communication/socketio.py +1933 -0
  57. claude_mpm/services/communication/websocket.py +479 -0
  58. claude_mpm/services/core/__init__.py +123 -0
  59. claude_mpm/services/core/base.py +247 -0
  60. claude_mpm/services/core/interfaces.py +951 -0
  61. claude_mpm/services/framework_claude_md_generator/__init__.py +10 -3
  62. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +14 -11
  63. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
  64. claude_mpm/services/framework_claude_md_generator.py +3 -2
  65. claude_mpm/services/health_monitor.py +4 -3
  66. claude_mpm/services/hook_service.py +64 -4
  67. claude_mpm/services/infrastructure/__init__.py +21 -0
  68. claude_mpm/services/infrastructure/logging.py +202 -0
  69. claude_mpm/services/infrastructure/monitoring.py +893 -0
  70. claude_mpm/services/memory/indexed_memory.py +648 -0
  71. claude_mpm/services/project/__init__.py +21 -0
  72. claude_mpm/services/project/analyzer.py +864 -0
  73. claude_mpm/services/project/registry.py +608 -0
  74. claude_mpm/services/project_analyzer.py +95 -2
  75. claude_mpm/services/recovery_manager.py +15 -9
  76. claude_mpm/services/response_tracker.py +3 -5
  77. claude_mpm/services/socketio/__init__.py +25 -0
  78. claude_mpm/services/socketio/handlers/__init__.py +25 -0
  79. claude_mpm/services/socketio/handlers/base.py +121 -0
  80. claude_mpm/services/socketio/handlers/connection.py +198 -0
  81. claude_mpm/services/socketio/handlers/file.py +213 -0
  82. claude_mpm/services/socketio/handlers/git.py +723 -0
  83. claude_mpm/services/socketio/handlers/memory.py +27 -0
  84. claude_mpm/services/socketio/handlers/project.py +25 -0
  85. claude_mpm/services/socketio/handlers/registry.py +145 -0
  86. claude_mpm/services/socketio_client_manager.py +12 -7
  87. claude_mpm/services/socketio_server.py +156 -30
  88. claude_mpm/services/ticket_manager.py +172 -9
  89. claude_mpm/services/ticket_manager_di.py +1 -1
  90. claude_mpm/services/version_control/semantic_versioning.py +80 -7
  91. claude_mpm/services/version_control/version_parser.py +528 -0
  92. claude_mpm/utils/error_handler.py +1 -1
  93. claude_mpm/validation/agent_validator.py +27 -14
  94. claude_mpm/validation/frontmatter_validator.py +231 -0
  95. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/METADATA +38 -128
  96. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/RECORD +100 -59
  97. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/WHEEL +0 -0
  98. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/entry_points.txt +0 -0
  99. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/licenses/LICENSE +0 -0
  100. {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/top_level.txt +0 -0
@@ -22,6 +22,25 @@ import asyncio
22
22
  from pathlib import Path
23
23
  from collections import deque
24
24
 
25
+ # Import constants for configuration
26
+ try:
27
+ from claude_mpm.core.constants import (
28
+ NetworkConfig,
29
+ TimeoutConfig,
30
+ RetryConfig
31
+ )
32
+ except ImportError:
33
+ # Fallback values if constants module not available
34
+ class NetworkConfig:
35
+ SOCKETIO_PORT_RANGE = (8080, 8099)
36
+ RECONNECTION_DELAY = 0.5
37
+ SOCKET_WAIT_TIMEOUT = 1.0
38
+ class TimeoutConfig:
39
+ QUICK_TIMEOUT = 2.0
40
+ class RetryConfig:
41
+ MAX_RETRIES = 3
42
+ INITIAL_RETRY_DELAY = 0.1
43
+
25
44
  # Debug mode is enabled by default for better visibility into hook processing
26
45
  # Set CLAUDE_MPM_HOOK_DEBUG=false to disable debug output
27
46
  DEBUG = os.environ.get('CLAUDE_MPM_HOOK_DEBUG', 'true').lower() != 'false'
@@ -412,7 +431,7 @@ class ClaudeHookHandler:
412
431
  ['git', 'branch', '--show-current'],
413
432
  capture_output=True,
414
433
  text=True,
415
- timeout=2 # Quick timeout to avoid hanging
434
+ timeout=TimeoutConfig.QUICK_TIMEOUT # Quick timeout to avoid hanging
416
435
  )
417
436
 
418
437
  # Restore original directory
@@ -464,8 +483,8 @@ class ClaudeHookHandler:
464
483
 
465
484
  # Need to create or reconnect client
466
485
  port = int(os.environ.get('CLAUDE_MPM_SOCKETIO_PORT', '8765'))
467
- max_retries = 3
468
- retry_delay = 0.1 # Start with 100ms
486
+ max_retries = RetryConfig.MAX_RETRIES
487
+ retry_delay = RetryConfig.INITIAL_RETRY_DELAY
469
488
 
470
489
  for attempt in range(max_retries):
471
490
  try:
@@ -481,7 +500,7 @@ class ClaudeHookHandler:
481
500
  self.sio_client = socketio.Client(
482
501
  reconnection=True, # Enable auto-reconnection
483
502
  reconnection_attempts=3,
484
- reconnection_delay=0.5,
503
+ reconnection_delay=NetworkConfig.RECONNECTION_DELAY,
485
504
  reconnection_delay_max=2,
486
505
  logger=False,
487
506
  engineio_logger=False
@@ -491,7 +510,7 @@ class ClaudeHookHandler:
491
510
  self.sio_client.connect(
492
511
  f'http://localhost:{port}',
493
512
  wait=True,
494
- wait_timeout=1.0 # Reasonable timeout
513
+ wait_timeout=NetworkConfig.SOCKET_WAIT_TIMEOUT
495
514
  )
496
515
 
497
516
  # Verify connection
@@ -540,36 +559,80 @@ class ClaudeHookHandler:
540
559
  - Always continues regardless of event status
541
560
  """
542
561
  try:
543
- # Read event
544
- event_data = sys.stdin.read()
545
- event = json.loads(event_data)
546
- hook_type = event.get('hook_event_name', 'unknown')
547
-
548
- # Fast path for common events
549
- if hook_type == 'UserPromptSubmit':
550
- self._handle_user_prompt_fast(event)
551
- elif hook_type == 'PreToolUse':
552
- self._handle_pre_tool_fast(event)
553
- elif hook_type == 'PostToolUse':
554
- self._handle_post_tool_fast(event)
555
- elif hook_type == 'Notification':
556
- self._handle_notification_fast(event)
557
- elif hook_type == 'Stop':
558
- self._handle_stop_fast(event)
559
- elif hook_type == 'SubagentStop':
560
- self._handle_subagent_stop_fast(event)
561
- elif hook_type == 'AssistantResponse':
562
- self._handle_assistant_response(event)
562
+ # Read and parse event
563
+ event = self._read_hook_event()
564
+ if not event:
565
+ self._continue_execution()
566
+ return
563
567
 
564
- # Socket.IO emit is non-blocking and will complete asynchronously
565
- # Removed sleep() to eliminate 100ms delay that was blocking Claude execution
568
+ # Route event to appropriate handler
569
+ self._route_event(event)
566
570
 
567
- # Always continue
568
- print(json.dumps({"action": "continue"}))
571
+ # Always continue execution
572
+ self._continue_execution()
569
573
 
570
574
  except:
571
575
  # Fail fast and silent
572
- print(json.dumps({"action": "continue"}))
576
+ self._continue_execution()
577
+
578
+ def _read_hook_event(self) -> dict:
579
+ """
580
+ Read and parse hook event from stdin.
581
+
582
+ WHY: Centralized event reading with error handling
583
+ ensures consistent parsing and validation.
584
+
585
+ Returns:
586
+ Parsed event dictionary or None if invalid
587
+ """
588
+ try:
589
+ event_data = sys.stdin.read()
590
+ return json.loads(event_data)
591
+ except (json.JSONDecodeError, ValueError):
592
+ if DEBUG:
593
+ print("Failed to parse hook event", file=sys.stderr)
594
+ return None
595
+
596
+ def _route_event(self, event: dict) -> None:
597
+ """
598
+ Route event to appropriate handler based on type.
599
+
600
+ WHY: Centralized routing reduces complexity and makes
601
+ it easier to add new event types.
602
+
603
+ Args:
604
+ event: Hook event dictionary
605
+ """
606
+ hook_type = event.get('hook_event_name', 'unknown')
607
+
608
+ # Map event types to handlers
609
+ event_handlers = {
610
+ 'UserPromptSubmit': self._handle_user_prompt_fast,
611
+ 'PreToolUse': self._handle_pre_tool_fast,
612
+ 'PostToolUse': self._handle_post_tool_fast,
613
+ 'Notification': self._handle_notification_fast,
614
+ 'Stop': self._handle_stop_fast,
615
+ 'SubagentStop': self._handle_subagent_stop_fast,
616
+ 'AssistantResponse': self._handle_assistant_response
617
+ }
618
+
619
+ # Call appropriate handler if exists
620
+ handler = event_handlers.get(hook_type)
621
+ if handler:
622
+ try:
623
+ handler(event)
624
+ except Exception as e:
625
+ if DEBUG:
626
+ print(f"Error handling {hook_type}: {e}", file=sys.stderr)
627
+
628
+ def _continue_execution(self) -> None:
629
+ """
630
+ Send continue action to Claude.
631
+
632
+ WHY: Centralized response ensures consistent format
633
+ and makes it easier to add response modifications.
634
+ """
635
+ print(json.dumps({"action": "continue"}))
573
636
 
574
637
  def _emit_socketio_event(self, namespace: str, event: str, data: dict):
575
638
  """Emit Socket.IO event with improved reliability and logging.
@@ -1066,6 +1129,78 @@ class ClaudeHookHandler:
1066
1129
  # Emit to /hook namespace
1067
1130
  self._emit_socketio_event('/hook', 'notification', notification_data)
1068
1131
 
1132
+ def _extract_stop_metadata(self, event: dict) -> dict:
1133
+ """
1134
+ Extract metadata from stop event.
1135
+
1136
+ WHY: Centralized metadata extraction ensures consistent
1137
+ data collection across stop event handling.
1138
+
1139
+ Args:
1140
+ event: Stop event dictionary
1141
+
1142
+ Returns:
1143
+ Metadata dictionary
1144
+ """
1145
+ working_dir = event.get('cwd', '')
1146
+ return {
1147
+ 'timestamp': datetime.now().isoformat(),
1148
+ 'working_directory': working_dir,
1149
+ 'git_branch': self._get_git_branch(working_dir) if working_dir else 'Unknown',
1150
+ 'event_type': 'stop',
1151
+ 'reason': event.get('reason', 'unknown'),
1152
+ 'stop_type': event.get('stop_type', 'normal')
1153
+ }
1154
+
1155
+ def _track_stop_response(self, event: dict, session_id: str, metadata: dict) -> None:
1156
+ """
1157
+ Track response for stop events.
1158
+
1159
+ WHY: Separated response tracking logic for better modularity
1160
+ and easier testing/maintenance.
1161
+
1162
+ Args:
1163
+ event: Stop event dictionary
1164
+ session_id: Session identifier
1165
+ metadata: Event metadata
1166
+ """
1167
+ if not (self.response_tracking_enabled and self.response_tracker):
1168
+ return
1169
+
1170
+ try:
1171
+ # Extract output from event
1172
+ output = event.get('output', '') or event.get('final_output', '') or event.get('response', '')
1173
+
1174
+ # Check if we have a pending prompt for this session
1175
+ prompt_data = self.pending_prompts.get(session_id)
1176
+
1177
+ if DEBUG:
1178
+ print(f" - output present: {bool(output)} (length: {len(str(output)) if output else 0})", file=sys.stderr)
1179
+ print(f" - prompt_data present: {bool(prompt_data)}", file=sys.stderr)
1180
+
1181
+ if output and prompt_data:
1182
+ # Add prompt timestamp to metadata
1183
+ metadata['prompt_timestamp'] = prompt_data.get('timestamp')
1184
+
1185
+ # Track the main Claude response
1186
+ file_path = self.response_tracker.track_response(
1187
+ agent_name='claude_main',
1188
+ request=prompt_data['prompt'],
1189
+ response=str(output),
1190
+ session_id=session_id,
1191
+ metadata=metadata
1192
+ )
1193
+
1194
+ if file_path and DEBUG:
1195
+ print(f" - Response tracked to: {file_path}", file=sys.stderr)
1196
+
1197
+ # Clean up pending prompt
1198
+ del self.pending_prompts[session_id]
1199
+
1200
+ except Exception as e:
1201
+ if DEBUG:
1202
+ print(f"Error tracking stop response: {e}", file=sys.stderr)
1203
+
1069
1204
  def _handle_stop_fast(self, event):
1070
1205
  """Handle stop events when Claude processing stops.
1071
1206
 
@@ -1075,83 +1210,62 @@ class ClaudeHookHandler:
1075
1210
  - Enables tracking of session completion patterns
1076
1211
  - Useful for understanding when and why Claude stops responding
1077
1212
  """
1078
- reason = event.get('reason', 'unknown')
1079
- stop_type = event.get('stop_type', 'normal')
1080
1213
  session_id = event.get('session_id', '')
1081
1214
 
1082
- # Get working directory and git branch
1083
- working_dir = event.get('cwd', '')
1084
- git_branch = self._get_git_branch(working_dir) if working_dir else 'Unknown'
1215
+ # Extract metadata for this stop event
1216
+ metadata = self._extract_stop_metadata(event)
1085
1217
 
1086
- # Track response for Stop events (main Claude responses, not delegations)
1218
+ # Debug logging
1087
1219
  if DEBUG:
1088
- print(f"[DEBUG] Stop event processing:", file=sys.stderr)
1089
- print(f" - response_tracking_enabled: {self.response_tracking_enabled}", file=sys.stderr)
1090
- print(f" - response_tracker exists: {self.response_tracker is not None}", file=sys.stderr)
1091
- print(f" - session_id: {session_id[:8] if session_id else 'None'}...", file=sys.stderr)
1092
- print(f" - reason: {reason}", file=sys.stderr)
1093
- print(f" - stop_type: {stop_type}", file=sys.stderr)
1220
+ self._log_stop_event_debug(event, session_id, metadata)
1094
1221
 
1095
- if self.response_tracking_enabled and self.response_tracker:
1096
- try:
1097
- # Extract output from event
1098
- output = event.get('output', '') or event.get('final_output', '') or event.get('response', '')
1099
-
1100
- # Check if we have a pending prompt for this session
1101
- prompt_data = self.pending_prompts.get(session_id)
1102
-
1103
- if DEBUG:
1104
- print(f" - output present: {bool(output)} (length: {len(str(output)) if output else 0})", file=sys.stderr)
1105
- print(f" - prompt_data present: {bool(prompt_data)}", file=sys.stderr)
1106
- if prompt_data:
1107
- print(f" - prompt preview: {str(prompt_data.get('prompt', ''))[:100]}...", file=sys.stderr)
1108
-
1109
- if output and prompt_data:
1110
- # Track the main Claude response
1111
- metadata = {
1112
- 'timestamp': datetime.now().isoformat(),
1113
- 'prompt_timestamp': prompt_data.get('timestamp'),
1114
- 'working_directory': working_dir,
1115
- 'git_branch': git_branch,
1116
- 'event_type': 'stop',
1117
- 'reason': reason,
1118
- 'stop_type': stop_type
1119
- }
1120
-
1121
- file_path = self.response_tracker.track_response(
1122
- agent_name='claude_main',
1123
- request=prompt_data['prompt'],
1124
- response=str(output),
1125
- session_id=session_id,
1126
- metadata=metadata
1127
- )
1128
-
1129
- if file_path and DEBUG:
1130
- print(f"✅ Tracked main Claude response on Stop event for session {session_id[:8]}...: {file_path.name}", file=sys.stderr)
1131
-
1132
- # Clean up the stored prompt
1133
- if session_id in self.pending_prompts:
1134
- del self.pending_prompts[session_id]
1135
-
1136
- elif DEBUG and not prompt_data:
1137
- print(f"No stored prompt for Stop event session {session_id[:8]}...", file=sys.stderr)
1138
- elif DEBUG and not output:
1139
- print(f"No output in Stop event for session {session_id[:8]}...", file=sys.stderr)
1140
-
1141
- except Exception as e:
1142
- if DEBUG:
1143
- print(f"❌ Failed to track response on Stop event: {e}", file=sys.stderr)
1222
+ # Track response if enabled
1223
+ self._track_stop_response(event, session_id, metadata)
1224
+
1225
+ # Emit stop event to Socket.IO
1226
+ self._emit_stop_event(event, session_id, metadata)
1227
+
1228
+ def _log_stop_event_debug(self, event: dict, session_id: str, metadata: dict) -> None:
1229
+ """
1230
+ Log debug information for stop events.
1231
+
1232
+ WHY: Separated debug logging for cleaner code and easier
1233
+ enable/disable of debug output.
1234
+
1235
+ Args:
1236
+ event: Stop event dictionary
1237
+ session_id: Session identifier
1238
+ metadata: Event metadata
1239
+ """
1240
+ print(f"[DEBUG] Stop event processing:", file=sys.stderr)
1241
+ print(f" - response_tracking_enabled: {self.response_tracking_enabled}", file=sys.stderr)
1242
+ print(f" - response_tracker exists: {self.response_tracker is not None}", file=sys.stderr)
1243
+ print(f" - session_id: {session_id[:8] if session_id else 'None'}...", file=sys.stderr)
1244
+ print(f" - reason: {metadata['reason']}", file=sys.stderr)
1245
+ print(f" - stop_type: {metadata['stop_type']}", file=sys.stderr)
1246
+
1247
+ def _emit_stop_event(self, event: dict, session_id: str, metadata: dict) -> None:
1248
+ """
1249
+ Emit stop event data to Socket.IO.
1144
1250
 
1251
+ WHY: Separated Socket.IO emission for better modularity
1252
+ and easier testing/mocking.
1253
+
1254
+ Args:
1255
+ event: Stop event dictionary
1256
+ session_id: Session identifier
1257
+ metadata: Event metadata
1258
+ """
1145
1259
  stop_data = {
1146
- 'reason': reason,
1147
- 'stop_type': stop_type,
1260
+ 'reason': metadata['reason'],
1261
+ 'stop_type': metadata['stop_type'],
1148
1262
  'session_id': session_id,
1149
- 'working_directory': working_dir,
1150
- 'git_branch': git_branch,
1151
- 'timestamp': datetime.now().isoformat(),
1152
- 'is_user_initiated': reason in ['user_stop', 'user_cancel', 'interrupt'],
1153
- 'is_error_stop': reason in ['error', 'timeout', 'failed'],
1154
- 'is_completion_stop': reason in ['completed', 'finished', 'done'],
1263
+ 'working_directory': metadata['working_directory'],
1264
+ 'git_branch': metadata['git_branch'],
1265
+ 'timestamp': metadata['timestamp'],
1266
+ 'is_user_initiated': metadata['reason'] in ['user_stop', 'user_cancel', 'interrupt'],
1267
+ 'is_error_stop': metadata['reason'] in ['error', 'timeout', 'failed'],
1268
+ 'is_completion_stop': metadata['reason'] in ['completed', 'finished', 'done'],
1155
1269
  'has_output': bool(event.get('final_output'))
1156
1270
  }
1157
1271
 
claude_mpm/init.py CHANGED
@@ -11,6 +11,7 @@ import json
11
11
  import yaml
12
12
 
13
13
  from claude_mpm.core.logger import get_logger
14
+ from claude_mpm.core.constants import NetworkConfig
14
15
 
15
16
 
16
17
  class ProjectInitializer:
@@ -249,7 +250,7 @@ class ProjectInitializer:
249
250
  "version": "1.0",
250
251
  "hooks": {
251
252
  "enabled": True,
252
- "port_range": [8080, 8099]
253
+ "port_range": list(NetworkConfig.SOCKETIO_PORT_RANGE)
253
254
  },
254
255
  "logging": {
255
256
  "level": "INFO",
@@ -1,4 +1,15 @@
1
- """Services for Claude MPM."""
1
+ """Services for Claude MPM.
2
+
3
+ This module provides backward compatibility for the reorganized service layer.
4
+ Part of TSK-0046: Service Layer Architecture Reorganization
5
+
6
+ New structure:
7
+ - core/: Core interfaces and base classes
8
+ - agent/: Agent-related services
9
+ - communication/: SocketIO and WebSocket services
10
+ - project/: Project management services
11
+ - infrastructure/: Logging and monitoring services
12
+ """
2
13
 
3
14
  # Use lazy imports to prevent circular dependency issues
4
15
  def __getattr__(name):
@@ -7,8 +18,13 @@ def __getattr__(name):
7
18
  from .ticket_manager import TicketManager
8
19
  return TicketManager
9
20
  elif name == "AgentDeploymentService":
10
- from .agents.deployment import AgentDeploymentService
11
- return AgentDeploymentService
21
+ # Try new location first, fall back to old
22
+ try:
23
+ from .agent.deployment import AgentDeploymentService
24
+ return AgentDeploymentService
25
+ except ImportError:
26
+ from .agents.deployment import AgentDeploymentService
27
+ return AgentDeploymentService
12
28
  elif name == "AgentMemoryManager":
13
29
  from .agents.memory import AgentMemoryManager
14
30
  return AgentMemoryManager
@@ -17,8 +33,13 @@ def __getattr__(name):
17
33
  return get_memory_manager
18
34
  # Add backward compatibility for other agent services
19
35
  elif name == "AgentRegistry":
20
- from .agents.registry import AgentRegistry
21
- return AgentRegistry
36
+ # Try new location first, fall back to old
37
+ try:
38
+ from .agent.registry import AgentRegistry
39
+ return AgentRegistry
40
+ except ImportError:
41
+ from .agents.registry import AgentRegistry
42
+ return AgentRegistry
22
43
  elif name == "AgentLifecycleManager":
23
44
  from .agents.deployment import AgentLifecycleManager
24
45
  return AgentLifecycleManager
@@ -53,23 +74,36 @@ def __getattr__(name):
53
74
  from .hook_service import HookService
54
75
  return HookService
55
76
  elif name == "ProjectAnalyzer":
56
- from .project_analyzer import ProjectAnalyzer
57
- return ProjectAnalyzer
58
- elif name == "AdvancedHealthMonitor":
77
+ # Try new location first, fall back to old
78
+ try:
79
+ from .project.analyzer import ProjectAnalyzer
80
+ return ProjectAnalyzer
81
+ except ImportError:
82
+ from .project_analyzer import ProjectAnalyzer
83
+ return ProjectAnalyzer
84
+ elif name == "AdvancedHealthMonitor" or name == "HealthMonitor":
59
85
  try:
60
- from .health_monitor import AdvancedHealthMonitor
61
- return AdvancedHealthMonitor
86
+ from .infrastructure.monitoring import HealthMonitor
87
+ return HealthMonitor
62
88
  except ImportError:
63
- raise AttributeError(f"Health monitoring not available: {name}")
89
+ try:
90
+ from .health_monitor import AdvancedHealthMonitor
91
+ return AdvancedHealthMonitor
92
+ except ImportError:
93
+ raise AttributeError(f"Health monitoring not available: {name}")
64
94
  elif name == "RecoveryManager":
65
95
  try:
66
96
  from .recovery_manager import RecoveryManager
67
97
  return RecoveryManager
68
98
  except ImportError:
69
99
  raise AttributeError(f"Recovery management not available: {name}")
70
- elif name == "StandaloneSocketIOServer":
71
- from .standalone_socketio_server import StandaloneSocketIOServer
72
- return StandaloneSocketIOServer
100
+ elif name == "StandaloneSocketIOServer" or name == "SocketIOServer":
101
+ try:
102
+ from .communication.socketio import SocketIOServer
103
+ return SocketIOServer
104
+ except ImportError:
105
+ from .standalone_socketio_server import StandaloneSocketIOServer
106
+ return StandaloneSocketIOServer
73
107
  # Backward compatibility for memory services
74
108
  elif name == "MemoryBuilder":
75
109
  from .memory.builder import MemoryBuilder
@@ -86,6 +120,23 @@ def __getattr__(name):
86
120
  elif name == "SharedPromptCache":
87
121
  from .memory.cache.shared_prompt_cache import SharedPromptCache
88
122
  return SharedPromptCache
123
+ # New service organization imports
124
+ elif name == "AgentManagementService":
125
+ from .agent.management import AgentManagementService
126
+ return AgentManagementService
127
+ elif name == "ProjectRegistry":
128
+ from .project.registry import ProjectRegistry
129
+ return ProjectRegistry
130
+ elif name == "LoggingService":
131
+ from .infrastructure.logging import LoggingService
132
+ return LoggingService
133
+ elif name == "SocketIOClientManager":
134
+ from .communication.websocket import SocketIOClientManager
135
+ return SocketIOClientManager
136
+ # Core interfaces and base classes
137
+ elif name.startswith('I') or name in ['BaseService', 'SyncBaseService', 'SingletonService']:
138
+ from . import core
139
+ return getattr(core, name)
89
140
  raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
90
141
 
91
142
  __all__ = [
@@ -96,12 +147,15 @@ __all__ = [
96
147
  "HookService",
97
148
  "ProjectAnalyzer",
98
149
  "AdvancedHealthMonitor",
150
+ "HealthMonitor", # New alias
99
151
  "RecoveryManager",
100
152
  "StandaloneSocketIOServer",
153
+ "SocketIOServer", # New alias
101
154
  # Additional agent services for backward compatibility
102
155
  "AgentRegistry",
103
156
  "AgentLifecycleManager",
104
157
  "AgentManager",
158
+ "AgentManagementService", # New service
105
159
  "AgentCapabilitiesGenerator",
106
160
  "AgentModificationTracker",
107
161
  "AgentPersistenceService",
@@ -110,10 +164,20 @@ __all__ = [
110
164
  "BaseAgentManager",
111
165
  "DeployedAgentDiscovery",
112
166
  "FrameworkAgentLoader",
167
+ # Project services
168
+ "ProjectRegistry", # New service
169
+ # Infrastructure services
170
+ "LoggingService", # New service
171
+ # Communication services
172
+ "SocketIOClientManager", # New service
113
173
  # Memory services (backward compatibility)
114
174
  "MemoryBuilder",
115
175
  "MemoryRouter",
116
176
  "MemoryOptimizer",
117
177
  "SimpleCacheService",
118
178
  "SharedPromptCache",
179
+ # Core exports
180
+ "BaseService",
181
+ "SyncBaseService",
182
+ "SingletonService",
119
183
  ]
@@ -0,0 +1,24 @@
1
+ """
2
+ Agent Services Module
3
+ ====================
4
+
5
+ This module contains all agent-related services including deployment,
6
+ management, and registry operations.
7
+
8
+ Part of TSK-0046: Service Layer Architecture Reorganization
9
+
10
+ Services:
11
+ - AgentDeploymentService: Handles agent deployment to Claude Code
12
+ - AgentManagementService: Manages agent lifecycle and operations
13
+ - AgentRegistry: Central registry for agent discovery and registration
14
+ """
15
+
16
+ from .deployment import AgentDeploymentService
17
+ from .management import AgentManagementService
18
+ from .registry import AgentRegistry
19
+
20
+ __all__ = [
21
+ 'AgentDeploymentService',
22
+ 'AgentManagementService',
23
+ 'AgentRegistry',
24
+ ]