updates for codecompanion

This commit is contained in:
2026-02-17 14:32:35 -06:00
parent bc11e9e186
commit acb86e77f3
3 changed files with 468 additions and 183 deletions

55
STYLUA_FIX.md Normal file
View File

@@ -0,0 +1,55 @@
# Stylua Crash Fix
## Problem
You were experiencing stylua crashing errors after upgrading Neovim. This was likely caused by stylua 2.1.0 requiring explicit configuration.
## Root Cause
Stylua 2.1.0 introduced stricter configuration requirements. Without a `.stylua.toml` configuration file, stylua may fail or behave unexpectedly when called by conform.nvim.
## Solution
Created a `.stylua.toml` configuration file in your project root with sensible defaults that match your Neovim configuration style:
```toml
column_width = 120
line_endings = "Unix"
indent_type = "Tabs"
indent_width = 4
quote_style = "AutoPreferDouble"
call_parentheses = "Input"
collapse_simple_statement = "Never"
```
## What This Configuration Does
- **column_width = 120**: Wraps lines at 120 characters
- **line_endings = "Unix"**: Uses Unix line endings (LF)
- **indent_type = "Tabs"**: Uses tabs for indentation (matches your config)
- **indent_width = 4**: Tab width of 4 spaces
- **quote_style = "AutoPreferDouble"**: Prefers double quotes
- **call_parentheses = "Input"**: Preserves input parentheses style
- **collapse_simple_statement = "Never"**: Doesn't collapse simple statements
## Files Modified
- Created: `.stylua.toml` (new configuration file)
## Testing
Stylua now works correctly:
```bash
stylua lua/shelbybark/core/init.lua # ✓ Success
```
## How to Verify
1. Open any Lua file in Neovim
2. Press `<leader>mp` to format
3. Stylua should format without errors
## Additional Notes
- This configuration file will be used by stylua automatically
- It applies to all Lua files in your project
- You can customize the settings in `.stylua.toml` as needed
- The configuration is compatible with stylua 2.1.0+
## If You Still Have Issues
1. Verify stylua is installed: `which stylua`
2. Check version: `stylua --version`
3. Test manually: `stylua --check lua/shelbybark/core/init.lua`
4. Check for errors: `stylua -v lua/shelbybark/core/init.lua`

View File

