| 9864 | #endif |
| 9865 | |
| 9866 | static char *handle_search_code(cbm_mcp_server_t *srv, const char *args) { |
| 9867 | char *pattern = cbm_mcp_get_string_arg(args, "pattern"); |
| 9868 | char *project = get_project_arg(args); |
| 9869 | char *file_pattern = cbm_mcp_get_string_arg(args, "file_pattern"); |
| 9870 | char *path_filter = cbm_mcp_get_string_arg(args, "path_filter"); |
| 9871 | char *mode_str = cbm_mcp_get_string_arg(args, "mode"); |
| 9872 | int limit = cbm_mcp_get_int_arg(args, "limit", MCP_DEFAULT_LIMIT); |
| 9873 | /* #1511: a negative limit flowed straight into the result cap and came back |
| 9874 | * as the reported count ("results: -5"), which reads to an agent as a real |
| 9875 | * answer rather than a rejected argument. The schema now declares |
| 9876 | * minimum:1, but a schema is a request to the client, never a guarantee to |
| 9877 | * the server — clamp here too. */ |
| 9878 | if (limit < 1) { |
| 9879 | limit = MCP_DEFAULT_LIMIT; |
| 9880 | } |
| 9881 | int context_lines = cbm_mcp_get_int_arg(args, "context", 0); |
| 9882 | bool use_regex = cbm_mcp_get_bool_arg(args, "regex"); |
| 9883 | uint64_t search_t0 = cbm_now_ms(); |
| 9884 | search_metrics_t metrics = {0}; |
| 9885 | metrics.include_phase_timings = cbm_mcp_get_bool_arg(args, "debug"); |
| 9886 | /* In literal (non-regex) mode a '|' is matched as a byte, not alternation — |
| 9887 | * a common silent 0-match trap; flagged in the result warnings (#282). */ |
| 9888 | bool pat_has_pipe = pattern && strchr(pattern, '|') != NULL; |
| 9889 | |
| 9890 | int mode = parse_search_mode(mode_str); |
| 9891 | free(mode_str); |
| 9892 | |
| 9893 | cbm_regex_t path_regex; |
| 9894 | bool has_path_filter = compile_path_filter(path_filter, &path_regex); |
| 9895 | free(path_filter); |
| 9896 | path_filter = NULL; |
| 9897 | |
| 9898 | if (!pattern) { |
| 9899 | free(project); |
| 9900 | free(file_pattern); |
| 9901 | return cbm_mcp_text_result("pattern is required", true); |
| 9902 | } |
| 9903 | |
| 9904 | /* Project is required */ |
| 9905 | if (!project) { |
| 9906 | free(pattern); |
| 9907 | free(file_pattern); |
| 9908 | char *_err = build_project_list_error("project is required"); |
| 9909 | char *_res = cbm_mcp_text_result(_err, true); |
| 9910 | free(_err); |
| 9911 | return _res; |
| 9912 | } |
| 9913 | |
| 9914 | char *root_path = get_project_root(srv, project); |
| 9915 | if (!root_path) { |
| 9916 | free(pattern); |
| 9917 | free(project); |
| 9918 | free(file_pattern); |
| 9919 | char *_err = build_project_list_error("project not found or not indexed"); |
| 9920 | char *_res = cbm_mcp_text_result(_err, true); |
| 9921 | free(_err); |
| 9922 | return _res; |
| 9923 | } |
no test coverage detected