feat: adding multiple files
### Added
- **Smart Scope Resolution** — Tree-sitter + indentation context for
selections
- `resolve_selection_context()` in `scope/init.lua` handles partial
functions,
whole functions, multi-function spans, indent blocks, and whole-file
selections
- Enclosing function automatically sent as context when selecting code
inside one
- Whole-file selection (>=80% of lines) triggers project tree as
context
- Indentation-based fallback when Tree-sitter is unavailable
- **Explain-to-Document Intent** — "explain" prompts generate
documentation
- Detects prompts like "explain this", "tell me about", "what does",
"question"
- Generates documentation comments and inserts them above selected
code
- Shows notification if nothing is selected
- Updated intent action from "none" to "insert" for explain intent
- **Granular LLM Status Notifications** — Real-time progress reporting
- Inline virtual text and floating status window show current stage
- Stages: "Reading context...", "Searching index...", "Gathering
context...",
"Recalling patterns...", "Building prompt...", "Sending to
[provider]...",
"Processing response...", "Generating patch...", "Applying code..."
- `update_inline_status()` in `thinking_placeholder.lua`
- `update_stage()` in `thinking.lua`
- **Thinking Placeholder Positioning** — "Implementing..." appears above
selection
- Uses `virt_lines_above = true` on extmark at selection start line
- Dynamic status text updates during LLM processing
### Changed
- **Providers reduced to Copilot and Ollama only**
- Removed Claude, OpenAI, and Gemini provider integrations
- Deleted `llm/openai.lua` and `llm/gemini.lua`
- Cleaned `llm/init.lua`, `config/defaults.lua`, `types.lua`,
`credentials.lua`,
`cost/init.lua`, and `events/queue.lua` of all references
- `valid_providers` now only includes "copilot" and "ollama"
- **Removed timer-based delayed processing** — Prompts are processed
instantly
- Removed `timer` field, `timeout_ms`, and timer setup/cancellation
from `worker.lua`
- **Removed chat/agent/split window UI**
- Deleted `ui/chat.lua`, `windows.lua`, `ui/switcher.lua`
- Removed `CoderOpen`, `CoderClose`, `CoderToggle` commands
- Removed window management from `autocmds.lua`, `inject.lua`,
`executor.lua`
- Removed auto-open companion file logic
- **Commands removed from menu** (code retained with TODOs for
re-enabling)
- `CoderAddApiKey`, `CoderRemoveApiKey`, `CoderBrain`,
`CoderFeedback`,
`CoderMemories`, `CoderForget`, `CoderProcess`
- Subcommands `process`, `status`, `memories`, `forget`,
`llm-feedback-good`,
`llm-feedback-bad`, `add-api-key`, `remove-api-key` removed from
completion
### Fixed
- Fixed `patch.lua` syntax error — missing `if` wrapper around
SEARCH/REPLACE block
- Fixed `CoderModel` require path typo
(`codetyper.adapters.config.credentials`
→ `codetyper.config.credentials`)
- Fixed `thinking_placeholder` extmark placement appearing after
selection
instead of above it
This commit is contained in:
@@ -65,7 +65,7 @@ function M.save(data)
|
||||
end
|
||||
|
||||
--- Get API key for a provider
|
||||
---@param provider string Provider name (claude, openai, gemini, copilot, ollama)
|
||||
---@param provider string Provider name (copilot, ollama)
|
||||
---@return string|nil API key or nil if not found
|
||||
function M.get_api_key(provider)
|
||||
local data = M.load()
|
||||
@@ -167,14 +167,13 @@ function M.list_providers()
|
||||
local data = M.load()
|
||||
local result = {}
|
||||
|
||||
local all_providers = { "claude", "openai", "gemini", "copilot", "ollama" }
|
||||
local all_providers = { "copilot", "ollama" }
|
||||
|
||||
for _, provider in ipairs(all_providers) do
|
||||
local provider_data = data.providers and data.providers[provider]
|
||||
local has_stored_key = provider_data and provider_data.api_key and provider_data.api_key ~= ""
|
||||
local has_model = provider_data and provider_data.model and provider_data.model ~= ""
|
||||
|
||||
-- Check if configured from config or environment
|
||||
local configured_from_config = false
|
||||
local config_model = nil
|
||||
local ok, codetyper = pcall(require, "codetyper")
|
||||
@@ -184,14 +183,8 @@ function M.list_providers()
|
||||
local pc = config.llm[provider]
|
||||
config_model = pc.model
|
||||
|
||||
if provider == "claude" then
|
||||
configured_from_config = pc.api_key ~= nil or vim.env.ANTHROPIC_API_KEY ~= nil
|
||||
elseif provider == "openai" then
|
||||
configured_from_config = pc.api_key ~= nil or vim.env.OPENAI_API_KEY ~= nil
|
||||
elseif provider == "gemini" then
|
||||
configured_from_config = pc.api_key ~= nil or vim.env.GEMINI_API_KEY ~= nil
|
||||
elseif provider == "copilot" then
|
||||
configured_from_config = true -- Just needs copilot.lua
|
||||
if provider == "copilot" then
|
||||
configured_from_config = true
|
||||
elseif provider == "ollama" then
|
||||
configured_from_config = pc.host ~= nil
|
||||
end
|
||||
@@ -218,9 +211,6 @@ end
|
||||
|
||||
--- Default models for each provider
|
||||
M.default_models = {
|
||||
claude = "claude-sonnet-4-20250514",
|
||||
openai = "gpt-4o",
|
||||
gemini = "gemini-2.0-flash",
|
||||
copilot = "claude-sonnet-4",
|
||||
ollama = "deepseek-coder:6.7b",
|
||||
}
|
||||
@@ -276,18 +266,17 @@ function M.get_copilot_model_cost(model_name)
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Interactive command to add/update API key
|
||||
--- Interactive command to add/update configuration
|
||||
function M.interactive_add()
|
||||
local providers = { "claude", "openai", "gemini", "copilot", "ollama" }
|
||||
local providers = { "copilot", "ollama" }
|
||||
|
||||
-- Step 1: Select provider
|
||||
vim.ui.select(providers, {
|
||||
prompt = "Select LLM provider:",
|
||||
format_item = function(item)
|
||||
local display = item:sub(1, 1):upper() .. item:sub(2)
|
||||
local creds = M.load()
|
||||
local configured = creds.providers and creds.providers[item]
|
||||
if configured and (configured.api_key or item == "ollama") then
|
||||
if configured and (configured.configured or item == "ollama") then
|
||||
return display .. " [configured]"
|
||||
end
|
||||
return display
|
||||
@@ -297,36 +286,14 @@ function M.interactive_add()
|
||||
return
|
||||
end
|
||||
|
||||
-- Step 2: Get API key (skip for Ollama)
|
||||
if provider == "ollama" then
|
||||
M.interactive_ollama_config()
|
||||
else
|
||||
M.interactive_api_key(provider)
|
||||
elseif provider == "copilot" then
|
||||
M.interactive_copilot_config()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Interactive API key input
|
||||
---@param provider string Provider name
|
||||
function M.interactive_api_key(provider)
|
||||
-- Copilot uses OAuth from copilot.lua, no API key needed
|
||||
if provider == "copilot" then
|
||||
M.interactive_copilot_config()
|
||||
return
|
||||
end
|
||||
|
||||
local prompt = string.format("Enter %s API key (leave empty to skip): ", provider:upper())
|
||||
|
||||
vim.ui.input({ prompt = prompt }, function(api_key)
|
||||
if api_key == nil then
|
||||
return -- Cancelled
|
||||
end
|
||||
|
||||
-- Step 3: Get model
|
||||
M.interactive_model(provider, api_key)
|
||||
end)
|
||||
end
|
||||
|
||||
--- Interactive Copilot configuration (no API key, uses OAuth)
|
||||
---@param silent? boolean If true, don't show the OAuth info message
|
||||
function M.interactive_copilot_config(silent)
|
||||
@@ -381,60 +348,6 @@ function M.interactive_copilot_config(silent)
|
||||
end)
|
||||
end
|
||||
|
||||
--- Interactive model selection
|
||||
---@param provider string Provider name
|
||||
---@param api_key string|nil API key
|
||||
function M.interactive_model(provider, api_key)
|
||||
local default_model = M.default_models[provider] or ""
|
||||
local prompt = string.format("Enter model (default: %s): ", default_model)
|
||||
|
||||
vim.ui.input({ prompt = prompt, default = default_model }, function(model)
|
||||
if model == nil then
|
||||
return -- Cancelled
|
||||
end
|
||||
|
||||
-- Use default if empty
|
||||
if model == "" then
|
||||
model = default_model
|
||||
end
|
||||
|
||||
-- Save credentials
|
||||
local credentials = {
|
||||
model = model,
|
||||
}
|
||||
|
||||
if api_key and api_key ~= "" then
|
||||
credentials.api_key = api_key
|
||||
end
|
||||
|
||||
-- For OpenAI, also ask for custom endpoint
|
||||
if provider == "openai" then
|
||||
M.interactive_endpoint(provider, credentials)
|
||||
else
|
||||
M.save_and_notify(provider, credentials)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
--- Interactive endpoint input for OpenAI-compatible providers
|
||||
---@param provider string Provider name
|
||||
---@param credentials table Current credentials
|
||||
function M.interactive_endpoint(provider, credentials)
|
||||
vim.ui.input({
|
||||
prompt = "Custom endpoint (leave empty for default OpenAI): ",
|
||||
}, function(endpoint)
|
||||
if endpoint == nil then
|
||||
return -- Cancelled
|
||||
end
|
||||
|
||||
if endpoint ~= "" then
|
||||
credentials.endpoint = endpoint
|
||||
end
|
||||
|
||||
M.save_and_notify(provider, credentials)
|
||||
end)
|
||||
end
|
||||
|
||||
--- Interactive Ollama configuration
|
||||
function M.interactive_ollama_config()
|
||||
vim.ui.input({
|
||||
@@ -589,16 +502,14 @@ end
|
||||
---@param provider string Provider name
|
||||
---@return boolean configured, string|nil source
|
||||
local function is_provider_configured(provider)
|
||||
-- Check stored credentials first
|
||||
local data = M.load()
|
||||
local stored = data.providers and data.providers[provider]
|
||||
if stored then
|
||||
if stored.configured or stored.api_key or provider == "ollama" or provider == "copilot" then
|
||||
if stored.configured or provider == "ollama" or provider == "copilot" then
|
||||
return true, "stored"
|
||||
end
|
||||
end
|
||||
|
||||
-- Check codetyper config
|
||||
local ok, codetyper = pcall(require, "codetyper")
|
||||
if not ok then
|
||||
return false, nil
|
||||
@@ -614,24 +525,9 @@ local function is_provider_configured(provider)
|
||||
return false, nil
|
||||
end
|
||||
|
||||
-- Check for API key in config or environment
|
||||
if provider == "claude" then
|
||||
if provider_config.api_key or vim.env.ANTHROPIC_API_KEY then
|
||||
return true, "config"
|
||||
end
|
||||
elseif provider == "openai" then
|
||||
if provider_config.api_key or vim.env.OPENAI_API_KEY then
|
||||
return true, "config"
|
||||
end
|
||||
elseif provider == "gemini" then
|
||||
if provider_config.api_key or vim.env.GEMINI_API_KEY then
|
||||
return true, "config"
|
||||
end
|
||||
elseif provider == "copilot" then
|
||||
-- Copilot just needs copilot.lua installed
|
||||
if provider == "copilot" then
|
||||
return true, "config"
|
||||
elseif provider == "ollama" then
|
||||
-- Ollama just needs host configured
|
||||
if provider_config.host then
|
||||
return true, "config"
|
||||
end
|
||||
@@ -642,7 +538,7 @@ end
|
||||
|
||||
--- Interactive switch provider
|
||||
function M.interactive_switch_provider()
|
||||
local all_providers = { "claude", "openai", "gemini", "copilot", "ollama" }
|
||||
local all_providers = { "copilot", "ollama" }
|
||||
local available = {}
|
||||
local sources = {}
|
||||
|
||||
|
||||
@@ -5,20 +5,11 @@ local M = {}
|
||||
---@type CoderConfig
|
||||
local defaults = {
|
||||
llm = {
|
||||
provider = "ollama", -- Options: "ollama", "openai", "gemini", "copilot"
|
||||
provider = "ollama", -- Options: "ollama", "copilot"
|
||||
ollama = {
|
||||
host = "http://localhost:11434",
|
||||
model = "deepseek-coder:6.7b",
|
||||
},
|
||||
openai = {
|
||||
api_key = nil, -- Will use OPENAI_API_KEY env var if nil
|
||||
model = "gpt-4o",
|
||||
endpoint = nil, -- Custom endpoint (Azure, OpenRouter, etc.)
|
||||
},
|
||||
gemini = {
|
||||
api_key = nil, -- Will use GEMINI_API_KEY env var if nil
|
||||
model = "gemini-2.0-flash",
|
||||
},
|
||||
copilot = {
|
||||
model = "claude-sonnet-4", -- Uses GitHub Copilot authentication
|
||||
},
|
||||
@@ -95,7 +86,7 @@ function M.validate(config)
|
||||
return false, "Missing LLM configuration"
|
||||
end
|
||||
|
||||
local valid_providers = { "ollama", "openai", "gemini", "copilot" }
|
||||
local valid_providers = { "ollama", "copilot" }
|
||||
local is_valid_provider = false
|
||||
for _, p in ipairs(valid_providers) do
|
||||
if config.llm.provider == p then
|
||||
@@ -108,21 +99,6 @@ function M.validate(config)
|
||||
return false, "Invalid LLM provider. Must be one of: " .. table.concat(valid_providers, ", ")
|
||||
end
|
||||
|
||||
-- Validate provider-specific configuration
|
||||
if config.llm.provider == "openai" then
|
||||
local api_key = config.llm.openai.api_key or vim.env.OPENAI_API_KEY
|
||||
if not api_key or api_key == "" then
|
||||
return false, "OpenAI API key not configured. Set llm.openai.api_key or OPENAI_API_KEY env var"
|
||||
end
|
||||
elseif config.llm.provider == "gemini" then
|
||||
local api_key = config.llm.gemini.api_key or vim.env.GEMINI_API_KEY
|
||||
if not api_key or api_key == "" then
|
||||
return false, "Gemini API key not configured. Set llm.gemini.api_key or GEMINI_API_KEY env var"
|
||||
end
|
||||
end
|
||||
-- Note: copilot uses OAuth from copilot.lua/copilot.vim, validated at runtime
|
||||
-- Note: ollama doesn't require API key, just host configuration
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user