claude-mpm 5.4.96__py3-none-any.whl → 5.6.3__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 (155) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/{CLAUDE_MPM_FOUNDERS_OUTPUT_STYLE.md → CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md} +14 -6
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +36 -7
  4. claude_mpm/agents/WORKFLOW.md +2 -0
  5. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  6. claude_mpm/cli/commands/autotodos.py +45 -5
  7. claude_mpm/cli/commands/commander.py +46 -0
  8. claude_mpm/cli/commands/hook_errors.py +60 -60
  9. claude_mpm/cli/commands/run.py +35 -3
  10. claude_mpm/cli/executor.py +32 -17
  11. claude_mpm/cli/parsers/base_parser.py +17 -0
  12. claude_mpm/cli/parsers/commander_parser.py +83 -0
  13. claude_mpm/cli/parsers/run_parser.py +10 -0
  14. claude_mpm/cli/startup.py +20 -2
  15. claude_mpm/cli/utils.py +7 -3
  16. claude_mpm/commander/__init__.py +72 -0
  17. claude_mpm/commander/adapters/__init__.py +31 -0
  18. claude_mpm/commander/adapters/base.py +191 -0
  19. claude_mpm/commander/adapters/claude_code.py +361 -0
  20. claude_mpm/commander/adapters/communication.py +366 -0
  21. claude_mpm/commander/api/__init__.py +16 -0
  22. claude_mpm/commander/api/app.py +105 -0
  23. claude_mpm/commander/api/errors.py +112 -0
  24. claude_mpm/commander/api/routes/__init__.py +8 -0
  25. claude_mpm/commander/api/routes/events.py +184 -0
  26. claude_mpm/commander/api/routes/inbox.py +171 -0
  27. claude_mpm/commander/api/routes/messages.py +148 -0
  28. claude_mpm/commander/api/routes/projects.py +271 -0
  29. claude_mpm/commander/api/routes/sessions.py +215 -0
  30. claude_mpm/commander/api/routes/work.py +260 -0
  31. claude_mpm/commander/api/schemas.py +182 -0
  32. claude_mpm/commander/chat/__init__.py +7 -0
  33. claude_mpm/commander/chat/cli.py +107 -0
  34. claude_mpm/commander/chat/commands.py +96 -0
  35. claude_mpm/commander/chat/repl.py +310 -0
  36. claude_mpm/commander/config.py +49 -0
  37. claude_mpm/commander/config_loader.py +115 -0
  38. claude_mpm/commander/daemon.py +398 -0
  39. claude_mpm/commander/events/__init__.py +26 -0
  40. claude_mpm/commander/events/manager.py +332 -0
  41. claude_mpm/commander/frameworks/__init__.py +12 -0
  42. claude_mpm/commander/frameworks/base.py +143 -0
  43. claude_mpm/commander/frameworks/claude_code.py +58 -0
  44. claude_mpm/commander/frameworks/mpm.py +62 -0
  45. claude_mpm/commander/inbox/__init__.py +16 -0
  46. claude_mpm/commander/inbox/dedup.py +128 -0
  47. claude_mpm/commander/inbox/inbox.py +224 -0
  48. claude_mpm/commander/inbox/models.py +70 -0
  49. claude_mpm/commander/instance_manager.py +337 -0
  50. claude_mpm/commander/llm/__init__.py +6 -0
  51. claude_mpm/commander/llm/openrouter_client.py +167 -0
  52. claude_mpm/commander/llm/summarizer.py +70 -0
  53. claude_mpm/commander/models/__init__.py +18 -0
  54. claude_mpm/commander/models/events.py +121 -0
  55. claude_mpm/commander/models/project.py +162 -0
  56. claude_mpm/commander/models/work.py +214 -0
  57. claude_mpm/commander/parsing/__init__.py +20 -0
  58. claude_mpm/commander/parsing/extractor.py +132 -0
  59. claude_mpm/commander/parsing/output_parser.py +270 -0
  60. claude_mpm/commander/parsing/patterns.py +100 -0
  61. claude_mpm/commander/persistence/__init__.py +11 -0
  62. claude_mpm/commander/persistence/event_store.py +274 -0
  63. claude_mpm/commander/persistence/state_store.py +309 -0
  64. claude_mpm/commander/persistence/work_store.py +164 -0
  65. claude_mpm/commander/polling/__init__.py +13 -0
  66. claude_mpm/commander/polling/event_detector.py +104 -0
  67. claude_mpm/commander/polling/output_buffer.py +49 -0
  68. claude_mpm/commander/polling/output_poller.py +153 -0
  69. claude_mpm/commander/project_session.py +268 -0
  70. claude_mpm/commander/proxy/__init__.py +12 -0
  71. claude_mpm/commander/proxy/formatter.py +89 -0
  72. claude_mpm/commander/proxy/output_handler.py +191 -0
  73. claude_mpm/commander/proxy/relay.py +155 -0
  74. claude_mpm/commander/registry.py +404 -0
  75. claude_mpm/commander/runtime/__init__.py +10 -0
  76. claude_mpm/commander/runtime/executor.py +191 -0
  77. claude_mpm/commander/runtime/monitor.py +316 -0
  78. claude_mpm/commander/session/__init__.py +6 -0
  79. claude_mpm/commander/session/context.py +81 -0
  80. claude_mpm/commander/session/manager.py +59 -0
  81. claude_mpm/commander/tmux_orchestrator.py +361 -0
  82. claude_mpm/commander/web/__init__.py +1 -0
  83. claude_mpm/commander/work/__init__.py +30 -0
  84. claude_mpm/commander/work/executor.py +189 -0
  85. claude_mpm/commander/work/queue.py +405 -0
  86. claude_mpm/commander/workflow/__init__.py +27 -0
  87. claude_mpm/commander/workflow/event_handler.py +219 -0
  88. claude_mpm/commander/workflow/notifier.py +146 -0
  89. claude_mpm/commands/mpm-config.md +8 -0
  90. claude_mpm/commands/mpm-doctor.md +8 -0
  91. claude_mpm/commands/mpm-help.md +8 -0
  92. claude_mpm/commands/mpm-init.md +8 -0
  93. claude_mpm/commands/mpm-monitor.md +8 -0
  94. claude_mpm/commands/mpm-organize.md +8 -0
  95. claude_mpm/commands/mpm-postmortem.md +8 -0
  96. claude_mpm/commands/mpm-session-resume.md +8 -0
  97. claude_mpm/commands/mpm-status.md +8 -0
  98. claude_mpm/commands/mpm-ticket-view.md +8 -0
  99. claude_mpm/commands/mpm-version.md +8 -0
  100. claude_mpm/commands/mpm.md +8 -0
  101. claude_mpm/config/agent_presets.py +8 -7
  102. claude_mpm/core/config.py +5 -0
  103. claude_mpm/core/logger.py +26 -9
  104. claude_mpm/core/logging_utils.py +35 -11
  105. claude_mpm/core/output_style_manager.py +15 -5
  106. claude_mpm/core/unified_config.py +10 -6
  107. claude_mpm/core/unified_paths.py +68 -80
  108. claude_mpm/experimental/cli_enhancements.py +2 -1
  109. claude_mpm/hooks/claude_hooks/event_handlers.py +39 -1
  110. claude_mpm/hooks/claude_hooks/hook_handler.py +81 -88
  111. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  112. claude_mpm/hooks/claude_hooks/installer.py +75 -8
  113. claude_mpm/hooks/claude_hooks/memory_integration.py +22 -11
  114. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +14 -77
  115. claude_mpm/scripts/claude-hook-handler.sh +39 -12
  116. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  117. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  118. claude_mpm/services/event_log.py +8 -0
  119. claude_mpm/services/pm_skills_deployer.py +84 -6
  120. claude_mpm/services/skills/git_skill_source_manager.py +51 -2
  121. claude_mpm/services/skills/skill_discovery_service.py +57 -3
  122. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  123. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  124. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  125. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  126. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  127. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  128. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  129. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  130. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  131. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  132. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  133. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  134. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/METADATA +18 -4
  135. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/RECORD +140 -68
  136. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  137. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  138. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  139. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  140. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  141. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  142. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  143. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  144. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  145. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  146. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  151. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/WHEEL +0 -0
  152. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/entry_points.txt +0 -0
  153. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/licenses/LICENSE +0 -0
  154. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  155. {claude_mpm-5.4.96.dist-info → claude_mpm-5.6.3.dist-info}/top_level.txt +0 -0
