()
| 336 | |
| 337 | |
| 338 | def run(): |
| 339 | global _channel_mgr |
| 340 | try: |
| 341 | # load config |
| 342 | load_config() |
| 343 | # ctrl + c |
| 344 | sigterm_handler_wrap(signal.SIGINT) |
| 345 | # kill signal |
| 346 | sigterm_handler_wrap(signal.SIGTERM) |
| 347 | |
| 348 | # Parse channel_type into a list |
| 349 | raw_channel = conf().get("channel_type", "web") |
| 350 | |
| 351 | if "--cmd" in sys.argv: |
| 352 | channel_names = ["terminal"] |
| 353 | else: |
| 354 | channel_names = _parse_channel_type(raw_channel) |
| 355 | if not channel_names: |
| 356 | channel_names = ["web"] |
| 357 | |
| 358 | # Auto-start web console unless explicitly disabled |
| 359 | web_console_enabled = conf().get("web_console", True) |
| 360 | if web_console_enabled and "web" not in channel_names: |
| 361 | channel_names.append("web") |
| 362 | |
| 363 | # Sync builtin skills to workspace before channels start |
| 364 | _sync_builtin_skills() |
| 365 | |
| 366 | # Kick off MCP server loading in the background so first-message |
| 367 | # latency isn't dominated by npx package downloads. |
| 368 | _warmup_mcp_tools() |
| 369 | |
| 370 | _warmup_scheduler() |
| 371 | |
| 372 | logger.info(f"[App] Starting channels: {channel_names}") |
| 373 | |
| 374 | _channel_mgr = ChannelManager() |
| 375 | _channel_mgr.start(channel_names, first_start=True) |
| 376 | |
| 377 | while True: |
| 378 | time.sleep(1) |
| 379 | except KeyboardInterrupt: |
| 380 | pass |
| 381 | except Exception as e: |
| 382 | logger.error("App startup failed!") |
| 383 | logger.exception(e) |
| 384 | |
| 385 | |
| 386 | if __name__ == "__main__": |
no test coverage detected