claude-mpm 5.6.10__py3-none-any.whl → 5.6.33__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (117) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/commands/commander.py +174 -4
  3. claude_mpm/cli/parsers/commander_parser.py +43 -10
  4. claude_mpm/cli/startup.py +140 -20
  5. claude_mpm/cli/startup_display.py +2 -1
  6. claude_mpm/commander/__init__.py +6 -0
  7. claude_mpm/commander/adapters/__init__.py +32 -3
  8. claude_mpm/commander/adapters/auggie.py +260 -0
  9. claude_mpm/commander/adapters/base.py +98 -1
  10. claude_mpm/commander/adapters/claude_code.py +32 -1
  11. claude_mpm/commander/adapters/codex.py +237 -0
  12. claude_mpm/commander/adapters/example_usage.py +310 -0
  13. claude_mpm/commander/adapters/mpm.py +389 -0
  14. claude_mpm/commander/adapters/registry.py +204 -0
  15. claude_mpm/commander/api/app.py +32 -16
  16. claude_mpm/commander/api/routes/messages.py +11 -11
  17. claude_mpm/commander/api/routes/projects.py +20 -20
  18. claude_mpm/commander/api/routes/sessions.py +19 -21
  19. claude_mpm/commander/api/routes/work.py +86 -50
  20. claude_mpm/commander/api/schemas.py +4 -0
  21. claude_mpm/commander/chat/cli.py +42 -3
  22. claude_mpm/commander/config.py +5 -3
  23. claude_mpm/commander/core/__init__.py +10 -0
  24. claude_mpm/commander/core/block_manager.py +325 -0
  25. claude_mpm/commander/core/response_manager.py +323 -0
  26. claude_mpm/commander/daemon.py +215 -10
  27. claude_mpm/commander/env_loader.py +59 -0
  28. claude_mpm/commander/frameworks/base.py +4 -1
  29. claude_mpm/commander/instance_manager.py +124 -11
  30. claude_mpm/commander/memory/__init__.py +45 -0
  31. claude_mpm/commander/memory/compression.py +347 -0
  32. claude_mpm/commander/memory/embeddings.py +230 -0
  33. claude_mpm/commander/memory/entities.py +310 -0
  34. claude_mpm/commander/memory/example_usage.py +290 -0
  35. claude_mpm/commander/memory/integration.py +325 -0
  36. claude_mpm/commander/memory/search.py +381 -0
  37. claude_mpm/commander/memory/store.py +657 -0
  38. claude_mpm/commander/registry.py +10 -4
  39. claude_mpm/commander/runtime/monitor.py +32 -2
  40. claude_mpm/commander/work/executor.py +38 -20
  41. claude_mpm/commander/workflow/event_handler.py +25 -3
  42. claude_mpm/core/claude_runner.py +152 -0
  43. claude_mpm/core/config.py +3 -3
  44. claude_mpm/core/config_constants.py +74 -9
  45. claude_mpm/core/constants.py +56 -12
  46. claude_mpm/core/interactive_session.py +5 -4
  47. claude_mpm/core/logging_utils.py +4 -2
  48. claude_mpm/core/network_config.py +148 -0
  49. claude_mpm/core/oneshot_session.py +7 -6
  50. claude_mpm/core/output_style_manager.py +37 -7
  51. claude_mpm/core/socketio_pool.py +13 -5
  52. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  53. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  54. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  55. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  56. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  57. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +1 -1
  58. claude_mpm/hooks/claude_hooks/event_handlers.py +284 -89
  59. claude_mpm/hooks/claude_hooks/hook_handler.py +81 -32
  60. claude_mpm/hooks/claude_hooks/installer.py +90 -28
  61. claude_mpm/hooks/claude_hooks/memory_integration.py +1 -1
  62. claude_mpm/hooks/claude_hooks/response_tracking.py +1 -1
  63. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  64. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  65. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  66. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  67. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  68. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  69. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  70. claude_mpm/hooks/claude_hooks/services/connection_manager.py +2 -2
  71. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +2 -2
  72. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  73. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  74. claude_mpm/hooks/claude_hooks/services/state_manager.py +2 -2
  75. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +2 -2
  76. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  77. claude_mpm/hooks/templates/pre_tool_use_template.py +6 -6
  78. claude_mpm/scripts/claude-hook-handler.sh +3 -3
  79. claude_mpm/services/command_deployment_service.py +44 -26
  80. claude_mpm/services/hook_installer_service.py +77 -8
  81. claude_mpm/services/pm_skills_deployer.py +3 -2
  82. claude_mpm/skills/__init__.py +2 -1
  83. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  84. claude_mpm/skills/registry.py +295 -90
  85. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/METADATA +5 -3
  86. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/RECORD +91 -94
  87. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-312.pyc +0 -0
  88. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  89. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-312.pyc +0 -0
  90. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-314.pyc +0 -0
  91. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-312.pyc +0 -0
  92. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-314.pyc +0 -0
  93. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-312.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-314.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-314.pyc +0 -0
  97. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-312.pyc +0 -0
  98. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-314.pyc +0 -0
  99. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-312.pyc +0 -0
  100. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-314.pyc +0 -0
  101. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-312.pyc +0 -0
  102. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-314.pyc +0 -0
  103. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-312.pyc +0 -0
  104. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-314.pyc +0 -0
  105. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-312.pyc +0 -0
  106. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-314.pyc +0 -0
  107. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-312.pyc +0 -0
  108. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-314.pyc +0 -0
  109. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-312.pyc +0 -0
  110. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-314.pyc +0 -0
  111. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-312.pyc +0 -0
  112. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-314.pyc +0 -0
  113. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/WHEEL +0 -0
  114. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/entry_points.txt +0 -0
  115. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE +0 -0
  116. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  117. {claude_mpm-5.6.10.dist-info → claude_mpm-5.6.33.dist-info}/top_level.txt +0 -0
