| 2328 | } |
| 2329 | |
| 2330 | int main(int argc, char **argv) { |
| 2331 | /* Must remain the first statement: see allocator binding contract above. */ |
| 2332 | cbm_alloc_init(); |
| 2333 | #ifndef _WIN32 |
| 2334 | pid_t process_initial_ppid = getppid(); |
| 2335 | #endif |
| 2336 | #ifdef _WIN32 |
| 2337 | { |
| 2338 | int win_argc = 0; |
| 2339 | char **win_argv = cbm_win_utf8_argv(&win_argc); |
| 2340 | if (win_argv) { |
| 2341 | argc = win_argc; |
| 2342 | argv = win_argv; |
| 2343 | } |
| 2344 | } |
| 2345 | #endif |
| 2346 | cbm_daemon_process_role_t role = cbm_daemon_process_role(argc, argv); |
| 2347 | if (role == CBM_DAEMON_PROCESS_INVALID) { |
| 2348 | (void)fprintf(stderr, "codebase-memory-mcp: invalid internal process arguments\n"); |
| 2349 | return EXIT_FAILURE; |
| 2350 | } |
| 2351 | #ifndef _WIN32 |
| 2352 | if (role == CBM_DAEMON_PROCESS_DAEMON) { |
| 2353 | (void)umask(077); |
| 2354 | } |
| 2355 | #endif |
| 2356 | |
| 2357 | cbm_cli_set_version(CBM_VERSION); |
| 2358 | cbm_profile_init(); |
| 2359 | cbm_log_init_from_env(); |
| 2360 | |
| 2361 | cbm_mcp_tool_profile_t tool_profile = CBM_MCP_TOOL_PROFILE_ALL; |
| 2362 | if (role == CBM_DAEMON_PROCESS_MCP_CLIENT && |
| 2363 | cbm_mcp_parse_tool_profile_args(argc, (const char *const *)argv, &tool_profile) != 0) { |
| 2364 | (void)fprintf(stderr, "codebase-memory-mcp: --tool-profile requires the supported value " |
| 2365 | "'analysis' or 'scout'\n"); |
| 2366 | return 2; |
| 2367 | } |
| 2368 | const char *hook_event = NULL; |
| 2369 | const char *hook_dialect = NULL; |
| 2370 | if (role == CBM_DAEMON_PROCESS_HOOK_CLIENT && |
| 2371 | !main_hook_options(argc, argv, &hook_event, &hook_dialect)) { |
| 2372 | return EXIT_SUCCESS; /* hook adapters are contractually fail-open */ |
| 2373 | } |
| 2374 | |
| 2375 | /* Hook augmentation is contractually fail-open and time-bounded. It is |
| 2376 | * daemon-backed but CONNECT-ONLY: a hook never spawns a daemon (a cold |
| 2377 | * spawn cannot fit the fail-open budget and livelocks against the |
| 2378 | * last-client-exit teardown), it recycles whichever daemon an MCP |
| 2379 | * session or `daemon start` already brought up. Arm the deadline before |
| 2380 | * hashing and IPC. */ |
| 2381 | if (role == CBM_DAEMON_PROCESS_HOOK_CLIENT) { |
| 2382 | #ifndef _WIN32 |
| 2383 | cbm_hook_augment_arm_deadline(); |
| 2384 | #endif |
| 2385 | } |
| 2386 | |
| 2387 | if (role == CBM_DAEMON_PROCESS_STATELESS) { |
nothing calls this directly
no test coverage detected