| 2382 | } |
| 2383 | |
| 2384 | int main(int argc, char **argv) { |
| 2385 | /* Must remain the first statement: see allocator binding contract above. */ |
| 2386 | cbm_alloc_init(); |
| 2387 | #ifndef _WIN32 |
| 2388 | pid_t process_initial_ppid = getppid(); |
| 2389 | #endif |
| 2390 | #ifdef _WIN32 |
| 2391 | { |
| 2392 | int win_argc = 0; |
| 2393 | char **win_argv = cbm_win_utf8_argv(&win_argc); |
| 2394 | if (win_argv) { |
| 2395 | argc = win_argc; |
| 2396 | argv = win_argv; |
| 2397 | } |
| 2398 | } |
| 2399 | #endif |
| 2400 | cbm_daemon_process_role_t role = cbm_daemon_process_role(argc, argv); |
| 2401 | if (role == CBM_DAEMON_PROCESS_INVALID) { |
| 2402 | (void)fprintf(stderr, "codebase-memory-mcp: invalid internal process arguments\n"); |
| 2403 | return EXIT_FAILURE; |
| 2404 | } |
| 2405 | #ifndef _WIN32 |
| 2406 | if (role == CBM_DAEMON_PROCESS_DAEMON) { |
| 2407 | (void)umask(077); |
| 2408 | } |
| 2409 | #endif |
| 2410 | |
| 2411 | cbm_cli_set_version(CBM_VERSION); |
| 2412 | cbm_profile_init(); |
| 2413 | cbm_log_init_from_env(); |
| 2414 | |
| 2415 | cbm_mcp_tool_profile_t tool_profile = CBM_MCP_TOOL_PROFILE_ALL; |
| 2416 | if (role == CBM_DAEMON_PROCESS_MCP_CLIENT && |
| 2417 | cbm_mcp_parse_tool_profile_args(argc, (const char *const *)argv, &tool_profile) != 0) { |
| 2418 | (void)fprintf(stderr, "codebase-memory-mcp: --tool-profile requires the supported value " |
| 2419 | "'analysis' or 'scout'\n"); |
| 2420 | return 2; |
| 2421 | } |
| 2422 | const char *hook_event = NULL; |
| 2423 | const char *hook_dialect = NULL; |
| 2424 | if (role == CBM_DAEMON_PROCESS_HOOK_CLIENT && |
| 2425 | !main_hook_options(argc, argv, &hook_event, &hook_dialect)) { |
| 2426 | return EXIT_SUCCESS; /* hook adapters are contractually fail-open */ |
| 2427 | } |
| 2428 | |
| 2429 | /* Hook augmentation is contractually fail-open and time-bounded. It is |
| 2430 | * daemon-backed but CONNECT-ONLY: a hook never spawns a daemon (a cold |
| 2431 | * spawn cannot fit the fail-open budget and livelocks against the |
| 2432 | * last-client-exit teardown), it recycles whichever daemon an MCP |
| 2433 | * session or `daemon start` already brought up. Arm the deadline before |
| 2434 | * hashing and IPC. */ |
| 2435 | if (role == CBM_DAEMON_PROCESS_HOOK_CLIENT) { |
| 2436 | #ifndef _WIN32 |
| 2437 | cbm_hook_augment_arm_deadline(); |
| 2438 | #endif |
| 2439 | } |
| 2440 | |
| 2441 | if (role == CBM_DAEMON_PROCESS_STATELESS) { |
nothing calls this directly
no test coverage detected