| 9687 | } |
| 9688 | |
| 9689 | static char *handle_search_code(cbm_mcp_server_t *srv, const char *args) { |
| 9690 | char *pattern = cbm_mcp_get_string_arg(args, "pattern"); |
| 9691 | char *project = get_project_arg(args); |
| 9692 | char *file_pattern = cbm_mcp_get_string_arg(args, "file_pattern"); |
| 9693 | char *path_filter = cbm_mcp_get_string_arg(args, "path_filter"); |
| 9694 | char *mode_str = cbm_mcp_get_string_arg(args, "mode"); |
| 9695 | int limit = cbm_mcp_get_int_arg(args, "limit", MCP_DEFAULT_LIMIT); |
| 9696 | /* #1511: a negative limit flowed straight into the result cap and came back |
| 9697 | * as the reported count ("results: -5"), which reads to an agent as a real |
| 9698 | * answer rather than a rejected argument. The schema now declares |
| 9699 | * minimum:1, but a schema is a request to the client, never a guarantee to |
| 9700 | * the server — clamp here too. */ |
| 9701 | if (limit < 1) { |
| 9702 | limit = MCP_DEFAULT_LIMIT; |
| 9703 | } |
| 9704 | int context_lines = cbm_mcp_get_int_arg(args, "context", 0); |
| 9705 | bool use_regex = cbm_mcp_get_bool_arg(args, "regex"); |
| 9706 | uint64_t search_t0 = cbm_now_ms(); |
| 9707 | search_metrics_t metrics = {0}; |
| 9708 | metrics.include_phase_timings = cbm_mcp_get_bool_arg(args, "debug"); |
| 9709 | /* In literal (non-regex) mode a '|' is matched as a byte, not alternation — |
| 9710 | * a common silent 0-match trap; flagged in the result warnings (#282). */ |
| 9711 | bool pat_has_pipe = pattern && strchr(pattern, '|') != NULL; |
| 9712 | |
| 9713 | int mode = parse_search_mode(mode_str); |
| 9714 | free(mode_str); |
| 9715 | |
| 9716 | cbm_regex_t path_regex; |
| 9717 | bool has_path_filter = compile_path_filter(path_filter, &path_regex); |
| 9718 | free(path_filter); |
| 9719 | path_filter = NULL; |
| 9720 | |
| 9721 | if (!pattern) { |
| 9722 | free(project); |
| 9723 | free(file_pattern); |
| 9724 | return cbm_mcp_text_result("pattern is required", true); |
| 9725 | } |
| 9726 | |
| 9727 | /* Project is required */ |
| 9728 | if (!project) { |
| 9729 | free(pattern); |
| 9730 | free(file_pattern); |
| 9731 | char *_err = build_project_list_error("project is required"); |
| 9732 | char *_res = cbm_mcp_text_result(_err, true); |
| 9733 | free(_err); |
| 9734 | return _res; |
| 9735 | } |
| 9736 | |
| 9737 | char *root_path = get_project_root(srv, project); |
| 9738 | if (!root_path) { |
| 9739 | free(pattern); |
| 9740 | free(project); |
| 9741 | free(file_pattern); |
| 9742 | char *_err = build_project_list_error("project not found or not indexed"); |
| 9743 | char *_res = cbm_mcp_text_result(_err, true); |
| 9744 | free(_err); |
| 9745 | return _res; |
| 9746 | } |
no test coverage detected