@@ -127,6 +127,14 @@ def execute_command(command: str, args) -> int:
127
127
  result = handle_verify(args)
128
128
  return result if result is not None else 0
129
129
 
130
+ # Handle commander command with lazy import
131
+ if command == "commander":
132
+ # Lazy import to avoid loading unless needed
133
+ from .commands.commander import handle_commander_command
134
+
135
+ result = handle_commander_command(args)
136
+ return result if result is not None else 0
137
+
130
138
  # Handle skill-source command with lazy import
131
139
  if command == "skill-source":
132
140
  # Lazy import to avoid loading unless needed
@@ -206,27 +214,33 @@ def execute_command(command: str, args) -> int:
206
214
  "status": show_status,
207
215
  }
208
216
 
209
- # Get handler and invoke
217
+ # Get handler and call it with argument list (same pattern as autotodos)
210
218
  handler = handlers.get(subcommand)
211
219
  if handler:
212
- # Build Click context programmatically
213
- import click
214
-
215
- ctx = click.Context(command=handler)
220
+ try:
221
+ # Build argument list for Click command based on subcommand
222
+ click_args = []
216
223
 
217
- # Prepare keyword arguments from args
218
- kwargs = {}
219
- if hasattr(args, "format"):
220
- kwargs["format"] = args.format
221
- if hasattr(args, "hook_type"):
222
- kwargs["hook_type"] = args.hook_type
223
- if hasattr(args, "yes"):
224
- kwargs["yes"] = args.yes
224
+ # list command: --format, --hook-type
225
+ if subcommand == "list":
226
+ if hasattr(args, "format") and args.format:
227
+ click_args.extend(["--format", args.format])
228
+ if hasattr(args, "hook_type") and args.hook_type:
229
+ click_args.extend(["--hook-type", args.hook_type])
230
+ # clear command: --hook-type, -y
231
+ elif subcommand == "clear":
232
+ if hasattr(args, "hook_type") and args.hook_type:
233
+ click_args.extend(["--hook-type", args.hook_type])
234
+ if hasattr(args, "yes") and args.yes:
235
+ click_args.append("-y")
236
+ # diagnose command: hook_type (positional argument)
237
+ elif subcommand == "diagnose":
238
+ if hasattr(args, "hook_type") and args.hook_type:
239
+ click_args.append(args.hook_type)
240
+ # status and summary commands: no options
225
241
 
