claude-mpm 5.6.1__py3-none-any.whl → 5.6.76__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 (131) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +8 -3
  3. claude_mpm/auth/__init__.py +35 -0
  4. claude_mpm/auth/callback_server.py +328 -0
  5. claude_mpm/auth/models.py +104 -0
  6. claude_mpm/auth/oauth_manager.py +266 -0
  7. claude_mpm/auth/providers/__init__.py +12 -0
  8. claude_mpm/auth/providers/base.py +165 -0
  9. claude_mpm/auth/providers/google.py +261 -0
  10. claude_mpm/auth/token_storage.py +252 -0
  11. claude_mpm/cli/commands/commander.py +174 -4
  12. claude_mpm/cli/commands/mcp.py +29 -17
  13. claude_mpm/cli/commands/mcp_command_router.py +39 -0
  14. claude_mpm/cli/commands/mcp_service_commands.py +304 -0
  15. claude_mpm/cli/commands/oauth.py +481 -0
  16. claude_mpm/cli/commands/skill_source.py +51 -2
  17. claude_mpm/cli/commands/skills.py +5 -3
  18. claude_mpm/cli/executor.py +9 -0
  19. claude_mpm/cli/helpers.py +1 -1
  20. claude_mpm/cli/parsers/base_parser.py +13 -0
  21. claude_mpm/cli/parsers/commander_parser.py +43 -10
  22. claude_mpm/cli/parsers/mcp_parser.py +79 -0
  23. claude_mpm/cli/parsers/oauth_parser.py +165 -0
  24. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  25. claude_mpm/cli/parsers/skills_parser.py +5 -0
  26. claude_mpm/cli/startup.py +300 -33
  27. claude_mpm/cli/startup_display.py +4 -2
  28. claude_mpm/cli/startup_migrations.py +236 -0
  29. claude_mpm/commander/__init__.py +6 -0
  30. claude_mpm/commander/adapters/__init__.py +32 -3
  31. claude_mpm/commander/adapters/auggie.py +260 -0
  32. claude_mpm/commander/adapters/base.py +98 -1
  33. claude_mpm/commander/adapters/claude_code.py +32 -1
  34. claude_mpm/commander/adapters/codex.py +237 -0
  35. claude_mpm/commander/adapters/example_usage.py +310 -0
  36. claude_mpm/commander/adapters/mpm.py +389 -0
  37. claude_mpm/commander/adapters/registry.py +204 -0
  38. claude_mpm/commander/api/app.py +32 -16
  39. claude_mpm/commander/api/errors.py +21 -0
  40. claude_mpm/commander/api/routes/messages.py +11 -11
  41. claude_mpm/commander/api/routes/projects.py +20 -20
  42. claude_mpm/commander/api/routes/sessions.py +37 -26
  43. claude_mpm/commander/api/routes/work.py +86 -50
  44. claude_mpm/commander/api/schemas.py +4 -0
  45. claude_mpm/commander/chat/cli.py +47 -5
  46. claude_mpm/commander/chat/commands.py +44 -16
  47. claude_mpm/commander/chat/repl.py +1729 -82
  48. claude_mpm/commander/config.py +5 -3
  49. claude_mpm/commander/core/__init__.py +10 -0
  50. claude_mpm/commander/core/block_manager.py +325 -0
  51. claude_mpm/commander/core/response_manager.py +323 -0
  52. claude_mpm/commander/daemon.py +215 -10
  53. claude_mpm/commander/env_loader.py +59 -0
  54. claude_mpm/commander/events/manager.py +61 -1
  55. claude_mpm/commander/frameworks/base.py +91 -1
  56. claude_mpm/commander/frameworks/mpm.py +9 -14
  57. claude_mpm/commander/git/__init__.py +5 -0
  58. claude_mpm/commander/git/worktree_manager.py +212 -0
  59. claude_mpm/commander/instance_manager.py +546 -15
  60. claude_mpm/commander/memory/__init__.py +45 -0
  61. claude_mpm/commander/memory/compression.py +347 -0
  62. claude_mpm/commander/memory/embeddings.py +230 -0
  63. claude_mpm/commander/memory/entities.py +310 -0
  64. claude_mpm/commander/memory/example_usage.py +290 -0
  65. claude_mpm/commander/memory/integration.py +325 -0
  66. claude_mpm/commander/memory/search.py +381 -0
  67. claude_mpm/commander/memory/store.py +657 -0
  68. claude_mpm/commander/models/events.py +6 -0
  69. claude_mpm/commander/persistence/state_store.py +95 -1
  70. claude_mpm/commander/registry.py +10 -4
  71. claude_mpm/commander/runtime/monitor.py +32 -2
  72. claude_mpm/commander/tmux_orchestrator.py +3 -2
  73. claude_mpm/commander/work/executor.py +38 -20
  74. claude_mpm/commander/workflow/event_handler.py +25 -3
  75. claude_mpm/config/skill_sources.py +16 -0
  76. claude_mpm/constants.py +5 -0
  77. claude_mpm/core/claude_runner.py +152 -0
  78. claude_mpm/core/config.py +30 -22
  79. claude_mpm/core/config_constants.py +74 -9
  80. claude_mpm/core/constants.py +56 -12
  81. claude_mpm/core/hook_manager.py +2 -1
  82. claude_mpm/core/interactive_session.py +5 -4
  83. claude_mpm/core/logger.py +16 -2
  84. claude_mpm/core/logging_utils.py +40 -16
  85. claude_mpm/core/network_config.py +148 -0
  86. claude_mpm/core/oneshot_session.py +7 -6
  87. claude_mpm/core/output_style_manager.py +37 -7
  88. claude_mpm/core/socketio_pool.py +47 -15
  89. claude_mpm/core/unified_paths.py +68 -80
  90. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +30 -31
  91. claude_mpm/hooks/claude_hooks/event_handlers.py +285 -194
  92. claude_mpm/hooks/claude_hooks/hook_handler.py +115 -32
  93. claude_mpm/hooks/claude_hooks/installer.py +222 -54
  94. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  95. claude_mpm/hooks/claude_hooks/response_tracking.py +40 -59
  96. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  97. claude_mpm/hooks/claude_hooks/services/connection_manager.py +25 -30
  98. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +24 -28
  99. claude_mpm/hooks/claude_hooks/services/container.py +326 -0
  100. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  101. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  102. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +49 -75
  103. claude_mpm/hooks/session_resume_hook.py +22 -18
  104. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  105. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  106. claude_mpm/init.py +21 -14
  107. claude_mpm/mcp/__init__.py +9 -0
  108. claude_mpm/mcp/google_workspace_server.py +610 -0
  109. claude_mpm/scripts/claude-hook-handler.sh +10 -9
  110. claude_mpm/services/agents/agent_selection_service.py +2 -2
  111. claude_mpm/services/agents/single_tier_deployment_service.py +4 -4
  112. claude_mpm/services/command_deployment_service.py +44 -26
  113. claude_mpm/services/hook_installer_service.py +77 -8
  114. claude_mpm/services/mcp_config_manager.py +99 -19
  115. claude_mpm/services/mcp_service_registry.py +294 -0
  116. claude_mpm/services/monitor/server.py +6 -1
  117. claude_mpm/services/pm_skills_deployer.py +5 -3
  118. claude_mpm/services/skills/git_skill_source_manager.py +79 -8
  119. claude_mpm/services/skills/selective_skill_deployer.py +28 -0
  120. claude_mpm/services/skills/skill_discovery_service.py +17 -1
  121. claude_mpm/services/skills_deployer.py +31 -5
  122. claude_mpm/skills/__init__.py +2 -1
  123. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  124. claude_mpm/skills/registry.py +295 -90
  125. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/METADATA +28 -3
  126. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/RECORD +131 -93
  127. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/WHEEL +1 -1
  128. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/entry_points.txt +2 -0
  129. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE +0 -0
  130. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  131. {claude_mpm-5.6.1.dist-info → claude_mpm-5.6.76.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,326 @@
1
+ """Dependency Injection container for hook handler services.
2
+
3
+ This module provides a DI container that manages service instantiation,
4
+ lazy initialization, and service overriding for testing.
5
+
6
+ WHY DI Container:
7
+ - Centralized service management
8
+ - Lazy initialization reduces startup overhead
9
+ - Easy testing through service overriding
10
+ - Clear dependency graph
11
+ - Thread-safe singleton pattern
12
+ """
13
+
14
+ import threading
15
+ from typing import Any, Optional, TypeVar
16
+
17
+ # Import service protocols for type hints
18
+ from .protocols import (
19
+ IAutoPauseHandler,
20
+ IConnectionManager,
21
+ IDuplicateDetector,
22
+ IEventHandlers,
23
+ IMemoryHookManager,
24
+ IResponseTrackingManager,
25
+ IStateManager,
26
+ ISubagentProcessor,
27
+ )
28
+
29
+ T = TypeVar("T")
30
+
31
+
32
+ class HookServiceContainer:
33
+ """Dependency injection container for hook handler services.
34
+
35
+ Features:
36
+ - Lazy initialization of services
37
+ - Thread-safe singleton pattern
38
+ - Service overriding for testing
39
+ - Automatic dependency resolution
40
+
41
+ Usage:
42
+ # Normal usage (services created lazily)
43
+ container = HookServiceContainer()
44
+ state_manager = container.get_state_manager()
45
+
46
+ # Testing usage (override services)
47
+ container = HookServiceContainer()
48
+ container.override_state_manager(mock_state_manager)
49
+ state_manager = container.get_state_manager() # Returns mock
50
+
51
+ # Reset overrides
52
+ container.reset_overrides()
53
+ """
54
+
55
+ # Thread-safe singleton
56
+ _instance: Optional["HookServiceContainer"] = None
57
+ _lock = threading.Lock()
58
+
59
+ def __new__(cls) -> "HookServiceContainer":
60
+ """Thread-safe singleton pattern."""
61
+ if cls._instance is None:
62
+ with cls._lock:
63
+ # Double-check locking pattern
64
+ if cls._instance is None:
65
+ cls._instance = super().__new__(cls)
66
+ cls._instance._initialized = False
67
+ return cls._instance
68
+
69
+ def __init__(self) -> None:
70
+ """Initialize container if not already initialized."""
71
+ if getattr(self, "_initialized", False):
72
+ return
73
+
74
+ # Service instances (lazily initialized)
75
+ self._state_manager: Optional[IStateManager] = None
76
+ self._connection_manager: Optional[IConnectionManager] = None
77
+ self._duplicate_detector: Optional[IDuplicateDetector] = None
78
+ self._response_tracking_manager: Optional[IResponseTrackingManager] = None
79
+ self._memory_hook_manager: Optional[IMemoryHookManager] = None
80
+ self._subagent_processor: Optional[ISubagentProcessor] = None
81
+ self._auto_pause_handler: Optional[IAutoPauseHandler] = None
82
+ self._event_handlers: Optional[IEventHandlers] = None
83
+
84
+ # Override factories for testing
85
+ self._overrides: dict[str, Any] = {}
86
+
87
+ # Lock for lazy initialization
88
+ self._init_lock = threading.Lock()
89
+
90
+ self._initialized = True
91
+
92
+ # =========================================================================
93
+ # Lazy Service Getters
94
+ # =========================================================================
95
+
96
+ def get_state_manager(self) -> IStateManager:
97
+ """Get or create StateManagerService instance."""
98
+ if "state_manager" in self._overrides:
99
+ return self._overrides["state_manager"]
100
+
101
+ if self._state_manager is None:
102
+ with self._init_lock:
103
+ if self._state_manager is None:
104
+ from claude_mpm.hooks.claude_hooks.services.state_manager import (
105
+ StateManagerService,
106
+ )
107
+
108
+ self._state_manager = StateManagerService()
109
+ return self._state_manager
110
+
111
+ def get_connection_manager(self) -> IConnectionManager:
112
+ """Get or create ConnectionManagerService instance."""
113
+ if "connection_manager" in self._overrides:
114
+ return self._overrides["connection_manager"]
115
+
116
+ if self._connection_manager is None:
117
+ with self._init_lock:
118
+ if self._connection_manager is None:
119
+ from claude_mpm.hooks.claude_hooks.services.connection_manager_http import (
120
+ ConnectionManagerService,
121
+ )
122
+
123
+ self._connection_manager = ConnectionManagerService()
124
+ return self._connection_manager
125
+
126
+ def get_duplicate_detector(self) -> IDuplicateDetector:
127
+ """Get or create DuplicateEventDetector instance."""
128
+ if "duplicate_detector" in self._overrides:
129
+ return self._overrides["duplicate_detector"]
130
+
131
+ if self._duplicate_detector is None:
132
+ with self._init_lock:
133
+ if self._duplicate_detector is None:
134
+ from claude_mpm.hooks.claude_hooks.services.duplicate_detector import (
135
+ DuplicateEventDetector,
136
+ )
137
+
138
+ self._duplicate_detector = DuplicateEventDetector()
139
+ return self._duplicate_detector
140
+
141
+ def get_response_tracking_manager(self) -> IResponseTrackingManager:
142
+ """Get or create ResponseTrackingManager instance."""
143
+ if "response_tracking_manager" in self._overrides:
144
+ return self._overrides["response_tracking_manager"]
145
+
146
+ if self._response_tracking_manager is None:
147
+ with self._init_lock:
148
+ if self._response_tracking_manager is None:
149
+ from claude_mpm.hooks.claude_hooks.response_tracking import (
150
+ ResponseTrackingManager,
151
+ )
152
+
153
+ self._response_tracking_manager = ResponseTrackingManager()
154
+ return self._response_tracking_manager
155
+
156
+ def get_memory_hook_manager(self) -> IMemoryHookManager:
157
+ """Get or create MemoryHookManager instance."""
158
+ if "memory_hook_manager" in self._overrides:
159
+ return self._overrides["memory_hook_manager"]
160
+
161
+ if self._memory_hook_manager is None:
162
+ with self._init_lock:
163
+ if self._memory_hook_manager is None:
164
+ from claude_mpm.hooks.claude_hooks.memory_integration import (
165
+ MemoryHookManager,
166
+ )
167
+
168
+ self._memory_hook_manager = MemoryHookManager()
169
+ return self._memory_hook_manager
170
+
171
+ def get_auto_pause_handler(self) -> Optional[IAutoPauseHandler]:
172
+ """Get or create AutoPauseHandler instance.
173
+
174
+ Returns None if initialization fails (auto-pause is optional).
175
+ """
176
+ if "auto_pause_handler" in self._overrides:
177
+ return self._overrides["auto_pause_handler"]
178
+
179
+ if self._auto_pause_handler is None:
180
+ with self._init_lock:
181
+ if self._auto_pause_handler is None:
182
+ try:
183
+ from claude_mpm.hooks.claude_hooks.auto_pause_handler import (
184
+ AutoPauseHandler,
185
+ )
186
+
187
+ self._auto_pause_handler = AutoPauseHandler()
188
+ except Exception:
189
+ # Auto-pause is optional
190
+ self._auto_pause_handler = None
191
+ return self._auto_pause_handler
192
+
193
+ def get_subagent_processor(
194
+ self,
195
+ state_manager: Optional[IStateManager] = None,
196
+ response_tracking_manager: Optional[IResponseTrackingManager] = None,
197
+ connection_manager: Optional[IConnectionManager] = None,
198
+ ) -> ISubagentProcessor:
199
+ """Get or create SubagentResponseProcessor instance.
200
+
201
+ Args:
202
+ state_manager: Optional override for state manager
203
+ response_tracking_manager: Optional override for response tracking
204
+ connection_manager: Optional override for connection manager
205
+ """
206
+ if "subagent_processor" in self._overrides:
207
+ return self._overrides["subagent_processor"]
208
+
209
+ if self._subagent_processor is None:
210
+ with self._init_lock:
211
+ if self._subagent_processor is None:
212
+ from claude_mpm.hooks.claude_hooks.services.subagent_processor import (
213
+ SubagentResponseProcessor,
214
+ )
215
+
216
+ # Use provided dependencies or get from container
217
+ sm = state_manager or self.get_state_manager()
218
+ rtm = (
219
+ response_tracking_manager
220
+ or self.get_response_tracking_manager()
221
+ )
222
+ cm = connection_manager or self.get_connection_manager()
223
+
224
+ self._subagent_processor = SubagentResponseProcessor(sm, rtm, cm)
225
+ return self._subagent_processor
226
+
227
+ def get_event_handlers(self, hook_handler: Any = None) -> IEventHandlers:
228
+ """Get or create EventHandlers instance.
229
+
230
+ Args:
231
+ hook_handler: The ClaudeHookHandler instance for backward compatibility.
232
+ In the future, this will be replaced with proper DI.
233
+ """
234
+ if "event_handlers" in self._overrides:
235
+ return self._overrides["event_handlers"]
236
+
237
+ if self._event_handlers is None:
238
+ with self._init_lock:
239
+ if self._event_handlers is None:
240
+ from claude_mpm.hooks.claude_hooks.event_handlers import (
241
+ EventHandlers,
242
+ )
243
+
244
+ if hook_handler is None:
245
+ raise ValueError(
246
+ "hook_handler is required to create EventHandlers"
247
+ )
248
+ self._event_handlers = EventHandlers(hook_handler)
249
+ return self._event_handlers
250
+
251
+ # =========================================================================
252
+ # Service Override Methods (for testing)
253
+ # =========================================================================
254
+
255
+ def override_state_manager(self, service: IStateManager) -> None:
256
+ """Override state manager with a mock or custom implementation."""
257
+ self._overrides["state_manager"] = service
258
+
259
+ def override_connection_manager(self, service: IConnectionManager) -> None:
260
+ """Override connection manager with a mock or custom implementation."""
261
+ self._overrides["connection_manager"] = service
262
+
263
+ def override_duplicate_detector(self, service: IDuplicateDetector) -> None:
264
+ """Override duplicate detector with a mock or custom implementation."""
265
+ self._overrides["duplicate_detector"] = service
266
+
267
+ def override_response_tracking_manager(
268
+ self, service: IResponseTrackingManager
269
+ ) -> None:
270
+ """Override response tracking manager with a mock or custom implementation."""
271
+ self._overrides["response_tracking_manager"] = service
272
+
273
+ def override_memory_hook_manager(self, service: IMemoryHookManager) -> None:
274
+ """Override memory hook manager with a mock or custom implementation."""
275
+ self._overrides["memory_hook_manager"] = service
276
+
277
+ def override_subagent_processor(self, service: ISubagentProcessor) -> None:
278
+ """Override subagent processor with a mock or custom implementation."""
279
+ self._overrides["subagent_processor"] = service
280
+
281
+ def override_auto_pause_handler(self, service: Optional[IAutoPauseHandler]) -> None:
282
+ """Override auto-pause handler with a mock or custom implementation."""
283
+ self._overrides["auto_pause_handler"] = service
284
+
285
+ def override_event_handlers(self, service: IEventHandlers) -> None:
286
+ """Override event handlers with a mock or custom implementation."""
287
+ self._overrides["event_handlers"] = service
288
+
289
+ def reset_overrides(self) -> None:
290
+ """Reset all service overrides."""
291
+ self._overrides.clear()
292
+
293
+ def reset_all(self) -> None:
294
+ """Reset all services and overrides.
295
+
296
+ Useful for testing to ensure clean state between tests.
297
+ """
298
+ self._state_manager = None
299
+ self._connection_manager = None
300
+ self._duplicate_detector = None
301
+ self._response_tracking_manager = None
302
+ self._memory_hook_manager = None
303
+ self._subagent_processor = None
304
+ self._auto_pause_handler = None
305
+ self._event_handlers = None
306
+ self._overrides.clear()
307
+
308
+ @classmethod
309
+ def reset_singleton(cls) -> None:
310
+ """Reset the singleton instance.
311
+
312
+ USE WITH CAUTION: This is primarily for testing.
313
+ """
314
+ with cls._lock:
315
+ if cls._instance is not None:
316
+ cls._instance.reset_all()
317
+ cls._instance = None
318
+
319
+
320
+ def get_container() -> HookServiceContainer:
321
+ """Get the global HookServiceContainer singleton.
322
+
323
+ Returns:
324
+ The singleton HookServiceContainer instance.
325
+ """
326
+ return HookServiceContainer()
@@ -0,0 +1,328 @@
1
+ """Protocol definitions for hook handler services.
2
+
3
+ This module defines Protocol classes for all hook handler services,
4
+ enabling type-safe dependency injection and easy testing through
5
+ protocol-based duck typing.
6
+
7
+ WHY Protocol-based DI:
8
+ - Enables loose coupling between components
9
+ - Allows easy mocking in tests without monkey-patching
10
+ - Provides clear interface contracts
11
+ - Supports static type checking with mypy
12
+ """
13
+
14
+ from typing import Any, Callable, Optional, Protocol, runtime_checkable
15
+
16
+
17
+ @runtime_checkable
18
+ class IStateManager(Protocol):
19
+ """Protocol for state management service.
20
+
21
+ Manages:
22
+ - Agent delegation tracking
23
+ - Git branch caching
24
+ - Session state management
25
+ - Cleanup of old entries
26
+ """
27
+
28
+ active_delegations: dict
29
+ delegation_history: Any # deque
30
+ delegation_requests: dict
31
+ pending_prompts: dict
32
+ events_processed: int
33
+
34
+ def track_delegation(
35
+ self, session_id: str, agent_type: str, request_data: Optional[dict] = None
36
+ ) -> None:
37
+ """Track a new agent delegation with optional request data."""
38
+ ...
39
+
40
+ def get_delegation_agent_type(self, session_id: str) -> str:
41
+ """Get the agent type for a session's active delegation."""
42
+ ...
43
+
44
+ def cleanup_old_entries(self) -> None:
45
+ """Clean up old entries to prevent memory growth."""
46
+ ...
47
+
48
+ def get_git_branch(self, working_dir: Optional[str] = None) -> str:
49
+ """Get git branch for the given directory with caching."""
50
+ ...
51
+
52
+ def find_matching_request(self, session_id: str) -> Optional[dict]:
53
+ """Find matching request data for a session, with fuzzy matching fallback."""
54
+ ...
55
+
56
+ def remove_request(self, session_id: str) -> None:
57
+ """Remove request data for a session."""
58
+ ...
59
+
60
+ def increment_events_processed(self) -> bool:
61
+ """Increment events processed counter and return True if cleanup is needed."""
62
+ ...
63
+
64
+
65
+ @runtime_checkable
66
+ class IConnectionManager(Protocol):
67
+ """Protocol for connection management service.
68
+
69
+ Handles:
70
+ - HTTP-based event emission to dashboard
71
+ - Event queuing and batching
72
+ - Connection state management
73
+ """
74
+
75
+ def emit_event(self, namespace: str, event: str, data: dict) -> None:
76
+ """Emit an event through HTTP to the dashboard."""
77
+ ...
78
+
79
+ def cleanup(self) -> None:
80
+ """Clean up any resources."""
81
+ ...
82
+
83
+
84
+ @runtime_checkable
85
+ class IDuplicateDetector(Protocol):
86
+ """Protocol for duplicate event detection service.
87
+
88
+ Detects:
89
+ - Duplicate events within a time window
90
+ - Rapid-fire events that should be deduplicated
91
+ """
92
+
93
+ def is_duplicate(self, event: dict) -> bool:
94
+ """Check if an event is a duplicate of a recent event."""
95
+ ...
96
+
97
+ def generate_event_key(self, event: dict) -> str:
98
+ """Generate a unique key for an event for deduplication."""
99
+ ...
100
+
101
+
102
+ @runtime_checkable
103
+ class IResponseTrackingManager(Protocol):
104
+ """Protocol for response tracking management.
105
+
106
+ Manages:
107
+ - Response tracking enablement
108
+ - Comprehensive response logging
109
+ - Agent response correlation
110
+ """
111
+
112
+ response_tracking_enabled: bool
113
+ response_tracker: Optional[Any]
114
+ track_all_interactions: bool
115
+ auto_pause_handler: Optional[Any]
116
+
117
+ def track_agent_response(
118
+ self,
119
+ session_id: str,
120
+ agent_type: str,
121
+ event: dict,
122
+ delegation_requests: dict,
123
+ ) -> None:
124
+ """Track an agent response for logging."""
125
+ ...
126
+
127
+ def track_stop_response(
128
+ self,
129
+ event: dict,
130
+ session_id: str,
131
+ metadata: dict,
132
+ pending_prompts: dict,
133
+ ) -> None:
134
+ """Track a stop event response."""
135
+ ...
136
+
137
+ def track_assistant_response(
138
+ self,
139
+ event: dict,
140
+ pending_prompts: dict,
141
+ ) -> None:
142
+ """Track an assistant response."""
143
+ ...
144
+
145
+
146
+ @runtime_checkable
147
+ class IMemoryHookManager(Protocol):
148
+ """Protocol for memory hook management.
149
+
150
+ Manages:
151
+ - Pre/post delegation memory hooks
152
+ - Memory field processing
153
+ """
154
+
155
+ def trigger_pre_delegation_hook(
156
+ self, agent_type: str, tool_input: dict, session_id: str
157
+ ) -> None:
158
+ """Trigger memory hooks before delegation."""
159
+ ...
160
+
161
+ def trigger_post_delegation_hook(
162
+ self, agent_type: str, event: dict, session_id: str
163
+ ) -> None:
164
+ """Trigger memory hooks after delegation."""
165
+ ...
166
+
167
+
168
+ @runtime_checkable
169
+ class ISubagentProcessor(Protocol):
170
+ """Protocol for subagent response processing.
171
+
172
+ Handles:
173
+ - SubagentStop event processing
174
+ - Structured response extraction
175
+ - Response tracking and correlation
176
+ """
177
+
178
+ def process_subagent_stop(self, event: dict) -> None:
179
+ """Handle subagent stop events."""
180
+ ...
181
+
182
+
183
+ @runtime_checkable
184
+ class IAutoPauseHandler(Protocol):
185
+ """Protocol for auto-pause functionality.
186
+
187
+ Manages:
188
+ - Session pause tracking
189
+ - Usage threshold monitoring
190
+ - Session state capture
191
+ """
192
+
193
+ def is_pause_active(self) -> bool:
194
+ """Check if auto-pause is currently active."""
195
+ ...
196
+
197
+ def on_user_message(self, message: str) -> None:
198
+ """Record a user message for auto-pause tracking."""
199
+ ...
200
+
201
+ def on_tool_call(self, tool_name: str, tool_input: dict) -> None:
202
+ """Record a tool call for auto-pause tracking."""
203
+ ...
204
+
205
+ def on_assistant_response(self, response: str) -> None:
206
+ """Record an assistant response for auto-pause tracking."""
207
+ ...
208
+
209
+ def on_usage_update(self, usage: dict) -> Optional[str]:
210
+ """Update usage metrics and return threshold crossed if any."""
211
+ ...
212
+
213
+ def emit_threshold_warning(self, threshold: str) -> str:
214
+ """Emit a warning for a crossed threshold."""
215
+ ...
216
+
217
+ def on_session_end(self) -> Optional[Any]:
218
+ """Finalize the current auto-pause session."""
219
+ ...
220
+
221
+
222
+ @runtime_checkable
223
+ class IEventHandlers(Protocol):
224
+ """Protocol for event handler collection.
225
+
226
+ Provides handlers for:
227
+ - UserPromptSubmit
228
+ - PreToolUse
229
+ - PostToolUse
230
+ - Notification
231
+ - Stop
232
+ - SubagentStop
233
+ - SubagentStart
234
+ - SessionStart
235
+ - AssistantResponse
236
+ """
237
+
238
+ def handle_user_prompt_fast(self, event: dict) -> None:
239
+ """Handle user prompt with comprehensive data capture."""
240
+ ...
241
+
242
+ def handle_pre_tool_fast(self, event: dict) -> Optional[dict]:
243
+ """Handle pre-tool use with comprehensive data capture."""
244
+ ...
245
+
246
+ def handle_post_tool_fast(self, event: dict) -> None:
247
+ """Handle post-tool use with comprehensive data capture."""
248
+ ...
249
+
250
+ def handle_notification_fast(self, event: dict) -> None:
251
+ """Handle notification events from Claude."""
252
+ ...
253
+
254
+ def handle_stop_fast(self, event: dict) -> None:
255
+ """Handle stop events when Claude processing stops."""
256
+ ...
257
+
258
+ def handle_subagent_stop_fast(self, event: dict) -> None:
259
+ """Handle subagent stop events."""
260
+ ...
261
+
262
+ def handle_subagent_start_fast(self, event: dict) -> None:
263
+ """Handle SubagentStart events."""
264
+ ...
265
+
266
+ def handle_session_start_fast(self, event: dict) -> None:
267
+ """Handle session start events."""
268
+ ...
269
+
270
+ def handle_assistant_response(self, event: dict) -> None:
271
+ """Handle assistant response events."""
272
+ ...
273
+
274
+
275
+ # Type alias for log function
276
+ LogFunction = Callable[[str], None]
277
+
278
+
279
+ @runtime_checkable
280
+ class ILogManager(Protocol):
281
+ """Protocol for log manager service (optional dependency).
282
+
283
+ Used for logging agent prompts and responses.
284
+ """
285
+
286
+ async def log_prompt(
287
+ self, source: str, content: str, metadata: dict
288
+ ) -> Optional[Any]:
289
+ """Log a prompt to the log manager."""
290
+ ...
291
+
292
+
293
+ @runtime_checkable
294
+ class IDelegationDetector(Protocol):
295
+ """Protocol for delegation pattern detector (optional dependency).
296
+
297
+ Used for detecting delegation anti-patterns in responses.
298
+ """
299
+
300
+ def detect_user_delegation(self, text: str) -> list[dict]:
301
+ """Detect delegation patterns in text."""
302
+ ...
303
+
304
+
305
+ @runtime_checkable
306
+ class IEventLog(Protocol):
307
+ """Protocol for event log service (optional dependency).
308
+
309
+ Used for logging PM violations and other events.
310
+ """
311
+
312
+ def append_event(
313
+ self,
314
+ event_type: str,
315
+ payload: dict,
316
+ status: str = "pending",
317
+ ) -> None:
318
+ """Append an event to the log."""
319
+ ...
320
+
321
+
322
+ @runtime_checkable
323
+ class IConfig(Protocol):
324
+ """Protocol for configuration service (optional dependency)."""
325
+
326
+ def get(self, key: str, default: Any = None) -> Any:
327
+ """Get a configuration value."""
328
+ ...