From 2ecfe587a087e7df3ca91f797844acdf3509b0ea Mon Sep 17 00:00:00 2001 From: Peter Cardenas <16930781+PeterCardenas@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:59:01 -0700 Subject: [PATCH] feat: parse and conditionally add cursor rules to system prompt (#2385) --- lua/avante/llm.lua | 2 ++ lua/avante/utils/prompts.lua | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/lua/avante/llm.lua b/lua/avante/llm.lua index 4173eaa..2a33a58 100644 --- a/lua/avante/llm.lua +++ b/lua/avante/llm.lua @@ -388,6 +388,8 @@ function M.generate_prompts(opts) local agents_rules = Prompts.get_agents_rules_prompt() if agents_rules then system_prompt = system_prompt .. "\n\n" .. agents_rules end + local cursor_rules = Prompts.get_cursor_rules_prompt(selected_files) + if cursor_rules then system_prompt = system_prompt .. "\n\n" .. cursor_rules end ---@type AvantePromptOptions return { diff --git a/lua/avante/utils/prompts.lua b/lua/avante/utils/prompts.lua index 54c21be..75ab487 100644 --- a/lua/avante/utils/prompts.lua +++ b/lua/avante/utils/prompts.lua @@ -233,4 +233,52 @@ function M.get_agents_rules_prompt() return nil end +---@param selected_files AvanteSelectedFile[] +---@return string | nil +function M.get_cursor_rules_prompt(selected_files) + local Utils = require("avante.utils") + local project_root = Utils.get_project_root() + local accumulated_content = "" + + ---@type string[] + local mdc_files = vim.fn.globpath(Utils.join_paths(project_root, ".cursor/rules"), "*.mdc", false, true) + for _, file_path in ipairs(mdc_files) do + ---@type string[] + local content = vim.fn.readfile(file_path) + if content[1] ~= "---" or content[5] ~= "---" then goto continue end + local header, body = table.concat(content, "\n", 2, 4), table.concat(content, "\n", 6) + local _description, globs, alwaysApply = header:match("description:%s*(.*)\nglobs:%s*(.*)\nalwaysApply:%s*(.*)") + + if not globs then goto continue end + globs = vim.trim(globs) + -- TODO: When empty string, this means the agent should request for this rule ad-hoc. + if globs == "" then goto continue end + local globs_array = vim.split(globs, ",%s*") + local path_regexes = {} ---@type string[] + for _, glob in ipairs(globs_array) do + path_regexes[#path_regexes + 1] = glob:gsub("%*%*", ".+"):gsub("%*", "[^/]*") + path_regexes[#path_regexes + 1] = glob:gsub("%*%*/", ""):gsub("%*", "[^/]*") + end + local always_apply = alwaysApply == "true" + + if always_apply then + accumulated_content = accumulated_content .. "\n" .. body + else + local matched = false + for _, selected_file in ipairs(selected_files) do + for _, path_regex in ipairs(path_regexes) do + if string.match(selected_file.path, path_regex) then + accumulated_content = accumulated_content .. "\n" .. body + matched = true + break + end + end + if matched then break end + end + end + ::continue:: + end + return accumulated_content ~= "" and accumulated_content or nil +end + return M