226
- try:
227
- # Invoke handler with arguments
228
- with ctx:
229
- handler.invoke(ctx, **kwargs)
242
+ # Call Click command with argument list and standalone_mode=False
243
+ handler(click_args, standalone_mode=False)
230
244
  return 0
231
245
  except SystemExit as e:
232
246
  return e.code if e.code is not None else 0
@@ -346,6 +360,7 @@ def execute_command(command: str, args) -> int:
346
360
  CLICommands.SKILLS.value: manage_skills,
347
361
  "debug": manage_debug, # Add debug command
348
362
  "mpm-init": None, # Will be handled separately with lazy import
363
+ "commander": None, # Will be handled separately with lazy import
349
364
  }
350
365
 
351
366
  # Execute command if found
@@ -297,6 +297,16 @@ def add_top_level_run_arguments(parser: argparse.ArgumentParser) -> None:
297
297
  action="store_true",
298
298
  help="Force refresh agents and skills from remote repos, bypassing ETag cache",
299
299
  )
300
+ run_group.add_argument(
301
+ "--chrome",
302
+ action="store_true",
303
+ help="Enable Claude in Chrome integration (passed to Claude Code)",
304
+ )
305
+ run_group.add_argument(
306
+ "--no-chrome",
307
+ action="store_true",
308
+ help="Disable Claude in Chrome integration (passed to Claude Code)",
309
+ )
300
310
 
301
311
  # Dependency checking options (for backward compatibility at top level)