@@ -15,77 +15,173 @@ return {
require("shelbybark.plugins.codecompanion.fidget-spinner"):init()
end,
config = function()
-- Store config in a module-level variable for later access
local codecompanion_config = {
strategies = {
chat = {
adapter = "anthropic_haiku",
},
inline = {
adapter = "anthropic_haiku",
},
},
}
_G.codecompanion_config = codecompanion_config
-- Default chat adapter used by <leader>cc (you can change this at runtime via :CodeCompanionSwitchModel)
vim.g.codecompanion_default_adapter = vim.g.codecompanion_default_adapter or "anthropic_haiku"
-- Helpers: read CodeCompanion's per-chat metadata (adapter/model) and reflect it in bufferline by renaming chat buffers.
-- CodeCompanion populates _G.codecompanion_chat_metadata and emits User events when adapter/model changes. See :h codecompanion.
local function cc_get_meta(bufnr)
local md = rawget(_G, "codecompanion_chat_metadata")
if type(md) ~= "table" then
return nil
end
return md[bufnr]
end
local function cc_label(bufnr)
local meta = cc_get_meta(bufnr)
if not (meta and meta.adapter) then
return nil
end
local a = meta.adapter
local adapter_name = a.formatted_name or a.name or "CodeCompanion"
local model = a.model or "?"
return string.format("%s • %s", adapter_name, model)
end
local function cc_update_chat_buf_name(bufnr)
local label = cc_label(bufnr)
if not label then
return
end
-- Make the name unique so multiple chats don't collide.
local meta = cc_get_meta(bufnr)
local id = (meta and meta.id) or bufnr
local name = string.format("[CC#%s %s]", id, label)
pcall(vim.api.nvim_buf_set_name, bufnr, name)
end
local function cc_update_all_chat_buf_names()
local md = rawget(_G, "codecompanion_chat_metadata")
if type(md) ~= "table" then
return
end
for bufnr, _ in pairs(md) do
bufnr = tonumber(bufnr)
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
cc_update_chat_buf_name(bufnr)
end
end
end
local cc_name_group = vim.api.nvim_create_augroup("CodeCompanionBufferNames", { clear = true })
vim.api.nvim_create_autocmd("User", {
group = cc_name_group,
pattern = {
"CodeCompanionChatCreated",
"CodeCompanionChatOpened",
"CodeCompanionChatAdapter",
"CodeCompanionChatModel",
},
callback = function(request)
local bufnr = request.buf
-- The plugin updates _G.codecompanion_chat_metadata around the same time it fires events.
-- Scheduling makes sure we read the latest metadata.
vim.schedule(function()
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
cc_update_chat_buf_name(bufnr)
end
cc_update_all_chat_buf_names()
pcall(vim.cmd, "redrawtabline")
end)
end,
})
-- Ollama defaults (works locally; set CODECOMPANION_OLLAMA_URL on other machines to use your Tailscale hostname/IP)
local ollama_model = os.getenv("CODECOMPANION_OLLAMA_MODEL") or "qwen3-coder:30b"
local ollama_url = os.getenv("CODECOMPANION_OLLAMA_URL") or "http://127.0.0.1:11434"
local ollama_api_key = os.getenv("CODECOMPANION_OLLAMA_API_KEY") -- optional
require("codecompanion").setup({
ignore_warnings = true,
strategies = {
chat = {
adapter = "anthropic_haiku",
-- Newer CodeCompanion uses `interactions` (older configs used `strategies`).
-- We set a startup default, but our keymaps below always pass adapter=... explicitly.
interactions = {
chat = { adapter = vim.g.codecompanion_default_adapter },
inline = { adapter = vim.g.codecompanion_default_adapter },
},
inline = {
adapter = "anthropic_haiku",
},
},
adapters = {
http = {
-- Claude Sonnet
anthropic = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-sonnet-4-20250514",
},
model = { default = "claude-sonnet-4-20250514" },
},
})
end,
-- Claude Opus
anthropic_opus = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-opus-4-5-20251101",
},
model = { default = "claude-opus-4-5-20251101" },
},
})
end,
-- Claude Haiku
anthropic_haiku = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-haiku-4-5-20251001",
},
model = { default = "claude-haiku-4-5-20251001" },
},
})
end,
-- Ollama (local or remote)
ollama = function()
local adapter = require("codecompanion.adapters").extend("ollama", {
env = {
url = ollama_url,
api_key = ollama_api_key,
},
-- If you don't set model=... in :CodeCompanionChat, this is what gets used.
schema = {
model = { default = ollama_model },
},
headers = {
["Content-Type"] = "application/json",
-- Only used if you set CODECOMPANION_OLLAMA_API_KEY (e.g. if you proxy Ollama behind auth)
["Authorization"] = "Bearer ${api_key}",
},
parameters = {
sync = true,
},
})
-- If no api key is set, drop Authorization so we don't send a meaningless header.
if not (ollama_api_key and ollama_api_key ~= "") then
adapter.headers = adapter.headers or {}
adapter.headers["Authorization"] = nil
end
return adapter
end,
},
},
-- Display settings for the chat window
display = {
chat = {
window = {
layout = "vertical", -- or "horizontal", "float"
},
window = { layout = "vertical" }, -- or "horizontal", "float"
show_progress = true,
show_token_count = true,
-- Consider enabling this if you also want the model/settings visible inside the chat buffer header:
-- show_settings = true,
},
-- Progress notifications using fidget
progress = {
@@ -95,51 +191,93 @@ return {
},
})
-- Optional: Set up keymaps
vim.api.nvim_set_keymap(
"n",
"<leader>cc",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>cc",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap("n", "<leader>ca", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("v", "<leader>ca", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true })
-- Update any existing chat buffer names after startup
vim.schedule(cc_update_all_chat_buf_names)
vim.api.nvim_set_keymap(
"n",
"<leader>cm",
"<cmd>CodeCompanionModel<cr>",
{ noremap = true, silent = true, desc = "Show current CodeCompanion model" }
)
-- Keymaps (updated to the newer command syntax: :CodeCompanionChat adapter=... [model=...] Toggle)
local function cc_toggle(adapter)
vim.cmd(string.format("CodeCompanionChat adapter=%s Toggle", adapter))
end
-- Create commands to show and change current model
vim.api.nvim_create_user_command("CodeCompanionModel", function()
local current_adapter = _G.codecompanion_config.strategies.chat.adapter
local model_info = "Unknown"
vim.keymap.set({ "n", "v" }, "<leader>cc", function()
cc_toggle(vim.g.codecompanion_default_adapter or "anthropic_haiku")
end, { noremap = true, silent = true, desc = "Chat with CodeCompanion (default)" })
if current_adapter == "anthropic" then
model_info = "Claude Sonnet (claude-sonnet-4-20250514)"
elseif current_adapter == "anthropic_opus" then
model_info = "Claude Opus (claude-opus-4-5-20251101)"
elseif current_adapter == "anthropic_haiku" then
model_info = "Claude Haiku (claude-haiku-4-5-20251001)"
vim.keymap.set({ "n", "v" }, "<leader>cs", function()
cc_toggle("anthropic")
end, { noremap = true, silent = true, desc = "Chat with Claude Sonnet" })
vim.keymap.set({ "n", "v" }, "<leader>co", function()
cc_toggle("anthropic_opus")
end, { noremap = true, silent = true, desc = "Chat with Claude Opus" })
vim.keymap.set({ "n", "v" }, "<leader>ch", function()
cc_toggle("anthropic_haiku")
end, { noremap = true, silent = true, desc = "Chat with Claude Haiku" })
vim.keymap.set({ "n", "v" }, "<leader>cl", function()
-- Explicitly set the model you asked for, even if CODECOMPANION_OLLAMA_MODEL isn't set.
vim.cmd("CodeCompanionChat adapter=ollama model=qwen3-coder:30b")
end, { noremap = true, silent = true, desc = "Chat with Ollama (qwen3-coder:30b)" })
vim.keymap.set({ "n", "v" }, "<leader>ca", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true })
-- Model picker (one shortcut to open a chat with a specific adapter/model)
local function cc_chat(adapter, model)
if model and model ~= "" then
vim.cmd(("CodeCompanionChat adapter=%s model=%s"):format(adapter, model))
else
vim.cmd(("CodeCompanionChat adapter=%s"):format(adapter))
end
end
vim.notify(string.format("Current CodeCompanion model: %s", model_info), vim.log.levels.INFO)
end, {
vim.keymap.set({ "n", "v" }, "<leader>cm", function()
local choices = {
{ label = "Ollama • " .. (ollama_model or "qwen3-coder:30b"), adapter = "ollama", model = (ollama_model or "qwen3-coder:30b") },
{ label = "Claude • Haiku", adapter = "anthropic_haiku", model = "claude-haiku-4-5-20251001" },
{ label = "Claude • Sonnet", adapter = "anthropic", model = "claude-sonnet-4-20250514" },
{ label = "Claude • Opus", adapter = "anthropic_opus", model = "claude-opus-4-5-20251101" },
}
vim.ui.select(choices, {
prompt = "CodeCompanion model",
format_item = function(item)
return item.label
end,
}, function(item)
if item then
cc_chat(item.adapter, item.model)
end
end)
end, { noremap = true, silent = true, desc = "CodeCompanion: Pick model" })
-- Keep an 'info' shortcut to show the current model for the active chat buffer
vim.keymap.set("n", "<leader>cM", "<cmd>CodeCompanionModel<cr>", {
noremap = true,
silent = true,
desc = "Show current CodeCompanion model",
})
-- Show model for the *current* chat buffer (if you're in one), otherwise show your default adapter.
vim.api.nvim_create_user_command("CodeCompanionModel", function()
local bufnr = vim.api.nvim_get_current_buf()
local label = cc_label(bufnr)
if label then
vim.notify(string.format("CodeCompanion (this chat): %s", label), vim.log.levels.INFO)
else
vim.notify(
string.format("CodeCompanion default adapter: %s", vim.g.codecompanion_default_adapter or "anthropic_haiku"),
vim.log.levels.INFO
)
end
end, { desc = "Show current CodeCompanion model" })
-- Switch which adapter <leader>cc uses (doesn't rewrite plugin config; it just changes your default toggle)
vim.api.nvim_create_user_command("CodeCompanionSwitchModel", function(args)
local model = args.args
if model == "" then
vim.notify("Available models: sonnet, opus, haiku", vim.log.levels.INFO)
local choice = (args.args or ""):lower()
if choice == "" then
vim.notify("Available: sonnet, opus, haiku, ollama", vim.log.levels.INFO)
return
end
@@ -147,70 +285,23 @@ return {
sonnet = "anthropic",
opus = "anthropic_opus",
haiku = "anthropic_haiku",
ollama = "ollama",
}
local adapter = adapter_map[model:lower()]
local adapter = adapter_map[choice]
if not adapter then
vim.notify("Invalid model. Use: sonnet, opus, haiku", vim.log.levels.ERROR)
vim.notify("Invalid choice. Use: sonnet, opus, haiku, ollama", vim.log.levels.ERROR)
return
end
-- Update the config
_G.codecompanion_config.strategies.chat.adapter = adapter
_G.codecompanion_config.strategies.inline.adapter = adapter
vim.notify(string.format("Switched to %s model", model), vim.log.levels.INFO)
-- Refresh lualine to update the status
-- pcall(require("lualine").refresh)
vim.g.codecompanion_default_adapter = adapter
vim.notify(string.format("CodeCompanion default adapter set to: %s", adapter), vim.log.levels.INFO)
end, {
nargs = 1,
complete = function()
return { "sonnet", "opus", "haiku" }
return { "sonnet", "opus", "haiku", "ollama" }
end,
desc = "Switch CodeCompanion model (sonnet/opus/haiku)",
desc = "Switch default CodeCompanion adapter used by <leader>cc",
})
-- Additional keymaps for Sonnet (backup primary)
vim.api.nvim_set_keymap(
"n",
"<leader>cs",
"<cmd>CodeCompanionChat anthropic Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Sonnet" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>cs",
"<cmd>CodeCompanionChat anthropic Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Sonnet" }
)
-- Additional keymaps for Opus
vim.api.nvim_set_keymap(
"n",
"<leader>co",
"<cmd>CodeCompanionChat anthropic_opus Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Opus" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>co",
"<cmd>CodeCompanionChat anthropic_opus Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Opus" }
)
-- Additional keymaps for Haiku
vim.api.nvim_set_keymap(
"n",
"<leader>ch",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>ch",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
end,
}

View File

@@ -1,77 +1,216 @@
return {
{
"olimorris/codecompanion.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
"j-hui/fidget.nvim",
},
opts = {
"olimorris/codecompanion.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
-- Optional: for enhanced diagnostics/context
"georgeharker/mcp-diagnostics.nvim",
-- For progress notifications
"j-hui/fidget.nvim",
-- For statusline integration
-- "nvim-lualine/lualine.nvim",
},
event = "VeryLazy", -- Lazy load the plugin
init = function()
require("shelbybark.plugins.codecompanion.fidget-spinner"):init()
end,
config = function()
-- Store config in a module-level variable for later access
local codecompanion_config = {
strategies = {
chat = {
adapter = "openai",
adapter = "anthropic_haiku",
},
inline = {
adapter = "openai",
adapter = "anthropic_haiku",
},
},
adapters = {},
},
config = function(_, opts)
local api_key = ""
local handle = io.popen("pass openai/api_key")
if handle then
api_key = handle:read("*a"):gsub("%s+$", "")
handle:close()
end
}
_G.codecompanion_config = codecompanion_config
opts.adapters.openai = function()
return require("codecompanion.adapters").extend("openai", {
env = {
api_key = api_key,
require("codecompanion").setup({
ignore_warnings = true,
strategies = {
chat = {
adapter = "anthropic_haiku",
},
inline = {
adapter = "anthropic_haiku",
},
},
adapters = {
http = {
anthropic = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-sonnet-4-20250514",
},
},
})
end,
anthropic_opus = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-opus-4-5-20251101",
},
},
})
end,
anthropic_haiku = function()
return require("codecompanion.adapters").extend("anthropic", {
env = {
api_key = "ANTHROPIC_API_KEY",
},
schema = {
model = {
default = "claude-haiku-4-5-20251001",
},
},
})
end,
},
},
-- Display settings for the chat window
display = {
chat = {
window = {
layout = "vertical", -- or "horizontal", "float"
},
})
show_progress = true,
show_token_count = true,
},
-- Progress notifications using fidget
progress = {
enabled = true,
provider = "fidget",
},
},
})
-- Optional: Set up keymaps
vim.api.nvim_set_keymap(
"n",
"<leader>cc",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>cc",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap("n", "<leader>ca", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("v", "<leader>ca", "<cmd>CodeCompanionActions<cr>", { noremap = true, silent = true })
vim.api.nvim_set_keymap(
"n",
"<leader>cm",
"<cmd>CodeCompanionModel<cr>",
{ noremap = true, silent = true, desc = "Show current CodeCompanion model" }
)
-- Create commands to show and change current model
vim.api.nvim_create_user_command("CodeCompanionModel", function()
local current_adapter = _G.codecompanion_config.strategies.chat.adapter
local model_info = "Unknown"
if current_adapter == "anthropic" then
model_info = "Claude Sonnet (claude-sonnet-4-20250514)"
elseif current_adapter == "anthropic_opus" then
model_info = "Claude Opus (claude-opus-4-5-20251101)"
elseif current_adapter == "anthropic_haiku" then
model_info = "Claude Haiku (claude-haiku-4-5-20251001)"
end
-- opts.adapters.openai = require("codecompanion.adapters").extend("openai", {
-- env = {
-- api_key = api_key,
-- },
-- })
require("codecompanion").setup(opts)
vim.notify(string.format("Current CodeCompanion model: %s", model_info), vim.log.levels.INFO)
end, {
desc = "Show current CodeCompanion model",
})
local progress = require("fidget.progress")
local handles = {}
local group = vim.api.nvim_create_augroup("CodeCompanionFidget", {})
vim.api.nvim_create_user_command("CodeCompanionSwitchModel", function(args)
local model = args.args
if model == "" then
vim.notify("Available models: sonnet, opus, haiku", vim.log.levels.INFO)
return
end
vim.api.nvim_create_autocmd("User", {
pattern = "CodeCompanionRequestStarted",
group = group,
callback = function(e)
handles[e.data.id] = progress.handle.create({
title = "CodeCompanion",
message = "Thinking...",
lsp_client = { name = e.data.adapter.formatted_name },
})
end,
})
local adapter_map = {
sonnet = "anthropic",
opus = "anthropic_opus",
haiku = "anthropic_haiku",
}
vim.api.nvim_create_autocmd("User", {
pattern = "CodeCompanionRequestFinished",
group = group,
callback = function(e)
local h = handles[e.data.id]
if h then
h.message = e.data.status == "success" and "Done" or "Failed"
h:finish()
handles[e.data.id] = nil
end
end,
})
end,
},
{
"MeanderingProgrammer/render-markdown.nvim",
ft = { "markdown", "codecompanion" },
},
local adapter = adapter_map[model:lower()]
if not adapter then
vim.notify("Invalid model. Use: sonnet, opus, haiku", vim.log.levels.ERROR)
return
end
-- Update the config
_G.codecompanion_config.strategies.chat.adapter = adapter
_G.codecompanion_config.strategies.inline.adapter = adapter
vim.notify(string.format("Switched to %s model", model), vim.log.levels.INFO)
-- Refresh lualine to update the status
-- pcall(require("lualine").refresh)
end, {
nargs = 1,
complete = function()
return { "sonnet", "opus", "haiku" }
end,
desc = "Switch CodeCompanion model (sonnet/opus/haiku)",
})
-- Additional keymaps for Sonnet (backup primary)
vim.api.nvim_set_keymap(
"n",
"<leader>cs",
"<cmd>CodeCompanionChat anthropic Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Sonnet" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>cs",
"<cmd>CodeCompanionChat anthropic Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Sonnet" }
)
-- Additional keymaps for Opus
vim.api.nvim_set_keymap(
"n",
"<leader>co",
"<cmd>CodeCompanionChat anthropic_opus Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Opus" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>co",
"<cmd>CodeCompanionChat anthropic_opus Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Opus" }
)
-- Additional keymaps for Haiku
vim.api.nvim_set_keymap(
"n",
"<leader>ch",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
vim.api.nvim_set_keymap(
"v",
"<leader>ch",
"<cmd>CodeCompanionChat anthropic_haiku Toggle<cr>",
{ noremap = true, silent = true, desc = "Chat with Claude Haiku" }
)
end,
}