Tracks orchestrator state for Mission Control observability. Parses orchestrator stdout for key events and emits orchestrator_update WebSocket messages showing what decisions the orchestrator is making.
| 431 | |
| 432 | |
| 433 | class OrchestratorTracker: |
| 434 | """Tracks orchestrator state for Mission Control observability. |
| 435 | |
| 436 | Parses orchestrator stdout for key events and emits orchestrator_update |
| 437 | WebSocket messages showing what decisions the orchestrator is making. |
| 438 | """ |
| 439 | |
| 440 | def __init__(self): |
| 441 | self.state = 'idle' |
| 442 | self.coding_agents = 0 |
| 443 | self.testing_agents = 0 |
| 444 | self.max_concurrency = 3 # Default, will be updated from output |
| 445 | self.ready_count = 0 |
| 446 | self.blocked_count = 0 |
| 447 | self.recent_events: list[dict] = [] |
| 448 | self._lock = asyncio.Lock() |
| 449 | |
| 450 | async def process_line(self, line: str) -> dict | None: |
| 451 | """ |
| 452 | Process an output line and return an orchestrator_update message if relevant. |
| 453 | |
| 454 | Returns None if no update should be emitted. |
| 455 | """ |
| 456 | async with self._lock: |
| 457 | update = None |
| 458 | |
| 459 | # Check for initializer start |
| 460 | if ORCHESTRATOR_PATTERNS['init_start'].search(line): |
| 461 | self.state = 'initializing' |
| 462 | update = self._create_update( |
| 463 | 'init_start', |
| 464 | 'Initializing project features...' |
| 465 | ) |
| 466 | |
| 467 | # Check for initializer complete |
| 468 | elif ORCHESTRATOR_PATTERNS['init_complete'].search(line): |
| 469 | self.state = 'scheduling' |
| 470 | update = self._create_update( |
| 471 | 'init_complete', |
| 472 | 'Initialization complete, preparing to schedule features' |
| 473 | ) |
| 474 | |
| 475 | # Check for capacity status |
| 476 | elif match := ORCHESTRATOR_PATTERNS['capacity_check'].search(line): |
| 477 | self.ready_count = int(match.group(1)) |
| 478 | slots = int(match.group(2)) |
| 479 | self.state = 'scheduling' if self.ready_count > 0 else 'monitoring' |
| 480 | update = self._create_update( |
| 481 | 'capacity_check', |
| 482 | f'{self.ready_count} features ready, {slots} slots available' |
| 483 | ) |
| 484 | |
| 485 | # Check for at capacity |
| 486 | elif ORCHESTRATOR_PATTERNS['at_capacity'].search(line): |
| 487 | self.state = 'monitoring' |
| 488 | update = self._create_update( |
| 489 | 'at_capacity', |
| 490 | 'At maximum capacity, monitoring active agents' |