302
312
  dep_group_top = parser.add_argument_group(
@@ -492,6 +502,13 @@ def create_parser(
492
502
  except ImportError:
493
503
  pass
494
504
 
505
+ try:
506
+ from .commander_parser import add_commander_subparser
507
+
508
+ add_commander_subparser(subparsers)
509
+ except ImportError:
510
+ pass
511
+
495
512
  # Add uninstall command parser
496
513
  try:
497
514
  from ..commands.uninstall import add_uninstall_parser
@@ -0,0 +1,83 @@
1
+ """
2
+ Commander parser module for claude-mpm CLI.
3
+
4
+ WHY: This module provides the commander subcommand for interactive instance management
5
+ and chat interface.
6
+
7
+ DESIGN DECISION: Uses subparser pattern consistent with other commands (run, agents, etc.)
8
+ to provide a clean interface for Commander mode.
9
+ """
10
+
11
+ import argparse
12
+ from pathlib import Path
13
+
14
+
15
+ def add_commander_subparser(subparsers: argparse._SubParsersAction) -> None:
16
+ """
17
+ Add commander subcommand parser.
18
+
19
+ WHY: Provides interactive mode for managing and chatting with multiple Claude instances.
20
+
21
+ Args:
22
+ subparsers: The subparsers object to add the commander parser to
23
+ """
24
+ commander_parser = subparsers.add_parser(
25
+ "commander",
26
+ help="Interactive Commander mode for managing multiple Claude instances",
27
+ description="""
28
+ Commander Mode - Interactive Instance Management
29
+
30
+ Commander provides an interactive REPL interface for:
31
+ - Starting and stopping Claude Code/MPM instances in tmux
32
+ - Connecting to instances and sending natural language commands
33
+ - Managing multiple concurrent projects
34
+ - Viewing instance status and output
35
+
36
+ Commands:
37
+ list, ls, instances List active instances
38
+ start <path> Start new instance at path
39
+ --framework <cc|mpm> Specify framework (default: cc)
40
+ --name <name> Specify instance name (default: dir name)
41
+ stop <name> Stop an instance
42
+ connect <name> Connect to an instance
43
+ disconnect Disconnect from current instance
44
+ status Show current session status
45
+ help Show help message
46
+ exit, quit, q Exit Commander
47
+
48
+ Natural Language:
49
+ When connected to an instance, any input that is not a built-in
50
+ command will be sent to the connected instance as a message.
51
+
52
+ Examples:
53
+ claude-mpm commander
54
+ > start ~/myproject --framework cc --name myapp
55
+ > connect myapp
56
+ > Fix the authentication bug in login.py
57
+ > disconnect
58
+ > exit
59
+ """,
60
+ formatter_class=argparse.RawDescriptionHelpFormatter,
61
+ )
62
+
63
+ # Optional: Port for internal services
64
+ commander_parser.add_argument(
65
+ "--port",
66
+ type=int,
67
+ default=8765,
68
+ help="Port for internal services (default: 8765)",
69
+ )
70
+
71
+ # Optional: State directory
72
+ commander_parser.add_argument(
73
+ "--state-dir",
74
+ type=Path,
75
+ help="Directory for state persistence (optional)",
76
+ )
77
+
78
+ # Debug mode
79
+ commander_parser.add_argument(
80
+ "--debug",
81
+ action="store_true",
82
+ help="Enable debug logging",
83
+ )
@@ -85,6 +85,16 @@ def add_run_arguments(parser: argparse.ArgumentParser) -> None:
85
85
  action="store_true",
86
86
  help="Pass --resume flag to Claude Code to resume the last conversation",
87
87
  )
88
+ run_group.add_argument(
89
+ "--chrome",
90
+ action="store_true",
91
+ help="Enable Claude in Chrome integration (passed to Claude Code)",
92
+ )
93
+ run_group.add_argument(
94
+ "--no-chrome",
95
+ action="store_true",
96
+ help="Disable Claude in Chrome integration (passed to Claude Code)",
97
+ )
88
98
 
89
99
  # Dependency checking options
90
100
  dep_group = parser.add_argument_group("dependency options")
claude_mpm/cli/startup.py CHANGED
@@ -161,7 +161,25 @@ def setup_early_environment(argv):
161
161
  # CRITICAL: Suppress ALL logging by default
162
162
  # This catches all loggers (claude_mpm.*, service.*, framework_loader, etc.)
163
163
  # This will be overridden by setup_mcp_server_logging() based on user preference
164
- logging.getLogger().setLevel(logging.CRITICAL + 1) # Root logger catches everything
164
+ root_logger = logging.getLogger()
165
+ root_logger.setLevel(logging.CRITICAL + 1) # Root logger catches everything
166
+ root_logger.handlers = [] # Remove any handlers
167
+
168
+ # Also suppress common module loggers explicitly to prevent handler leakage
169
+ for logger_name in [
170
+ "claude_mpm",
171
+ "path_resolver",
172
+ "file_loader",
173
+ "framework_loader",
174
+ "service",
175
+ "instruction_loader",
176
+ "agent_loader",
177
+ "startup",
178
+ ]:
179
+ module_logger = logging.getLogger(logger_name)
180
+ module_logger.setLevel(logging.CRITICAL + 1)
181
+ module_logger.handlers = []
182
+ module_logger.propagate = False
165
183
 
166
184
  # Process argv
167
185
  if argv is None:
@@ -316,7 +334,7 @@ def deploy_output_style_on_startup():
316
334
  Deploys all styles:
317
335
  - claude-mpm.md (professional mode)
318
336
  - claude-mpm-teacher.md (teaching mode)
319
- - claude-mpm-founders.md (founders mode)
337
+ - claude-mpm-research.md (research mode - for codebase analysis)
320
338
  """
321
339
  try:
322
340
  from ..core.output_style_manager import OutputStyleManager
claude_mpm/cli/utils.py CHANGED
@@ -107,7 +107,7 @@ def get_agent_versions_display() -> Optional[str]:
107
107
  base_version_tuple
108
108
  )
109
109
  output_lines.append(f"\n Base Agent Version: {base_version_str}")
110
- except Exception:
110
+ except Exception: # nosec B110 - intentional: version display is optional
111
111
  pass
112
112
 
113
113
  # Check for agents needing migration
@@ -173,8 +173,12 @@ def setup_logging(args) -> object:
173
173
  if not hasattr(args, "logging") or args.logging is None:
174
174
  args.logging = LogLevel.OFF.value
175
175
 
176
+ # Handle deprecated --verbose flag
177
+ if hasattr(args, "verbose") and args.verbose and args.logging == LogLevel.OFF.value:
178
+ args.logging = LogLevel.INFO.value
179
+
176
180
  # Handle deprecated --debug flag
177
- if hasattr(args, "debug") and args.debug and args.logging == LogLevel.INFO.value:
181
+ if hasattr(args, "debug") and args.debug:
178
182
  args.logging = LogLevel.DEBUG.value
179
183
 
180
184
  # Only setup logging if not OFF
@@ -204,7 +208,7 @@ def ensure_directories() -> None:
204
208
  from ..init import ensure_directories as init_ensure_directories
205
209
 
206
210
  init_ensure_directories()
207
- except Exception:
211
+ except Exception: # nosec B110
208
212
  # Continue even if initialization fails
209
213
  # The individual commands will handle missing directories as needed
210
214
  pass
@@ -0,0 +1,72 @@
1
+ """MPM Commander - Multi-Project Orchestration.
2
+
3
+ This module provides the core infrastructure for managing multiple projects
4
+ with isolated state, work queues, and tool sessions.
5
+
6
+ Key Components:
7
+ - ProjectRegistry: Thread-safe project management
8
+ - Project models: Data structures for state and sessions
9
+ - TmuxOrchestrator: Tmux session and pane management
10
+ - Config loading: .claude-mpm/ directory configuration
11
+ - CommanderDaemon: Main daemon process for orchestration
12
+ - ProjectSession: Per-project lifecycle management
13
+ - InstanceManager: Framework selection and instance lifecycle
14
+ - Frameworks: Claude Code, MPM framework abstractions
15
+
16
+ Example:
17
+ >>> from claude_mpm.commander import ProjectRegistry
18
+ >>> registry = ProjectRegistry()
19
+ >>> project = registry.register("/path/to/project")
20
+ >>> registry.update_state(project.id, ProjectState.WORKING)
21
+ """
22
+
23
+ from claude_mpm.commander.config import DaemonConfig
24
+ from claude_mpm.commander.config_loader import load_project_config
25
+ from claude_mpm.commander.daemon import CommanderDaemon
26
+ from claude_mpm.commander.frameworks import (
27
+ BaseFramework,
28
+ ClaudeCodeFramework,
29
+ InstanceInfo,
30
+ MPMFramework,
31
+ )
32
+ from claude_mpm.commander.instance_manager import (
33
+ FrameworkNotFoundError,
34
+ InstanceAlreadyExistsError,
35
+ InstanceManager,
36
+ InstanceNotFoundError,
37
+ )
38
+ from claude_mpm.commander.models import (
39
+ Project,
40
+ ProjectState,
41
+ ThreadMessage,
42
+ ToolSession,
43
+ )
44
+ from claude_mpm.commander.project_session import ProjectSession, SessionState
45
+ from claude_mpm.commander.registry import ProjectRegistry
46
+ from claude_mpm.commander.tmux_orchestrator import (
47
+ TmuxNotFoundError,
48
+ TmuxOrchestrator,
49
+ )
50
+
51
+ __all__ = [
52
+ "BaseFramework",
53
+ "ClaudeCodeFramework",
54
+ "CommanderDaemon",
55
+ "DaemonConfig",
56
+ "FrameworkNotFoundError",
57
+ "InstanceAlreadyExistsError",
58
+ "InstanceInfo",
59
+ "InstanceManager",
60
+ "InstanceNotFoundError",
61
+ "MPMFramework",
62
+ "Project",
63
+ "ProjectRegistry",
64
+ "ProjectSession",
65
+ "ProjectState",
66
+ "SessionState",
67
+ "ThreadMessage",
68
+ "TmuxNotFoundError",
69
+ "TmuxOrchestrator",
70
+ "ToolSession",
71
+ "load_project_config",
72
+ ]
@@ -0,0 +1,31 @@
1
+ """Runtime adapters for MPM Commander.
2
+
3
+ This package provides adapters for different AI coding tools, allowing
4
+ the TmuxOrchestrator to interface with various runtimes in a uniform way.
5
+
6
+ Two types of adapters:
7
+ - RuntimeAdapter: Synchronous parsing and state detection
8
+ - CommunicationAdapter: Async I/O and state management
9
+ """
10
+
11
+ from .base import Capability, ParsedResponse, RuntimeAdapter
12
+ from .claude_code import ClaudeCodeAdapter
13
+ from .communication import (
14
+ AdapterResponse,
15
+ AdapterState,
16
+ BaseCommunicationAdapter,
17
+ ClaudeCodeCommunicationAdapter,
18
+ )
19
+
20
+ __all__ = [
21
+ # Communication adapters (async I/O)
22
+ "AdapterResponse",
23
+ "AdapterState",
24
+ "BaseCommunicationAdapter",
25
+ # Runtime adapters (parsing)
26
+ "Capability",
27
+ "ClaudeCodeAdapter",
28
+ "ClaudeCodeCommunicationAdapter",
29
+ "ParsedResponse",
30
+ "RuntimeAdapter",
31
+ ]
@@ -0,0 +1,191 @@
1
+ """Base runtime adapter interface for MPM Commander.
2
+
3
+ This module defines the abstract interface for runtime adapters that bridge
4
+ between the TmuxOrchestrator and various AI coding tools (Claude Code, Cursor, etc.).
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass
9
+ from enum import Enum
10
+ from typing import List, Optional, Set
11
+
12
+
13
+ class Capability(Enum):
14
+ """Capabilities that a runtime adapter can provide."""
15
+
16
+ TOOL_USE = "tool_use"
17
+ FILE_EDIT = "file_edit"
18
+ FILE_CREATE = "file_create"
19
+ GIT_OPERATIONS = "git_operations"
20
+ SHELL_COMMANDS = "shell_commands"
21
+ WEB_SEARCH = "web_search"
22
+ COMPLEX_REASONING = "complex_reasoning"
23
+
24
+
25
+ @dataclass
26
+ class ParsedResponse:
27
+ """Parsed output from a runtime tool.
28
+
29
+ Attributes:
30
+ content: The extracted text content, with ANSI codes removed
31
+ is_complete: True if tool is waiting for input (idle state)
32
+ is_error: True if an error was detected in the output
33
+ error_message: The error message if is_error is True
34
+ is_question: True if tool is asking a question
35
+ question_text: The question text if is_question is True
36
+ options: List of options if presenting a choice
37
+
38
+ Example:
39
+ >>> response = ParsedResponse(
40
+ ... content="File created successfully",
41
+ ... is_complete=True,
42
+ ... is_error=False,
43
+ ... error_message=None,
44
+ ... is_question=False,
45
+ ... question_text=None,
46
+ ... options=None
47
+ ... )
48
+ """
49
+
50
+ content: str
51
+ is_complete: bool
52
+ is_error: bool
53
+ error_message: Optional[str] = None
54
+ is_question: bool = False
55
+ question_text: Optional[str] = None
56
+ options: Optional[List[str]] = None
57
+
58
+
59
+ class RuntimeAdapter(ABC):
60
+ """Abstract base class for runtime adapters.
61
+
62
+ A runtime adapter provides the interface between the TmuxOrchestrator
63
+ and a specific AI coding tool. It handles:
64
+ - Launching the tool with appropriate settings
65
+ - Formatting input messages
66
+ - Detecting tool states (idle, error, questioning)
67
+ - Parsing tool output into structured responses
68
+
69
+ Example:
70
+ >>> class MyAdapter(RuntimeAdapter):
71
+ ... @property
72
+ ... def name(self) -> str:
73
+ ... return "my-tool"
74
+ ...
75
+ ... def build_launch_command(self, project_path: str) -> str:
76
+ ... return f"cd {project_path} && my-tool --interactive"
77
+ """
78
+
79
+ @abstractmethod
80
+ def build_launch_command(
81
+ self, project_path: str, agent_prompt: Optional[str] = None
82
+ ) -> str:
83
+ """Generate shell command to start the tool.
84
+
85
+ Args:
86
+ project_path: Absolute path to the project directory
87
+ agent_prompt: Optional system prompt to configure the agent
88
+
89
+ Returns:
90
+ Shell command string ready to execute
91
+
92
+ Example:
93
+ >>> adapter.build_launch_command("/home/user/project", "You are a Python expert")
94
+ 'cd /home/user/project && claude --system-prompt "You are a Python expert"'
95
+ """
96
+
97
+ @abstractmethod
98
+ def format_input(self, message: str) -> str:
99
+ """Prepare message for tool's input format.
100
+
101
+ Args:
102
+ message: The user message to send
103
+
104
+ Returns:
105
+ Formatted message ready to send to the tool
106
+
107
+ Example:
108
+ >>> adapter.format_input("Fix the bug in main.py")
109
+ 'Fix the bug in main.py'
110
+ """
111
+
112
+ @abstractmethod
113
+ def detect_idle(self, output: str) -> bool:
114
+ """Recognize when tool is waiting for input.
115
+
116
+ Args:
117
+ output: Raw output from the tool (may contain ANSI codes)
118
+
119
+ Returns:
120
+ True if the tool is in an idle state awaiting input
121
+
122
+ Example:
123
+ >>> adapter.detect_idle("Done editing file.\\n> ")
124
+ True
125
+ >>> adapter.detect_idle("Processing request...")
126
+ False
127
+ """
128
+
129
+ @abstractmethod
130
+ def detect_error(self, output: str) -> Optional[str]:
131
+ """Recognize error states, return error message if found.
132
+
133
+ Args:
134
+ output: Raw output from the tool
135
+
136
+ Returns:
137
+ Error message string if error detected, None otherwise
138
+
139
+ Example:
140
+ >>> adapter.detect_error("Error: File not found: config.py")
141
+ 'Error: File not found: config.py'
142
+ >>> adapter.detect_error("File edited successfully")
143
+ None
144
+ """
145
+
146
+ @abstractmethod
147
+ def parse_response(self, output: str) -> ParsedResponse:
148
+ """Extract meaningful content from output.
149
+
150
+ This method combines all detection logic (idle, error, questions)
151
+ into a single structured response.
152
+
153
+ Args:
154
+ output: Raw output from the tool
155
+
156
+ Returns:
157
+ ParsedResponse with all detected states and content
158
+
159
+ Example:
160
+ >>> response = adapter.parse_response("Error: Invalid input\\n> ")
161
+ >>> response.is_error
162
+ True
163
+ >>> response.is_complete
164
+ True
165
+ """
166
+
167
+ @property
168
+ @abstractmethod
169
+ def capabilities(self) -> Set[Capability]:
170
+ """What this tool can do.
171
+
172
+ Returns:
173
+ Set of Capability enums indicating supported features
174
+
175
+ Example:
176
+ >>> adapter.capabilities
177
+ {Capability.FILE_EDIT, Capability.TOOL_USE}
178
+ """
179
+
180
+ @property
181
+ @abstractmethod
182
+ def name(self) -> str:
183
+ """Runtime identifier.
184
+
185
+ Returns:
186
+ Unique name for this runtime adapter
187
+
188
+ Example:
189
+ >>> adapter.name
190
+ 'claude-code'
191
+ """