@@ -4,25 +4,39 @@ This module implements REST endpoints for managing work items
4
4
  in project work queues.
5
5
  """
6
6
 
7
- from typing import List, Optional
7
+ from typing import Dict, List, Optional
8
8
 
9
- from fastapi import APIRouter, HTTPException, Query
9
+ from fastapi import APIRouter, HTTPException, Query, Request
10
10
 
11
11
  from ...models.work import WorkPriority, WorkState
12
12
  from ...work import WorkQueue
13
- from ..errors import ProjectNotFoundError
14
13
  from ..schemas import CreateWorkRequest, WorkItemResponse
15
14
 
16
15
  router = APIRouter()
17
16
 
18
17
 
19
- def _get_registry():
20
- """Get registry instance from app global."""
21
- from ..app import registry
22
-
23
- if registry is None:
18
+ def _get_registry(request: Request):
19
+ """Get registry instance from app.state."""
20
+ if not hasattr(request.app.state, "registry") or request.app.state.registry is None:
24
21
  raise RuntimeError("Registry not initialized")
25
- return registry
22
+ return request.app.state.registry
23
+
24
+
25
+ def _get_work_queues(request: Request) -> Dict:
26
+ """Get work queues dict from app.state (shared with daemon)."""
27
+ if (
28
+ not hasattr(request.app.state, "work_queues")
29
+ or request.app.state.work_queues is None
30
+ ):
31
+ raise RuntimeError("Work queues not initialized")
32
+ return request.app.state.work_queues
33
+
34
+
35
+ def _get_daemon(request: Request):
36
+ """Get daemon instance from app.state."""
37
+ if not hasattr(request.app.state, "daemon_instance"):
38
+ return None
39
+ return request.app.state.daemon_instance
26
40
 
27
41
 
28
42
  def _work_item_to_response(work_item) -> WorkItemResponse:
@@ -51,10 +65,13 @@ def _work_item_to_response(work_item) -> WorkItemResponse:
51
65
 
52
66
 
53
67
  @router.post("/projects/{project_id}/work", response_model=WorkItemResponse)
54
- async def add_work(project_id: str, work: CreateWorkRequest) -> WorkItemResponse:
68
+ async def add_work(
69
+ request: Request, project_id: str, work: CreateWorkRequest
70
+ ) -> WorkItemResponse:
55
71
  """Add work item to project queue.
56
72
 
57
73
  Args:
74
+ request: FastAPI request (for accessing app.state)
58
75
  project_id: Project identifier
59
76
  work: Work item creation request
60
77
 
@@ -80,22 +97,29 @@ async def add_work(project_id: str, work: CreateWorkRequest) -> WorkItemResponse
80
97
  ...
81
98
  }
