| 2442 | } |
| 2443 | |
| 2444 | static int main_run_daemon_ctl(int argc, char **argv, const cbm_daemon_ipc_endpoint_t *endpoint, |
| 2445 | const cbm_daemon_build_identity_t *identity, |
| 2446 | const char *executable_path) { |
| 2447 | const char *subcommand = NULL; |
| 2448 | bool open_browser = false; |
| 2449 | int requested_port = 0; |
| 2450 | bool arguments_valid = true; |
| 2451 | for (int index = 1; index < argc; index++) { |
| 2452 | if (strcmp(argv[index], "daemon") == 0) { |
| 2453 | continue; |
| 2454 | } |
| 2455 | if (strcmp(argv[index], "start") == 0 || strcmp(argv[index], "stop") == 0 || |
| 2456 | strcmp(argv[index], "status") == 0) { |
| 2457 | subcommand = argv[index]; |
| 2458 | } else if (strcmp(argv[index], "--open") == 0) { |
| 2459 | open_browser = true; |
| 2460 | } else if (strncmp(argv[index], "--port=", 7) == 0) { |
| 2461 | requested_port = atoi(argv[index] + 7); |
| 2462 | if (requested_port <= 0 || requested_port >= MAIN_MAX_PORT) { |
| 2463 | (void)fprintf(stderr, "error: --port requires a value between 1 and 65535\n"); |
| 2464 | return EXIT_FAILURE; |
| 2465 | } |
| 2466 | } else { |
| 2467 | (void)fprintf(stderr, "error: unknown daemon option: %s\n", argv[index]); |
| 2468 | arguments_valid = false; |
| 2469 | break; |
| 2470 | } |
| 2471 | } |
| 2472 | if (!arguments_valid || !subcommand) { |
| 2473 | (void)fprintf(stderr, "usage: codebase-memory-mcp daemon <start|stop|status> " |
| 2474 | "[--open] [--port=N]\n"); |
| 2475 | return EXIT_FAILURE; |
| 2476 | } |
| 2477 | |
| 2478 | cbm_daemon_runtime_status_t status; |
| 2479 | bool active = cbm_daemon_runtime_request_status(endpoint, identity, |
| 2480 | MAIN_DAEMON_CTL_PROBE_TIMEOUT_MS, &status); |
| 2481 | |
| 2482 | if (strcmp(subcommand, "status") == 0) { |
| 2483 | if (!active) { |
| 2484 | if (status.muted_endpoint_holder_pid != 0) { |
| 2485 | /* Alive process, dead runtime (2026-08-29 zombie class). |
| 2486 | * "not running" here sent the operator hunting through |
| 2487 | * processes, pipes, and logs by hand; name the holder and the |
| 2488 | * recovery instead. */ |
| 2489 | printf("daemon: not responding (endpoint held by pid %llu)\n", |
| 2490 | (unsigned long long)status.muted_endpoint_holder_pid); |
| 2491 | printf("hint: that process holds the daemon endpoint but answered nothing; " |
| 2492 | "its runtime is likely dead. Terminate pid %llu, then run " |
| 2493 | "`codebase-memory-mcp daemon start`.\n", |
| 2494 | (unsigned long long)status.muted_endpoint_holder_pid); |
| 2495 | return EXIT_FAILURE; |
| 2496 | } |
| 2497 | printf("daemon: not running\n"); |
| 2498 | printf("hint: `codebase-memory-mcp daemon start` keeps a daemon warm so CLI " |
| 2499 | "commands and hooks skip the per-command startup cost.\n"); |
| 2500 | return EXIT_FAILURE; |
| 2501 | } |
no test coverage detected