diff --git a/src/mcp/mcp.c b/src/mcp/mcp.c index 8d8810896..8ca146415 100644 --- a/src/mcp/mcp.c +++ b/src/mcp/mcp.c @@ -3821,10 +3821,10 @@ static void build_grep_cmd(char *cmd, size_t cmd_sz, bool use_regex, bool scoped const char *flag = use_regex ? "-E" : "-F"; if (scoped) { if (file_pattern) { - snprintf(cmd, cmd_sz, "xargs grep -Hn %s --include='%s' -f '%s' < '%s' 2>/dev/null", + snprintf(cmd, cmd_sz, "xargs -0 grep -Hn %s --include='%s' -f '%s' < '%s' 2>/dev/null", flag, file_pattern, tmpfile, filelist); } else { - snprintf(cmd, cmd_sz, "xargs grep -Hn %s -f '%s' < '%s' 2>/dev/null", flag, tmpfile, + snprintf(cmd, cmd_sz, "xargs -0 grep -Hn %s -f '%s' < '%s' 2>/dev/null", flag, tmpfile, filelist); } } else { @@ -4240,10 +4240,29 @@ static bool write_scoped_filelist(cbm_mcp_server_t *srv, const char *project, co bool ok = false; if (fl) { for (int fi = 0; fi < indexed_count; fi++) { - /* Use forward slashes so xargs doesn't interpret Windows - * backslashes as escape sequences (e.g. \n becomes newline). - * Binary mode to prevent CRLF (xargs would see trailing \r). */ - (void)fprintf(fl, "%s/%s\n", root_path, indexed_files[fi]); + /* Build "/". Separator differs by platform: + * - Unix: NUL-separated, consumed by `xargs -0` (handles + * spaces in paths; newline would split on \n in paths). + * - Windows: newline-separated, consumed by PowerShell + * `Get-Content | ForEach-Object { Select-String -LiteralPath $_ }` + * which reads line-by-line and accepts spaces in each path; + * NUL bytes break Get-Content ("Illegal characters in path"). + * Binary mode prevents CRLF translation on Windows. */ + size_t rlen = strlen(root_path); + size_t flen = strlen(indexed_files[fi]); + char buf[CBM_SZ_2K]; + size_t total = 0; + memcpy(buf + total, root_path, rlen); + total += rlen; + buf[total++] = '/'; + memcpy(buf + total, indexed_files[fi], flen); + total += flen; +#ifdef _WIN32 + buf[total++] = '\n'; /* line-separated for PowerShell Get-Content */ +#else + buf[total++] = '\0'; /* NUL separator for xargs -0 */ +#endif + (void)fwrite(buf, 1, total, fl); } (void)fclose(fl); ok = true;