82
99
  """
83
- registry = _get_registry()
100
+ registry = _get_registry(request)
101
+ work_queues = _get_work_queues(request)
102
+ daemon = _get_daemon(request)
84
103
 
85
104
  # Get project
86
- try:
87
- project = registry.get(project_id)
88
- except ProjectNotFoundError as e:
89
- raise HTTPException(status_code=404, detail=str(e)) from e
105
+ project = registry.get(project_id)
106
+ if project is None:
107
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
90
108
 
91
- # Get or create work queue for project
92
- # Note: In full implementation, this would be managed by ProjectSession
93
- # For now, we'll need to integrate with project's work queue
94
- # Access or create work queue
95
- if not hasattr(project, "_work_queue"):
96
- project._work_queue = WorkQueue(project_id)
109
+ # Get or create work queue (shared with daemon)
110
+ import logging
97
111
 
98
- queue = project._work_queue
112
+ logger = logging.getLogger(__name__)
113
+ logger.info(
114
+ f"work_queues dict id: {id(work_queues)}, keys: {list(work_queues.keys())}"
115
+ )
116
+
117
+ if project_id not in work_queues:
118
+ logger.info(f"Creating new work queue for {project_id}")
119
+ work_queues[project_id] = WorkQueue(project_id)
120
+ logger.info(f"After creation, work_queues keys: {list(work_queues.keys())}")
121
+
122
+ queue = work_queues[project_id]
99
123
 
100
124
  # Convert priority int to enum
101
125
  priority = WorkPriority(work.priority)
@@ -105,16 +129,25 @@ async def add_work(project_id: str, work: CreateWorkRequest) -> WorkItemResponse
105
129
  content=work.content, priority=priority, depends_on=work.depends_on
106
130
  )
107
131
 
132
+ # Ensure daemon has a session for this project (creates if needed)
133
+ if daemon and not daemon.sessions.get(project_id):
134
+ # Session creation will be handled by daemon's main loop
135
+ # when it detects work in the queue
136
+ pass
137
+
108
138
  return _work_item_to_response(work_item)
109
139
 
110
140
 
111
141
  @router.get("/projects/{project_id}/work", response_model=List[WorkItemResponse])
112
142
  async def list_work(
113
- project_id: str, state: Optional[str] = Query(None, description="Filter by state")
143
+ request: Request,
144
+ project_id: str,
145
+ state: Optional[str] = Query(None, description="Filter by state"),
114
146
  ) -> List[WorkItemResponse]:
115
147
  """List work items for project.
116
148
 
117
149
  Args:
150
+ request: FastAPI request (for accessing app.state)
118
151
  project_id: Project identifier
119
152
  state: Optional state filter (pending, queued, in_progress, etc.)
120
153
 
@@ -136,19 +169,20 @@ async def list_work(
136
169
  {"id": "work-1", "state": "queued", ...}
137
170
  ]
138
171
  """
139
- registry = _get_registry()
172
+ registry = _get_registry(request)
173
+ work_queues = _get_work_queues(request)
140
174
 
141
175
  # Get project
142
- try:
143
- project = registry.get(project_id)
144
- except ProjectNotFoundError as e:
145
- raise HTTPException(status_code=404, detail=str(e)) from e
176
+ project = registry.get(project_id)
177
+ if project is None:
178
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
146
179
 
147
- # Get work queue
148
- if not hasattr(project, "_work_queue"):
149
- project._work_queue = WorkQueue(project_id)
180
+ # Get work queue (shared with daemon)
181
+ if project_id not in work_queues:
182
+ # Return empty list if no work queue exists yet
183
+ return []
150
184
 
151
- queue = project._work_queue
185
+ queue = work_queues[project_id]
152
186
 
153
187
  # Parse state filter
154
188
  state_filter = None
@@ -169,10 +203,11 @@ async def list_work(
169
203
 
170
204
 
171
205
  @router.get("/projects/{project_id}/work/{work_id}", response_model=WorkItemResponse)
172
- async def get_work(project_id: str, work_id: str) -> WorkItemResponse:
206
+ async def get_work(request: Request, project_id: str, work_id: str) -> WorkItemResponse:
173
207
  """Get work item details.
174
208
 
175
209
  Args:
210
+ request: FastAPI request (for accessing app.state)
176
211
  project_id: Project identifier
177
212
  work_id: Work item identifier
178
213
 
@@ -191,19 +226,19 @@ async def get_work(project_id: str, work_id: str) -> WorkItemResponse:
191
226
  ...
192
227
  }
