One-shot CLI commands execute through the shared daemon, exactly like MCP * sessions and hooks: an active daemon (any starter) is recycled, an absent * one is spawned for this command — with a hint that `daemon start` removes * that per-command cost. Only supervised index workers stay in-process. */
| 1483 | * one is spawned for this command — with a hint that `daemon start` removes |
| 1484 | * that per-command cost. Only supervised index workers stay in-process. */ |
| 1485 | static char *main_local_cli_daemon_execute(const char *tool_name, const char *args_json) { |
| 1486 | cbm_daemon_ipc_endpoint_t *endpoint = cbm_daemon_bootstrap_endpoint_new(NULL); |
| 1487 | char executable_path[MAIN_PATH_CAP] = {0}; |
| 1488 | cbm_daemon_build_identity_t identity; |
| 1489 | bool prepared = |
| 1490 | endpoint && |
| 1491 | cbm_http_server_resolve_binary_path(NULL, executable_path, sizeof(executable_path)) && |
| 1492 | main_build_identity(&identity) == MAIN_BUILD_IDENTITY_OK; |
| 1493 | if (!prepared) { |
| 1494 | (void)fprintf(stderr, "error: daemon-backed CLI coordination could not be prepared\n"); |
| 1495 | cbm_daemon_ipc_endpoint_free(endpoint); |
| 1496 | return NULL; |
| 1497 | } |
| 1498 | cbm_daemon_bootstrap_config_t config = { |
| 1499 | .role = CBM_DAEMON_PROCESS_MCP_CLIENT, |
| 1500 | .endpoint = endpoint, |
| 1501 | .identity = &identity, |
| 1502 | .executable_path = executable_path, |
| 1503 | .connect_timeout_ms = MAIN_CONNECT_TIMEOUT_MS, |
| 1504 | .startup_timeout_ms = MAIN_MCP_STARTUP_TIMEOUT_MS, |
| 1505 | }; |
| 1506 | cbm_daemon_bootstrap_result_t bootstrap; |
| 1507 | cbm_daemon_bootstrap_status_t status = main_client_bootstrap_with_upgrade(&config, &bootstrap); |
| 1508 | cbm_daemon_ipc_endpoint_free(endpoint); |
| 1509 | if (status != CBM_DAEMON_BOOTSTRAP_CONNECTED || !bootstrap.client) { |
| 1510 | (void)fprintf(stderr, "error: %s\n", |
| 1511 | bootstrap.message[0] ? bootstrap.message |
| 1512 | : "no CBM daemon connection for CLI execution"); |
| 1513 | return NULL; |
| 1514 | } |
| 1515 | if (bootstrap.daemon_spawned) { |
| 1516 | (void)fprintf(stderr, "hint: this command started a temporary CBM daemon. " |
| 1517 | "`codebase-memory-mcp daemon start` keeps one warm and removes this " |
| 1518 | "startup cost from every CLI command.\n"); |
| 1519 | } |
| 1520 | char session_root[MAIN_PATH_CAP]; |
| 1521 | char allowed_root[MAIN_PATH_CAP]; |
| 1522 | const char *allowed_root_ptr = NULL; |
| 1523 | char *result = NULL; |
| 1524 | uint8_t *response = NULL; |
| 1525 | uint32_t response_length = 0; |
| 1526 | bool context_ok = |
| 1527 | main_session_context(NULL, session_root, allowed_root, &allowed_root_ptr) && |
| 1528 | main_set_client_context(bootstrap.client, session_root, CBM_MCP_TOOL_PROFILE_ALL, NULL, |
| 1529 | NULL, MAIN_CONNECT_TIMEOUT_MS); |
| 1530 | if (context_ok && |
| 1531 | cbm_daemon_application_client_tool(bootstrap.client, tool_name, args_json, &response, |
| 1532 | &response_length, MAIN_REQUEST_TIMEOUT_MS) == |
| 1533 | CBM_DAEMON_RUNTIME_APPLICATION_OK && |
| 1534 | response && response_length > 0) { |
| 1535 | result = malloc((size_t)response_length + 1U); |
| 1536 | if (result) { |
| 1537 | memcpy(result, response, response_length); |
| 1538 | result[response_length] = '\0'; |
| 1539 | } |
| 1540 | } |
| 1541 | free(response); |
| 1542 | if (!result) { |
no test coverage detected