From 2895ac732dce0eece5ab2586f5d4d76ee0fab710 Mon Sep 17 00:00:00 2001 From: Elvis Claros Castro Date: Thu, 23 Apr 2026 23:15:45 -0300 Subject: =?UTF-8?q?feat(neovim):=20integrar=20CodeCompanion/MCPHub,=20a?= =?UTF-8?q?=C3=B1adir=20autocompletado=20AI=20y=20actualizar=20plugins?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añadir integración completa de CodeCompanion (mcphub, adaptadores, UI, herramientas, historial, paleta de acciones) - Configuración de build/portado de `mcphub` y opciones de tiempo de ejecución - Configurar adaptadores, herramientas por defecto y múltiples adaptadores para `chat`/`inline`/`cmd` - Añadir autocomandos de CodeCompanion para mostrar/ocultar el spinner - Añadir keymaps relacionados con CodeCompanion - Añadir proveedor de autocompletado AI `minuet-ai` y cambiar la fuente de completado por defecto a `minuet` - Eliminar el archivo de configuración antiguo de Copilot y varios archivos de configuración de plugins obsoletos (`lua/config/copilot.lua`, `lua/plugins/foatterm.lua`, `lua/plugins/img-clip.lua`, `lua/plugins/markdown-preview.lua`, `lua/plugins/markview.lua`) - Actualizar muchos pines de plugins en `lazy-lock.json` (bump/reemplazo de commits) - Comentar los `autocmd` de trim de espacios en blanco y `clang-format` (deshabilita comportamiento de autoformateo/auto-guardar) - Establecer opciones globales: - desactivar el autoformateo global de LazyVim: `vim.g.autoformat = false` - evitar que `:w` agregue automáticamente un salto de línea final: `opt.fixeol = false` - Ajustes de UI: - agregar resaltados `FloatBorder`/`FloatTitle` y hacer `PmenuSel` en negrita - Añadir keymap específico para Rust: sobrescribir `K` para invocar las acciones de hover de `rustaceanvim` - Actualizar/limpiar muchas configuraciones de plugins: - reescritura amplia de `lua/plugins/codecompanion.lua` - añadir/modificar opciones de `lua/plugins/image.lua` (`image.nvim`) - ajustar UI, pickers y keymaps de `lua/plugins/snacks.lua` - actualizar versión de `rustaceanvim` y desactivar `format_on_save` en `navigator` - varias correcciones de formato y consistencia en archivos de plugins - Actualizar `lua/config/keymaps.lua` para incluir bindings de CodeCompanion Notas: - Estos cambios modifican el comportamiento de formateo/autoformateo (autoformateo desactivado y algunos `autocmd` `BufWritePre` comentados). Revisa si quieres reactivar el formateo automático al guardar. --- lua/plugins/codecompanion.lua | 559 ++++++++++++++++++++++-------------------- 1 file changed, 298 insertions(+), 261 deletions(-) (limited to 'lua/plugins/codecompanion.lua') diff --git a/lua/plugins/codecompanion.lua b/lua/plugins/codecompanion.lua index 052b066..90c78b8 100644 --- a/lua/plugins/codecompanion.lua +++ b/lua/plugins/codecompanion.lua @@ -1,291 +1,328 @@ -local IS_DEV = false return { - { - dir = IS_DEV and "~/Projects/research/codecompanion.nvim" or nil, - "olimorris/codecompanion.nvim", - dependencies = { - "nvim-lua/plenary.nvim", - "nvim-treesitter/nvim-treesitter", - -- "nvim-telescope/telescope.nvim", -- Using telescope for file and buffer picker - "jellydn/spinner.nvim", -- Show loading spinner when request is started - "ravitemer/codecompanion-history.nvim", -- History management extension - { - "echasnovski/mini.diff", - config = function() - local diff = require "mini.diff" - diff.setup { source = diff.gen_source.none() } - end, + "olimorris/codecompanion.nvim", + branch = "main", + dependencies = { + { + "ravitemer/mcphub.nvim", + dependencies = { + "nvim-lua/plenary.nvim", }, - { - "ravitemer/mcphub.nvim", - dependencies = { - "nvim-lua/plenary.nvim", - }, - build = "npm install -g mcp-hub@latest", -- Installs `mcp-hub` node binary globally - config = function() - require("mcphub").setup() - end, - }, - }, - opts = { - log_level = "TRACE", -- or "DEBUG" - adapters = { - http = { - ollama = function() - return require("codecompanion.adapters").extend("ollama", { - name = "tinyllama", - env = { - url = "http://127.0.0.1:11434", - -- api_key = "", - }, - headers = { - ["Content-Type"] = "application/json", - -- ["Authorization"] = "Bearer ${api_key}", - }, - parameters = { - sync = true, - }, - schema = { - model = { - default = "qwen2.5-coder:0.5b", - }, - }, - }) - end, - anthropic = function() - return require("codecompanion.adapters").extend("anthropic", { - env = { - api_key = "cmd:echo $ANTHROPIC_API_KEY", - }, - schema = { - model = { - default = "claude-3-opus-20240229", - }, - }, - }) - end, - copilot = function() - return require("codecompanion.adapters").extend("copilot", { - schema = { - model = { - default = "gpt-4.1", - }, - }, - }) - end, - gemini = function() - return require("codecompanion.adapters").extend("gemini", { - env = { - api_key = "cmd:echo $GEMINI_API_KEY", + build = "bundled_build.lua", -- Bundles `mcp-hub` binary along with the neovim plugin + config = function() + require("mcphub").setup({ + use_bundled_binary = true, -- Use local `mcp-hub` binary + --- `mcp-hub` binary related options------------------- + config = vim.fn.expand("~/.config/mcphub/servers.json"), -- Absolute path to MCP Servers config file (will create if not exists) + port = 37373, -- The port `mcp-hub` server listens to + shutdown_delay = 5 * 60 * 000, -- Delay in ms before shutting down the server when last instance closes (default: 5 minutes) + use_bundled_binary = false, -- Use local `mcp-hub` binary (set this to true when using build = "bundled_build.lua") + mcp_request_timeout = 60000, --Max time allowed for a MCP tool or resource to execute in milliseconds, set longer for long running tasks + global_env = {}, -- Global environment variables available to all MCP servers (can be a table or a function returning a table) + workspace = { + enabled = true, -- Enable project-local configuration files + look_for = { ".mcphub/servers.json", ".vscode/mcp.json", ".cursor/mcp.json" }, -- Files to look for when detecting project boundaries (VS Code format supported) + reload_on_dir_changed = true, -- Automatically switch hubs on DirChanged event + port_range = { min = 40000, max = 41000 }, -- Port range for generating unique workspace ports + get_port = nil, -- Optional function returning custom port number. Called when generating ports to allow custom port assignment logic + }, + + ---Chat-plugin related options----------------- + auto_approve = false, -- Auto approve mcp tool calls + auto_toggle_mcp_servers = true, -- Let LLMs start and stop MCP servers automatically + extensions = { + avante = { + make_slash_commands = true, -- make /slash commands from MCP server prompts + } + }, + + --- Plugin specific options------------------- + native_servers = {}, -- add your custom lua native servers here + builtin_tools = { + edit_file = { + parser = { + track_issues = true, + extract_inline_content = true, }, - }) - end, - openai = function() - return require("codecompanion.adapters").extend("openai", { - env = { - api_key = "cmd:echo $OPENAI_API_KEY", - chat_url = "/v1/chat/completions", - url = "https://api.openai.com", + locator = { + fuzzy_threshold = 0.8, + enable_fuzzy_matching = true, }, - schema = { - model = { - default = function() - return "gpt-4o-mini" - end, + ui = { + go_to_origin_on_complete = true, + keybindings = { + accept = ".", + reject = ",", + next = "n", + prev = "p", + accept_all = "ga", + reject_all = "gr", }, }, - }) + }, + }, + ui = { + window = { + width = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number) + height = 0.8, -- 0-1 (ratio); "50%" (percentage); 50 (raw number) + align = "center", -- "center", "top-left", "top-right", "bottom-left", "bottom-right", "top", "bottom", "left", "right" + relative = "editor", + zindex = 50, + border = "rounded", -- "none", "single", "double", "rounded", "solid", "shadow" + }, + wo = { -- window-scoped options (vim.wo) + winhl = "Normal:MCPHubNormal,FloatBorder:MCPHubBorder", + }, + }, + json_decode = nil, -- Custom JSON parser function (e.g., require('json5').parse for JSON5 support) + on_ready = function(hub) + -- Called when hub is ready end, - openai_compatible_llama_cpp = function() - return require("codecompanion.adapters").extend("openai_compatible", { - env = { - api_key = "cmd:echo $OPENAI_API_KEY", - chat_url = "/v1/chat/completions", - url = "http://127.0.0.1:8012", - }, - headers = { - ["Content-Type"] = "application/json", - }, - schema = { - model = { - default = function() - return "davinci" - end, - }, - }, - }) + on_error = function(err) + -- Called on errors end, + log = { + level = vim.log.levels.WARN, + to_file = false, + file_path = nil, + prefix = "MCPHub", + }, + }) + end, + }, + "nvim-lua/plenary.nvim", + "nvim-treesitter/nvim-treesitter", + "nvim-treesitter/nvim-treesitter", + "jellydn/spinner.nvim", -- Show loading spinner when request is started + "ravitemer/codecompanion-history.nvim", -- History management extension + { + "echasnovski/mini.diff", + config = function() + local diff = require "mini.diff" + diff.setup { source = diff.gen_source.none() } + end, + }, + { + "HakonHarnes/img-clip.nvim", + opts = { + filetypes = { + codecompanion = { + prompt_for_file_name = false, + template = "[Image]($FILE_PATH)", + use_absolute_path = true, + }, + }, + }, + }, + { + "OXY2DEV/markview.nvim", + lazy = false, + opts = { + preview = { + filetypes = { "markdown", "codecompanion" }, + ignore_buftypes = {}, + }, + }, + }, + + }, + opts = { + log_level = "DEBUG", + }, + config = function() + -- Compatibility patch for recent CodeCompanion/Copilot model schemas + -- where `schema.model.choices` can be a function instead of a table. + local adapter_utils = require("codecompanion.utils.adapters") + adapter_utils.model_choice = function(adapter) + local model = adapter_utils.model(adapter) + local choices = adapter.schema.model.choices + + if type(choices) == "function" then + choices = choices(adapter, { async = false }) + end + + if type(choices) ~= "table" then + return nil + end + + return choices[model] + end - openai_compatible_qwen3_coder = function() + require("codecompanion").setup({ + mcp = { + servers = { + ["duckduckgo-mcp"] = { + cmd = { "npx", "-y", "duckduckgo-mcp" }, + }, + }, + opts = { + default_servers = { "duckduckgo-mcp" }, + }, + }, + adapters = { + http = { + ["llama.cpp"] = function() return require("codecompanion.adapters").extend("openai_compatible", { env = { - api_key = "cmd:echo $DASHSCOPE_API_KEY", + url = "http://127.0.0.1:8012", -- replace with your llama.cpp instance chat_url = "/v1/chat/completions", - url = "https://dashscope-intl.aliyuncs.com/compatible-mode", - }, - headers = { - ["Content-Type"] = "application/json", - }, - schema = { - model = { - default = function() - return "qwen3-coder-plus" - end, - }, - }, - }) - end, - - xai = function() - return require("codecompanion.adapters").extend("xai", { - env = { - api_key = "cmd:op read op://personal/xAI_API/credential --no-newline", - }, - }) - end, - azure_openai = function() - return require("codecompanion.adapters").extend("azure_openai", { - env = { - api_key = "cmd:echo $AZ_DS_API_KEY", - endpoint = "https://DeepSeek-R1-nphob.eastus2.models.ai.azure.com", - }, - schema = { - model = { - default = "DeepSeek-R1-nphob", - }, }, }) end, }, }, - display = { - diff = { - provider = "mini_diff", - }, - }, - strategies = { + interactions = { chat = { - adapter = "openai_compatible_qwen3_coder", - -- roles = { llm = " Copilot Chat", user = "IT Man" }, - }, - inline = { adapter = "copilot" }, - agent = { adapter = "copilot" }, - cmd = { adapter = "copilot" }, - }, - }, - config = function(_, options) - require("codecompanion").setup(options) - require("codecompanion").setup { - opts = { - language = "English", - }, - extensions = { - mcphub = { - callback = "mcphub.extensions.codecompanion", + -- opts = { + -- system_prompt = function(ctx) + -- return "You are a helpful coding assistant. Today is " .. ctx.date + -- end, + -- }, + auto_scroll = false, + tools = { opts = { - make_vars = true, - make_slash_commands = true, - show_result_in_chat = true, + default_tools = { + "agent", + "neovim", + "files", + "grep_search", + "get_changed_files", + "fetch_webpage", + }, + auto_submit_errors = true, -- Send any errors to the LLM automatically? + auto_submit_success = true, -- Send any successful output to the LLM automatically? }, }, - history = { - enabled = true, - opts = { - -- Keymap to open history from chat buffer (default: gh) - keymap = "gh", - -- Keymap to save the current chat manually (when auto_save is disabled) - save_chat_keymap = "sc", - -- Save all chats by default (disable to save only manually using 'sc') - auto_save = true, - -- Number of days after which chats are automatically deleted (0 to disable) - expiration_days = 0, - -- Picker interface (auto resolved to a valid picker) - picker = "snacks", -- ("telescope", "snacks", "fzf-lua", or "default") - -- Optional filter function to control which chats are shown when browsing - chat_filter = nil, -- function(chat_data) return boolean end - -- Customize picker keymaps (optional) - picker_keymaps = { - rename = { n = "r", i = "" }, - delete = { n = "d", i = "" }, - duplicate = { n = "", i = "" }, + slash_commands = { + ["file"] = { + -- Use Snacks as the provider for the /file command + opts = { + provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks" }, - -- Automatically generate titles for new chats - auto_generate_title = true, - title_generation_opts = { - -- Adapter for generating titles (defaults to current chat adapter) - adapter = "copilot", -- Use copilot for cheaper title generation - -- Model for generating titles (defaults to current chat model) - model = "gpt-4.1", -- Use cheaper model for titles - -- Number of user prompts after which to refresh the title (0 to disable) - refresh_every_n_prompts = 3, -- Refresh after every 3rd user prompt - -- Maximum number of times to refresh the title (default: 3) - max_refreshes = 5, - format_title = function(original_title) - -- Custom formatting for titles - return original_title - end, + }, + ["image"] = { + ---@param opts { adapter: CodeCompanion.HTTPAdapter } + ---@return boolean + enabled = function(opts) + return opts.adapter.opts and opts.adapter.opts.vision == true + end, + -- Keep snacks for image-aware picker preview + opts = { + provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks" }, - -- On exiting and entering neovim, loads the last chat on opening chat - continue_last_chat = false, - -- When chat is cleared with `gx` delete the chat from history - delete_on_clearing_chat = false, - -- Directory path to save the chats - dir_to_save = vim.fn.stdpath "data" .. "/codecompanion-history", - -- Enable detailed logging for history extension - enable_logging = false, + }, - -- Summary system - summary = { - -- Keymap to generate summary for current chat (default: "gcs") - create_summary_keymap = "gcs", - -- Keymap to browse summaries (default: "gbs") - browse_summaries_keymap = "gbs", - generation_opts = { - adapter = "copilot", -- Use copilot for cheaper summary generation - model = "gpt-4.1", -- Use cheaper model for summaries - context_size = 90000, -- max tokens that the model supports - include_references = true, -- include slash command content - include_tool_outputs = true, -- include tool execution results - system_prompt = nil, -- custom system prompt (string or function) - format_summary = nil, -- custom function to format generated summary - }, + }, + -- adapter = "llama.cpp", + adapter = { + name = "copilot", + model = "gpt-5-mini", + }, + }, + inline = { + -- adapter = "llama.cpp", + adapter = { + name = "copilot", + model = "gpt-5-mini", + }, + }, + cmd = { + -- adapter = "llama.cpp", + adapter = { + name = "copilot", + model = "gpt-5-mini", + }, + }, + background = { + -- adapter = "llama.cpp" + adapter = { + name = "copilot", + model = "gpt-5-mini", + }, + }, + }, + extensions = { + history = { + enabled = true, + opts = { + keymap = "gh", + save_chat_keymap = "sc", + auto_save = true, + expiration_days = 0, + picker = "snacks", + chat_filter = nil, + picker_keymaps = { + rename = { n = "r", i = "" }, + delete = { n = "d", i = "" }, + duplicate = { n = "", i = "" }, + }, + auto_generate_title = true, + title_generation_opts = { + adapter = nil, + model = nil, + refresh_every_n_prompts = 0, -- e.g., 3 to refresh after every 3rd user prompt + max_refreshes = 3, + format_title = function(original_title) + return original_title + end + }, + continue_last_chat = false, + delete_on_clearing_chat = false, + dir_to_save = vim.fn.stdpath("data") .. "/codecompanion-history", + enable_logging = false, + + summary = { + create_summary_keymap = "gcs", + browse_summaries_keymap = "gbs", + generation_opts = { + adapter = nil, -- defaults to current chat adapter + model = nil, -- defaults to current chat model + context_size = 90000, -- max tokens that the model supports + include_references = true, -- include slash command content + include_tool_outputs = true, -- include tool execution results + system_prompt = nil, -- custom system prompt (string or function) + format_summary = nil, -- custom function to format generated summary e.g to remove tags from summary }, + }, - -- Memory system (requires VectorCode CLI) - memory = { - -- Automatically index summaries when they are generated - auto_create_memories_on_summary_generation = false, -- Disabled by default - -- Path to the VectorCode executable - vectorcode_exe = "vectorcode", - -- Tool configuration - tool_opts = { - -- Default number of memories to retrieve - default_num = 10, - }, - -- Enable notifications for indexing progress - notify = true, - -- Index all existing memories on startup - index_on_startup = false, + memory = { + auto_create_memories_on_summary_generation = true, + vectorcode_exe = "vectorcode", + tool_opts = { + default_num = 10 }, + notify = true, + index_on_startup = false, }, - }, + } + } + }, + action_palette = { + width = 95, + height = 10, + prompt = "Prompt ", -- Prompt used for interactive LLM calls + provider = "snacks", -- Can be "default", "telescope", "fzf_lua", "mini_pick" or "snacks". If not specified, the plugin will autodetect installed providers. + opts = { + show_preset_actions = true, -- Show the preset actions in the action palette? + show_preset_prompts = true, -- Show the preset prompts in the action palette? + title = "CodeCompanion actions", -- The title of the action palette }, - } - -- Show loading spinner when request is started - local spinner = require "spinner" - local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {}) - vim.api.nvim_create_autocmd({ "User" }, { - pattern = "CodeCompanionRequest*", - group = group, - callback = function(request) - if request.match == "CodeCompanionRequestStarted" then - spinner.show() - end - if request.match == "CodeCompanionRequestFinished" then - spinner.hide() - end - end, - }) - end, - }, + }, + }) + + -- Show loading spinner when request is started + local spinner = require "spinner" + local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {}) + vim.api.nvim_create_autocmd({ "User" }, { + pattern = "CodeCompanionRequest*", + group = group, + callback = function(request) + if request.match == "CodeCompanionRequestStarted" then + spinner.show() + end + if request.match == "CodeCompanionRequestFinished" then + spinner.hide() + end + end, + }) + end, } -- cgit v1.2.3