193
228
  """
194
- registry = _get_registry()
229
+ registry = _get_registry(request)
230
+ work_queues = _get_work_queues(request)
195
231
 
196
232
  # Get project
197
- try:
198
- project = registry.get(project_id)
199
- except ProjectNotFoundError as e:
200
- raise HTTPException(status_code=404, detail=str(e)) from e
233
+ project = registry.get(project_id)
234
+ if project is None:
235
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
201
236
 
202
- # Get work queue
203
- if not hasattr(project, "_work_queue"):
237
+ # Get work queue (shared with daemon)
238
+ if project_id not in work_queues:
204
239
  raise HTTPException(status_code=404, detail="Work queue not found")
205
240
 
206
- queue = project._work_queue
241
+ queue = work_queues[project_id]
207
242
 
208
243
  # Get work item
209
244
  work_item = queue.get(work_id)
@@ -214,10 +249,11 @@ async def get_work(project_id: str, work_id: str) -> WorkItemResponse:
214
249
 
215
250
 
216
251
  @router.post("/projects/{project_id}/work/{work_id}/cancel")
217
- async def cancel_work(project_id: str, work_id: str) -> dict:
252
+ async def cancel_work(request: Request, project_id: str, work_id: str) -> dict:
218
253
  """Cancel pending work item.
219
254
 
220
255
  Args:
256
+ request: FastAPI request (for accessing app.state)
221
257
  project_id: Project identifier
222
258
  work_id: Work item identifier
223
259
 
@@ -231,19 +267,19 @@ async def cancel_work(project_id: str, work_id: str) -> dict:
231
267
  POST /api/projects/proj-123/work/work-xyz/cancel
232
268
  Response: {"status": "cancelled", "id": "work-xyz"}
233
269
  """
234
- registry = _get_registry()
270
+ registry = _get_registry(request)
271
+ work_queues = _get_work_queues(request)
235
272
 
236
273
  # Get project
237
- try:
238
- project = registry.get(project_id)
239
- except ProjectNotFoundError as e:
240
- raise HTTPException(status_code=404, detail=str(e)) from e
274
+ project = registry.get(project_id)
275
+ if project is None:
276
+ raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
241
277
 
242
- # Get work queue
243
- if not hasattr(project, "_work_queue"):
278
+ # Get work queue (shared with daemon)
279
+ if project_id not in work_queues:
244
280
  raise HTTPException(status_code=404, detail="Work queue not found")
245
281
 
246
- queue = project._work_queue
282
+ queue = work_queues[project_id]
247
283
 
248
284
  # Cancel work item
249
285
  if not queue.cancel(work_id):
@@ -17,10 +17,14 @@ class RegisterProjectRequest(BaseModel):
17
17
 
18
18
  Attributes:
19
19
  path: Filesystem path to project directory
20
+ project_id: Optional project identifier (UUID generated if omitted)
20
21
  name: Optional display name (derived from path if omitted)
21
22
  """
22
23
 
23
24
  path: str = Field(..., description="Filesystem path to project")
25
+ project_id: Optional[str] = Field(
26
+ None, description="Project identifier (UUID generated if omitted)"
27
+ )
24
28
  name: Optional[str] = Field(
25
29
  None, description="Display name (derived from path if omitted)"
26
30
  )
@@ -2,9 +2,11 @@
2
2
 
3
3
  import asyncio
4
4
  import logging
5
+ from dataclasses import dataclass
5
6
  from pathlib import Path
6
7
  from typing import Optional
7
8
 
9
+ from claude_mpm.commander.env_loader import load_env
8
10
  from claude_mpm.commander.instance_manager import InstanceManager
9
11
  from claude_mpm.commander.llm.openrouter_client import (
10
12
  OpenRouterClient,
@@ -19,23 +21,53 @@ from claude_mpm.commander.tmux_orchestrator import TmuxOrchestrator
19
21
 
20
22
  from .repl import CommanderREPL
21
23
 
24
+ # Load environment variables at module import
25
+ load_env()
26
+
22
27
  logger = logging.getLogger(__name__)
23
28
 
24
29
 
30
+ @dataclass
31
+ class CommanderCLIConfig:
32
+ """Configuration for Commander CLI mode.
33
+
34
+ Attributes:
35
+ summarize_responses: Whether to use LLM to summarize instance responses
36
+ port: Port for internal services (reserved for future use)
37
+ state_dir: Directory for state persistence (optional)
38
+
39
+ Example:
40
+ >>> config = CommanderCLIConfig(summarize_responses=False)
41
+ """
42
+
43
+ summarize_responses: bool = True
44
+ port: int = 8765
45
+ state_dir: Optional[Path] = None
46
+
47
+
25
48
  async def run_commander(
26
49
  port: int = 8765,
27
50
  state_dir: Optional[Path] = None,
51
+ config: Optional[CommanderCLIConfig] = None,
28
52
  ) -> None:
29
53
  """Run Commander in interactive mode.
30
54
 
31
55
  Args:
32
56
  port: Port for internal services (unused currently).
33
57
  state_dir: Directory for state persistence (optional).
58
+ config: Commander CLI configuration (optional, uses defaults if None).
34
59
 
35
60
  Example:
36
61
  >>> asyncio.run(run_commander())
37
62
  # Starts interactive Commander REPL
63
+ >>> config = CommanderCLIConfig(summarize_responses=False)
64
+ >>> asyncio.run(run_commander(config=config))
65
+ # Starts Commander without response summarization
38
66
  """
67
+ # Use default config if not provided
68
+ if config is None:
69
+ config = CommanderCLIConfig(port=port, state_dir=state_dir)
70
+
39
71
  # Setup logging
40
72
  logging.basicConfig(
41
73
  level=logging.INFO,
@@ -57,8 +89,8 @@ async def run_commander(
57
89
  # Try to initialize LLM client (optional)
58
90
  llm_client: Optional[OpenRouterClient] = None
59
91
  try:
60
- config = OpenRouterConfig()
61
- llm_client = OpenRouterClient(config)
92
+ llm_config = OpenRouterConfig()
93
+ llm_client = OpenRouterClient(llm_config)
62
94
  logger.info("LLM client initialized")
63
95
  except ValueError as e:
64
96
  logger.warning(f"LLM client not available: {e}")
@@ -68,7 +100,14 @@ async def run_commander(
68
100
  output_relay: Optional[OutputRelay] = None
69
101
  if llm_client:
70
102
  try:
71
- summarizer = OutputSummarizer(llm_client)
103
+ # Only create summarizer if summarize_responses is enabled
104
+ summarizer = None
105
+ if config.summarize_responses:
106
+ summarizer = OutputSummarizer(llm_client)
107
+ logger.info("Response summarization enabled")
108
+ else:
109
+ logger.info("Response summarization disabled")
110
+
72
111
  handler = OutputHandler(orchestrator, summarizer)
73
112
  formatter = OutputFormatter()
74
113
  output_relay = OutputRelay(handler, formatter)
@@ -14,28 +14,30 @@ class DaemonConfig:
14
14
 
15
15
  Attributes:
16
16
  host: API server bind address
17
- port: API server port
17
+ port: API server port (default: 8766 from NetworkPorts.COMMANDER_DEFAULT)
18
18
  log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
19
19
  state_dir: Directory for state persistence
20
20
  max_projects: Maximum concurrent projects
21
21
  healthcheck_interval: Healthcheck interval in seconds
22
22
  save_interval: State persistence interval in seconds
23
23
  poll_interval: Event polling interval in seconds
24
+ summarize_responses: Whether to use LLM to summarize instance responses
24
25
 
25
26
  Example:
26
- >>> config = DaemonConfig(port=8765, log_level="DEBUG")
27
+ >>> config = DaemonConfig(port=8766, log_level="DEBUG")
27
28
  >>> config.state_dir
28
29
  PosixPath('/Users/user/.claude-mpm/commander')
29
30
  """
30
31
 
31
32
  host: str = "127.0.0.1"
32
- port: int = 8765
33
+ port: int = 8766 # Default commander port (from network_config.NetworkPorts.COMMANDER_DEFAULT)
33
34
  log_level: str = "INFO"
34
35
  state_dir: Path = Path.home() / ".claude-mpm" / "commander"
35
36
  max_projects: int = 10
36
37
  healthcheck_interval: int = 30
37
38
  save_interval: int = 30
38
39
  poll_interval: float = 2.0
40
+ summarize_responses: bool = True
39
41
 
40
42
  def __post_init__(self):
41
43
  """Ensure state_dir is a Path object and create if needed."""
@@ -0,0 +1,10 @@
1
+ """Core coordination components for MPM Commander.
2
+
3
+ This module provides core components that coordinate between different
4
+ subsystems like events, work execution, and session management.
5
+ """
6
+
7
+ from .block_manager import BlockManager
8
+ from .response_manager import ResponseManager, ResponseRoute
9
+
10
+ __all__ = ["BlockManager", "ResponseManager", "ResponseRoute"]