From a750dc845ebdcfb51704a8dd15acc04b7d6b7624 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 25 Sep 2025 06:16:40 -0400 Subject: [PATCH 01/48] wip: context bar --- README.md | 14 ++ lua/opencode/config.lua | 4 + lua/opencode/context.lua | 154 +++++++----- lua/opencode/reactive_state.lua | 140 +++++++++++ lua/opencode/state.lua | 18 +- lua/opencode/types.lua | 31 ++- lua/opencode/ui/autocmds.lua | 18 +- lua/opencode/ui/completion.lua | 2 + lua/opencode/ui/completion/context.lua | 223 ++++++++++++++++++ .../ui/completion/engines/blink_cmp.lua | 1 + .../ui/completion/engines/nvim_cmp.lua | 5 +- .../ui/completion/engines/vim_complete.lua | 8 +- lua/opencode/ui/completion/subagents.lua | 2 + lua/opencode/ui/context_bar.lua | 188 +++++++++++++++ lua/opencode/ui/icons.lua | 28 ++- lua/opencode/ui/input_window.lua | 68 ++++++ lua/opencode/ui/mention.lua | 1 + lua/opencode/ui/output_window.lua | 1 + lua/opencode/ui/ui.lua | 4 +- lua/opencode/util.lua | 6 +- 20 files changed, 835 insertions(+), 81 deletions(-) create mode 100644 lua/opencode/reactive_state.lua create mode 100644 lua/opencode/ui/completion/context.lua create mode 100644 lua/opencode/ui/context_bar.lua diff --git a/README.md b/README.md index cc9dae96..43b68960 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,8 @@ require('opencode').setup({ ['~'] = { 'mention_file', mode = 'i' }, -- Pick a file and add to context. See File Mentions section ['@'] = { 'mention', mode = 'i' }, -- Insert mention (file/agent) ['/'] = { 'slash_commands', mode = 'i' }, -- Pick a command to run in the input window + ['#'] = { 'context_items', mode = 'i' }, -- Manage context items (current file, selection, diagnostics, mentioned files) + [''] = { 'focus_input', mode = { 'n', 'i' } }, -- Focus on input window and enter insert mode at the end of the input from the output window [''] = { 'toggle_pane', mode = { 'n', 'i' } }, -- Toggle between input and output panes [''] = { 'prev_prompt_history', mode = { 'n', 'i' } }, -- Navigate to previous prompt in history [''] = { 'next_prompt_history', mode = { 'n', 'i' } }, -- Navigate to next prompt in history @@ -425,6 +427,18 @@ The following editor context is automatically captured and included in your conv You can reference files in your project directly in your conversations with Opencode. This is useful when you want to ask about or provide context about specific files. Type `@` in the input window to trigger the file picker. Supported pickers include [`fzf-lua`](https://github.com/ibhagwan/fzf-lua), [`telescope`](https://github.com/nvim-telescope/telescope.nvim), [`mini.pick`](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-pick.md), [`snacks`](https://github.com/folke/snacks.nvim/blob/main/docs/picker.md) +### Context Items Completion + +You can quickly reference available context items by typing `#` in the input window. This will show a completion menu with all available context items: + +- **Current File** - The currently focused file in the editor +- **Selection** - Currently selected text in visual mode +- **Diagnostics** - LSP diagnostics from the current file +- **Cursor Data** - Current cursor position and line content +- **[filename]** - Files that have been mentioned in the conversation + +Context items that are not currently available will be shown as disabled in the completion menu. + ## ๐Ÿ”„ Agents Opencode provides two built-in agents and supports custom ones: diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index d80b8468..7d0d9435 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -148,6 +148,7 @@ M.defaults = { enabled = false, }, diagnostics = { + enabled = false, info = false, warning = true, error = true, @@ -163,6 +164,9 @@ M.defaults = { selection = { enabled = true, }, + agents = { + enabled = true, + }, }, debug = { enabled = false, diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 214ab0cb..0cd7530a 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -13,27 +13,34 @@ M.context = { -- attachments mentioned_files = nil, - mentioned_files_content = nil, - selections = nil, - linter_errors = nil, - mentioned_subagents = nil, + selections = {}, + linter_errors = {}, + mentioned_subagents = {}, } function M.unload_attachments() M.context.mentioned_files = nil - M.context.mentioned_files_content = nil M.context.selections = nil M.context.linter_errors = nil end +function M.get_current_buf() + local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf() + if util.is_buf_a_file(curr_buf) then + return curr_buf, state.last_code_win_before_opencode or vim.api.nvim_get_current_win() + end +end + function M.load() - if util.is_current_buf_a_file() then - local current_file = M.get_current_file() - local cursor_data = M.get_current_cursor_data() + local buf, win = M.get_current_buf() + + if buf then + local current_file = M.get_current_file(buf) + local cursor_data = M.get_current_cursor_data(buf, win) M.context.current_file = current_file M.context.cursor_data = cursor_data - M.context.linter_errors = M.check_linter_errors() + M.context.linter_errors = M.get_diagnostics(buf) end local current_selection = M.get_current_selection() @@ -41,13 +48,23 @@ function M.load() local selection = M.new_selection(M.context.current_file, current_selection.text, current_selection.lines) M.add_selection(selection) end + state.context_updated_at = vim.uv.now() end -function M.check_linter_errors() - local diagnostic_conf = config.context and config.context.diagnostics - if not diagnostic_conf then +function M.is_context_enabled(context_key) + local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled') + local is_state_enabled = vim.tbl_get(state, 'current_context_config', context_key, 'enabled') + + return is_state_enabled ~= nil and is_state_enabled or is_enabled +end + +function M.get_diagnostics(buf) + if not M.is_context_enabled('diagnostics') then return nil end + + local diagnostic_conf = config.context and state.current_context_config.diagnostics or config.context.diagnostics + local severity_levels = {} if diagnostic_conf.error then table.insert(severity_levels, vim.diagnostic.severity.ERROR) @@ -59,20 +76,12 @@ function M.check_linter_errors() table.insert(severity_levels, vim.diagnostic.severity.INFO) end - local diagnostics = vim.diagnostic.get(0, { severity = severity_levels }) + local diagnostics = vim.diagnostic.get(buf, { severity = severity_levels }) if #diagnostics == 0 then - return nil - end - - local lines = { 'Found ' .. #diagnostics .. ' error' .. (#diagnostics > 1 and 's' or '') .. ':' } - - for _, diagnostic in ipairs(diagnostics) do - local line_number = diagnostic.lnum + 1 - local short_message = diagnostic.message:gsub('%s+', ' '):gsub('^%s', ''):gsub('%s$', '') - table.insert(lines, string.format(' Line %d: %s', line_number, short_message)) + return {} end - return table.concat(lines, '\n') + return diagnostics end function M.new_selection(file, content, lines) @@ -89,6 +98,8 @@ function M.add_selection(selection) end table.insert(M.context.selections, selection) + + state.context_updated_at = vim.uv.now() end function M.add_file(file) @@ -113,9 +124,19 @@ function M.add_file(file) end end -M.clear_files = function() - M.context.mentioned_files = nil - M.context.mentioned_files_content = nil +function M.remove_file(file) + file = vim.fn.fnamemodify(file, ':p') + if not M.context.mentioned_files then + return + end + + for i, f in ipairs(M.context.mentioned_files) do + if f == file then + table.remove(M.context.mentioned_files, i) + break + end + end + state.context_updated_at = vim.uv.now() end function M.add_subagent(subagent) @@ -126,13 +147,24 @@ function M.add_subagent(subagent) if not vim.tbl_contains(M.context.mentioned_subagents, subagent) then table.insert(M.context.mentioned_subagents, subagent) end + state.context_updated_at = vim.uv.now() end -M.clear_subagents = function() - M.context.mentioned_subagents = nil +function M.remove_subagent(subagent) + if not M.context.mentioned_subagents then + return + end + + for i, a in ipairs(M.context.mentioned_subagents) do + if a == subagent then + table.remove(M.context.mentioned_subagents, i) + break + end + end + state.context_updated_at = vim.uv.now() end ----@param opts OpencodeContextConfig +---@param opts? OpencodeContextConfig function M.delta_context(opts) opts = opts or config.context if opts.enabled == false then @@ -173,18 +205,11 @@ function M.delta_context(opts) return context end -function M.get_current_file() - if - not ( - config.context - and config.context.enabled - and config.context.current_file - and config.context.current_file.enabled - ) - then +function M.get_current_file(buf) + if not M.is_context_enabled('current_file') then return nil end - local file = vim.fn.expand('%:p') + local file = vim.api.nvim_buf_get_name(buf) if not file or file == '' or vim.fn.filereadable(file) ~= 1 then return nil end @@ -195,29 +220,21 @@ function M.get_current_file() } end -function M.get_current_cursor_data() - if - not ( - config.context - and config.context.enabled - and config.context.cursor_data - and config.context.cursor_data.enabled - ) - then +function M.get_current_cursor_data(buf, win) + if not M.is_context_enabled('cursor_data') then return nil end - local cursor_pos = vim.fn.getcurpos() - local cursor_content = vim.trim(vim.api.nvim_get_current_line()) + local cursor_pos = vim.fn.getcurpos(win) + local cursor_content = vim.trim(vim.api.nvim_buf_get_lines(buf, cursor_pos[2] - 1, cursor_pos[2], false)[1] or '') return { line = cursor_pos[2], col = cursor_pos[3], line_content = cursor_content } end function M.get_current_selection() - if - not (config.context and config.context.enabled and config.context.selection and config.context.selection.enabled) - then + if not M.is_context_enabled('selection') then return nil end + -- Return nil if not in a visual mode if not vim.fn.mode():match('[vV\022]') then return nil @@ -411,8 +428,6 @@ function M.extract_legacy_tag(tag, text) local start_tag = '<' .. tag .. '>' local end_tag = '' - -- Use pattern matching to find the content between the tags - -- Make search start_tag and end_tag more robust with pattern escaping local pattern = vim.pesc(start_tag) .. '(.-)' .. vim.pesc(end_tag) local content = text:match(pattern) @@ -425,7 +440,6 @@ function M.extract_legacy_tag(tag, text) local query_end = text:find(end_tag) if query_start and query_end then - -- Extract and trim the content between the tags local query_content = text:sub(query_start + #start_tag, query_end - 1) return vim.trim(query_content) end @@ -433,4 +447,32 @@ function M.extract_legacy_tag(tag, text) return nil end +function M.setup() + state.subscribe({ 'current_code_buf', 'current_context_config', 'opencode_focused' }, function() + M.load() + end) + + vim.api.nvim_create_autocmd('BufWritePost', { + pattern = '*', + callback = function(args) + local buf = args.buf + local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf() + if buf == curr_buf and util.is_buf_a_file(buf) then + M.load() + end + end, + }) + + vim.api.nvim_create_autocmd('DiagnosticChanged', { + pattern = '*', + callback = function(args) + local buf = args.buf + local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf() + if buf == curr_buf and util.is_buf_a_file(buf) and M.is_context_enabled('diagnostics') then + M.load() + end + end, + }) +end + return M diff --git a/lua/opencode/reactive_state.lua b/lua/opencode/reactive_state.lua new file mode 100644 index 00000000..df1a02b6 --- /dev/null +++ b/lua/opencode/reactive_state.lua @@ -0,0 +1,140 @@ +local M = {} + +local function shallow_copy(obj) + if type(obj) ~= 'table' then + return obj + end + + local copy = {} + for key, value in pairs(obj) do + copy[key] = value + end + return copy +end + +local function merge_array(t1, t2) + local result = shallow_copy(t1 or {}) + return vim.list_extend(result, t2 or {}) +end + +local function update_path(obj, path_parts, value) + if #path_parts == 0 then + return value + end + + local key = path_parts[1] + local rest = vim.list_slice(path_parts, 2) + + local new_obj = shallow_copy(obj) + + new_obj[key] = update_path(new_obj[key] or {}, rest, value) + + return new_obj +end + +---@generic T +--- Create a new reactive state manager +---@param initial_state T Initial state +---@return table state manager with set, watch, and get methods +function M.create(initial_state) + initial_state = initial_state or {} + + local _state = shallow_copy(initial_state) + + ---@type table + local _listeners = {} + + local function split_path(path) + return type(path) == 'string' and vim.split(path, '.', { plain = true }) or path + end + + local function get_by_path(obj, path) + path = split_path(path) + + local current = obj + for _, key in ipairs(path) do + if type(current) ~= 'table' then + return nil + end + current = current[key] + end + return current + end + + local function notify(path, new_val, old_val) + local listeners = merge_array(_listeners[path], _listeners['*']) + for _, cb in ipairs(listeners) do + pcall(cb, path, new_val, old_val) + end + end + + local state_manager = {} + + --- Set state value at path or using producer function + ---@generic T + ---@param path_or_producer string|fun(draft:T):T|nil Path to set or producer function + ---@param value any + function state_manager.set(path_or_producer, value) + if type(path_or_producer) == 'function' then + local producer = path_or_producer + local draft = shallow_copy(_state) + + local result = producer(draft) + local new_state = result or draft + + local old_state = _state + _state = shallow_copy(new_state) + + local all_keys = merge_array(vim.tbl_keys(old_state), vim.tbl_keys(_state)) + + for _, k in ipairs(all_keys) do + local old_val = old_state[k] + local new_val = _state[k] + if old_val ~= new_val then + notify(k, new_val, old_val) + end + end + else + local path = path_or_producer + local path_parts = split_path(path) + local old_val = get_by_path(_state, path_parts) + + if old_val ~= value then + _state = update_path(_state, path_parts, value) + notify(path, value, old_val) + end + end + end + + --- Watch for changes to a specific path or all changes + ---@param path string|nil Path to watch, or nil/'*' for all changes + ---@param callback fun(path:string, new_val:any, old_val:any) + ---@return fun() unsubscribe function + function state_manager.watch(path, callback) + path = path or '*' + + _listeners[path] = _listeners[path] or {} + table.insert(_listeners[path], callback) + + local unsub = function() + _listeners[path] = vim.tbl_filter(function(cb) + return cb ~= callback + end, _listeners[path] or {}) + end + return unsub + end + + --- Get current state or value at path + ---@param path string|nil Path to get, or nil for entire state + ---@return any + function state_manager.get(path) + if path == nil or path == '' then + return shallow_copy(_state) + end + return get_by_path(_state, path) + end + + return state_manager +end + +return M diff --git a/lua/opencode/state.lua b/lua/opencode/state.lua index 9b934a83..0420bae7 100644 --- a/lua/opencode/state.lua +++ b/lua/opencode/state.lua @@ -16,10 +16,13 @@ local config = require('opencode.config') ---@field last_input_window_position number|nil ---@field last_output_window_position number|nil ---@field last_code_win_before_opencode number|nil +---@field current_code_buf number|nil ---@field display_route any|nil ---@field current_mode string ---@field last_output number ----@field last_sent_context any +---@field last_sent_context OpencodeContext|nil +---@field current_context_config OpencodeContextConfig|nil +---@field context_updated_at number|nil ---@field active_session Session|nil ---@field restore_points RestorePoint[] ---@field current_model string|nil @@ -39,6 +42,8 @@ local config = require('opencode.config') ---@field append fun( key:string, value:any) ---@field remove fun( key:string, idx:number) ---@field subscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any)) +---@field opencode_server_job OpencodeServer +---@field subscribe fun( key:string|string[]|nil, cb:fun(key:string, new_val:any, old_val:any)) ---@field unsubscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any)) ---@field is_running fun():boolean @@ -52,11 +57,14 @@ local _state = { last_input_window_position = nil, last_output_window_position = nil, last_code_win_before_opencode = nil, + current_code_buf = nil, display_route = nil, current_mode = nil, last_output = 0, -- context last_sent_context = nil, + current_context_config = {}, + context_updated_at = nil, -- session active_session = nil, restore_points = {}, @@ -84,12 +92,18 @@ local _state = { local _listeners = {} --- Subscribe to changes for a key (or all keys with '*'). ----@param key string|nil If nil or '*', listens to all keys +---@param key string|string[]|nil If nil or '*', listens to all keys ---@param cb fun(key:string, new_val:any, old_val:any) ---@usage --- state.subscribe('foo', function(key, new, old) ... end) --- state.subscribe('*', function(key, new, old) ... end) local function subscribe(key, cb) + if type(key) == 'table' then + for _, k in ipairs(key) do + subscribe(k, cb) + end + return + end key = key or '*' if not _listeners[key] then _listeners[key] = {} diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index a4cbfcfe..983d2607 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -66,6 +66,28 @@ ---@field accept_all string ---@field deny string +<<<<<<< HEAD +======= +---@class OpencodeKeymapWindow +---@field submit string +---@field submit_insert string +---@field close string +---@field stop string +---@field next_message string +---@field prev_message string +---@field mention_file string # mention files with a file picker +---@field mention string # mention subagents or files with a completion popup +---@field slash_commands string +---@field context_items string # select context items with a completion popup +---@field toggle_pane string +---@field prev_prompt_history string +---@field next_prompt_history string +---@field focus_input string +---@field debug_message string +---@field debug_output string +---@field switch_mode string +---@field select_child_session string +>>>>>>> 31b9b62 (wip: context bar) ---@class OpencodeKeymap ---@field editor OpencodeKeymapEditor ---@field input_window OpencodeKeymapInputWindow @@ -118,9 +140,15 @@ ---@class OpencodeContextConfig ---@field enabled boolean ---@field cursor_data { enabled: boolean } +<<<<<<< HEAD ---@field diagnostics { info: boolean, warning: boolean, error: boolean } ---@field current_file { enabled: boolean, show_full_path: boolean } +======= +---@field diagnostics { enabled:boolean, info: boolean, warning: boolean, error: boolean } +---@field current_file { enabled: boolean } +>>>>>>> 31b9b62 (wip: context bar) ---@field selection { enabled: boolean } +---@field subagents { enabled: boolean } ---@class OpencodeDebugConfig ---@field enabled boolean @@ -296,6 +324,7 @@ ---@class CompletionItem ---@field label string Display text for the completion item ---@field kind string Type of completion item (e.g., 'file', 'subagent') +---@field kind_icon string Icon representing the kind ---@field detail string Additional detail text ---@field documentation string Documentation text ---@field insert_text string Text to insert when selected @@ -314,7 +343,7 @@ ---@field mentioned_files string[]|nil ---@field mentioned_subagents string[]|nil ---@field selections OpencodeContextSelection[]|nil ----@field linter_errors string|nil +---@field linter_errors vim.Diagnostic[]|nil ---@class OpencodeContextSelection ---@field file OpencodeContextFile diff --git a/lua/opencode/ui/autocmds.lua b/lua/opencode/ui/autocmds.lua index f71bb049..d6a72912 100644 --- a/lua/opencode/ui/autocmds.lua +++ b/lua/opencode/ui/autocmds.lua @@ -22,21 +22,15 @@ function M.setup_autocmds(windows) end, }) - vim.api.nvim_create_autocmd('WinLeave', { + vim.api.nvim_create_autocmd({ 'BufWinEnter', 'BufFilePost', 'WinLeave' }, { group = group, pattern = '*', - callback = function(e) - if not require('opencode.ui.ui').is_opencode_focused() then - require('opencode.context').load() - require('opencode.state').last_code_win_before_opencode = vim.api.nvim_get_current_win() - else - local pos = vim.api.nvim_win_get_cursor(0) - if windows.input_win and vim.api.nvim_get_current_win() == windows.input_win then - require('opencode.state').last_input_window_position = pos - elseif windows.output_win and vim.api.nvim_get_current_win() == windows.output_win then - require('opencode.state').last_output_window_position = pos - end + callback = function(args) + if args.file == '' then + return end + state.last_code_win_before_opencode = vim.api.nvim_get_current_win() + state.current_code_buf = vim.api.nvim_get_current_buf() end, }) diff --git a/lua/opencode/ui/completion.lua b/lua/opencode/ui/completion.lua index cdab9b2d..2c589345 100644 --- a/lua/opencode/ui/completion.lua +++ b/lua/opencode/ui/completion.lua @@ -6,10 +6,12 @@ function M.setup() local files_source = require('opencode.ui.completion.files') local subagents_source = require('opencode.ui.completion.subagents') local commands_source = require('opencode.ui.completion.commands') + local context_source = require('opencode.ui.completion.context') M.register_source(files_source.get_source()) M.register_source(subagents_source.get_source()) M.register_source(commands_source.get_source()) + M.register_source(context_source.get_source()) table.sort(completion_sources, function(a, b) return (a.priority or 0) > (b.priority or 0) diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua new file mode 100644 index 00000000..f4150b6a --- /dev/null +++ b/lua/opencode/ui/completion/context.lua @@ -0,0 +1,223 @@ +local config = require('opencode.config').get() +local context = require('opencode.context') +local state = require('opencode.state') +local icons = require('opencode.ui.icons') + +local M = {} + +---@param name string +---@param type string +---@param available boolean +---@param documentation string|nil +---@param icon string|nil +---@return CompletionItem +local function create_context_item(name, type, available, documentation, icon) + local label = name + + return { + label = label, + kind = 'context', + kind_icon = icon or (available and '๏ˆ… ' or '๏ˆ„ '), + detail = name, + documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'), + insert_text = '', + source_name = 'context', + data = { type = type, name = name, available = available }, + } +end + +local function format_diagnostics(diagnostics) + if context.is_context_enabled('diagnostics') == false then + return 'Enable diagnostics context.' + end + if not diagnostics or #diagnostics == 0 then + return 'No diagnostics available.' + end + + local counts = {} + for _, diag in ipairs(diagnostics) do + counts[diag.severity] = (counts[diag.severity] or 0) + 1 + end + local parts = {} + if counts[vim.diagnostic.severity.ERROR] then + table.insert(parts, string.format('%d Error%s', counts[1], counts[1] > 1 and 's' or '')) + end + if counts[vim.diagnostic.severity.WARN] then + table.insert(parts, string.format('%d Warning%s', counts[2], counts[2] > 1 and 's' or '')) + end + if counts[vim.diagnostic.severity.INFO] then + table.insert(parts, string.format('%d Info%s', counts[3], counts[3] > 1 and 's' or '')) + end + + return table.concat(parts, ', ') +end + +local function format_selections(selections) + local content = {} + for _, sel in ipairs(selections or {}) do + local lang = sel.file and sel.file.extension or '' + local text = string.format('```%s\n%s\n```', lang, sel.content) + + table.insert(content, text) + end + return table.concat(content, '\n') +end + +---@param cursor_data OpencodeContextCursorData +local function format_cursor_data(cursor_data) + if context.is_context_enabled('cursor_data') == false then + return 'Enable cursor data context.' + end + if not cursor_data or vim.tbl_isempty(cursor_data) then + return 'No cursor data available.' + end + + local filetype = context.context.current_file.extension + local parts = { + 'Line: ' .. (cursor_data.line or 'N/A'), + (cursor_data.column or ''), + string.format('```%s \n%s\n```', filetype, cursor_data.line_content or 'N/A'), + } + + return table.concat(parts, '\n') +end + +---@type CompletionSource +local context_source = { + name = 'context', + priority = 1, + complete = function(completion_context) + local input = completion_context.input or '' + + if completion_context.trigger_char ~= '#' then + return {} + end + + local items = {} + local ctx = context.delta_context() + + local current_file_available = context.is_context_enabled('current_file') + + table.insert( + items, + create_context_item( + 'Current File', + 'current_file', + current_file_available, + string.format('Current file: %s', ctx.current_file and vim.fn.fnamemodify(ctx.current_file.path, ':~:.')) + ) + ) + + if context.is_context_enabled('files') and ctx.mentioned_files and #ctx.mentioned_files > 0 then + for _, file in ipairs(ctx.mentioned_files) do + local filename = vim.fn.fnamemodify(file, ':~:.') + table.insert( + items, + create_context_item(filename, 'mentioned_file', true, 'Remove ' .. filename, icons.get_glyph('file')) + ) + end + end + + table.insert( + items, + create_context_item( + 'Selection', + 'selection', + context.is_context_enabled('selection'), + format_selections(ctx.selections or {}) + ) + ) + + if context.is_context_enabled('agents') and ctx.mentioned_subagents then + for _, subagent in ipairs(ctx.mentioned_subagents) do + table.insert( + items, + create_context_item(subagent .. ' (agent)', 'subagent', true, 'Remove ' .. subagent, icons.get_glyph('agent')) + ) + end + end + + table.insert( + items, + create_context_item( + 'Diagnostics', + 'diagnostics', + context.is_context_enabled('diagnostics'), + format_diagnostics(ctx.linter_errors) + ) + ) + + table.insert( + items, + create_context_item( + 'Cursor Data', + 'cursor_data', + context.is_context_enabled('cursor_data'), + format_cursor_data(ctx.cursor_data) + ) + ) + + if #input > 0 then + items = vim.tbl_filter(function(item) + return item.label:lower():find(input:lower(), 1, true) ~= nil + end, items) + end + + table.sort(items, function(a, b) + if a.data.available ~= b.data.available then + return a.data.available + end + return a.label < b.label + end) + + return items + end, + on_complete = function(item) + local input_win = require('opencode.ui.input_window') + if not item or not item.data then + return + end + + local type = item.data.type + local context_cfg = vim.deepcopy(state.current_context_config) or {} + if not context_cfg or not context_cfg[type] then + context_cfg[type] = vim.deepcopy(config.context[type]) + end + + if vim.tbl_contains({ 'current_file', 'selection', 'diagnostics', 'cursor_data' }, type) then + context_cfg[type] = context_cfg[type] or {} + context_cfg[type].enabled = not item.data.available + end + + state.current_context_config = context_cfg + + if type == 'mentioned_file' then + context.remove_file(item.data.name) + input_win.remove_mention(item.data.name) + elseif type == 'subagent' then + local subagent_name = item.data.name:gsub(' %(agent%)$', '') + context.remove_subagent(subagent_name) + input_win.remove_mention(subagent_name) + end + + vim.schedule(function() + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n') + + local _, col = unpack(vim.api.nvim_win_get_cursor(0)) + local line = vim.api.nvim_get_current_line() + if col > 0 and line:sub(col, col) == config.keymap.window.context_items then + line = line:sub(1, col - 1) .. line:sub(col + 1) + input_win.set_current_line(line) + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') + end + end) + end, +} + +---Get the context completion source +---@return CompletionSource +function M.get_source() + return context_source +end + +return M diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index e539be3a..7357168d 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -56,6 +56,7 @@ function Source:get_completions(ctx, callback) table.insert(items, { label = item.label, kind = item.kind == 'file' and 17 or item.kind == 'folder' and 19 or 1, -- 17: File, 19: Folder, 1: Text + kind_icon = item.kind_icon, detail = item.detail, documentation = item.documentation, insertText = item.insert_text or item.label, diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index dd0a3025..955c88d0 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -50,7 +50,7 @@ function M.setup(completion_sources) } local items = {} - for i, completion_source in ipairs(completion_sources) do + for _, completion_source in ipairs(completion_sources) do local source_items = completion_source.complete(context) for j, item in ipairs(source_items) do table.insert(items, { @@ -58,6 +58,9 @@ function M.setup(completion_sources) kind = item.kind == 'file' and cmp.lsp.CompletionItemKind.File or item.kind == 'folder' and cmp.lsp.CompletionItemKind.Folder or cmp.lsp.CompletionItemKind.Text, + cmp = { + kind_text = item.kind_icon, + }, detail = item.detail, documentation = item.documentation, insertText = item.insert_text or item.label, diff --git a/lua/opencode/ui/completion/engines/vim_complete.lua b/lua/opencode/ui/completion/engines/vim_complete.lua index 6ba2ab73..3b579525 100644 --- a/lua/opencode/ui/completion/engines/vim_complete.lua +++ b/lua/opencode/ui/completion/engines/vim_complete.lua @@ -31,8 +31,12 @@ function M._get_trigger(before_cursor) local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') local triggers = {} - if mention_key then table.insert(triggers, mention_key) end - if slash_key then table.insert(triggers, slash_key) end + if mention_key then + table.insert(triggers, mention_key) + end + if slash_key then + table.insert(triggers, slash_key) + end local trigger_chars = table.concat(vim.tbl_map(vim.pesc, triggers), '') local trigger_char, trigger_match = before_cursor:match('.*([' .. trigger_chars .. '])([%w_%-%.]*)') return trigger_char, trigger_match diff --git a/lua/opencode/ui/completion/subagents.lua b/lua/opencode/ui/completion/subagents.lua index bcdfdb46..c6d37ef3 100644 --- a/lua/opencode/ui/completion/subagents.lua +++ b/lua/opencode/ui/completion/subagents.lua @@ -1,3 +1,4 @@ +local icons = require('opencode.ui.icons') local M = {} ---@type CompletionSource @@ -23,6 +24,7 @@ local subagent_source = { local item = { label = subagent .. ' (agent)', kind = 'subagent', + kind_icon = icons.get('agent'), detail = 'Subagent', documentation = 'Use the "' .. subagent .. '" subagent for this task.', insert_text = subagent, diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua new file mode 100644 index 00000000..7a615a53 --- /dev/null +++ b/lua/opencode/ui/context_bar.lua @@ -0,0 +1,188 @@ +local M = {} + +local context = require('opencode.context') +local icons = require('opencode.ui.icons') +local state = require('opencode.state') + +local function get_current_file_info(ctx) + local current_file = ctx.current_file + if not current_file then + return nil + end + + return { + name = current_file.name, + path = current_file.path, + } +end + +local function get_attached_files_count(ctx) + local mentioned_files = ctx.mentioned_files + return mentioned_files and #mentioned_files or 0 +end + +local function has_selection(ctx) + local selections = ctx.selections + return selections and #selections > 0 +end + +local function has_cursor_data(ctx) + local cursor_data = ctx.cursor_data + return cursor_data ~= nil +end + +local function has_diagnostics(ctx) + local diagnostics = ctx.linter_errors + return diagnostics and #diagnostics > 0 +end + +local function format_cursor_data(ctx) + local cursor_data = ctx.cursor_data + if not cursor_data then + return '' + end + return string.format('L:%d ', cursor_data.line, cursor_data.col) +end + +local function create_winbar_segments() + local ctx = context.delta_context() + local segments = { + { + icon = icons.get('context'), + text = '', + highlight = 'OpencodeContext', + }, + } + + local current_file = get_current_file_info(ctx) + if context.is_context_enabled('current_file') and current_file then + table.insert(segments, { + icon = icons.get('attached_file'), + text = current_file.name, + highlight = 'OpencodeContextCurrentFile', + }) + end + + local agents = ctx.mentioned_subagents or {} + if context.is_context_enabled('agents') and #agents > 0 then + table.insert(segments, { + icon = icons.get('agent'), + text = '(' .. #agents .. ')', + highlight = 'OpencodeContextAgent', + }) + end + + local attached_count = get_attached_files_count(ctx) + if context.is_context_enabled('files') and attached_count > 0 then + table.insert(segments, { + icon = icons.get('file'), + text = '(' .. attached_count .. ')', + highlight = 'OpencodeContext', + }) + end + + if context.is_context_enabled('selection') and has_selection(ctx) then + table.insert(segments, { + icon = '', + text = "'<'> Sel", + highlight = 'OpencodeContextSelection', + }) + end + + if context.is_context_enabled('cursor_data') and has_cursor_data(ctx) then + table.insert(segments, { + icon = icons.get('cursor_data'), + text = format_cursor_data(ctx), + highlight = 'OpencodeContextSelection', + }) + end + + if context.is_context_enabled('diagnostics') and has_diagnostics(ctx) then + local counts = {} + local diagnostics = ctx.linter_errors + local severity_types = { + [vim.diagnostic.severity.ERROR] = 'error', + [vim.diagnostic.severity.WARN] = 'warning', + [vim.diagnostic.severity.INFO] = 'info', + } + + for _, diag in ipairs(diagnostics or {}) do + local type_name = severity_types[diag.severity] or 'error' + counts[type_name] = (counts[type_name] or 0) + 1 + end + + for _, type_name in pairs(severity_types) do + local count = counts[type_name] + if count and count > 0 then + table.insert(segments, { + icon = icons.get(type_name), + text = '(' .. count .. ')', + highlight = 'OpencodeContext' .. type_name:gsub('^%l', string.upper), + }) + end + end + end + + return segments +end + +local function format_winbar_text(segments) + if #segments == 0 then + return '' + end + + local parts = {} + + for i, segment in ipairs(segments) do + local segment_text = segment.icon .. segment.text + local highlight = segment.highlight and ('%#' .. segment.highlight .. '#') or '' + + table.insert(parts, highlight .. segment_text .. '%*') + + if i < #segments then + table.insert(parts, ' %#OpencodeContextBar#|%* ') + end + end + + return ' ' .. table.concat(parts, '') +end + +local function update_winbar_highlights(win_id) + local current = vim.api.nvim_get_option_value('winhighlight', { win = win_id }) + local parts = vim.split(current, ',') + + parts = vim.tbl_filter(function(part) + return not part:match('^WinBar:') and not part:match('^WinBarNC:') + end, parts) + + if not vim.tbl_contains(parts, 'Normal:OpencodeNormal') then + table.insert(parts, 'Normal:OpencodeNormal') + end + + table.insert(parts, 'WinBar:OpencodeContextBar') + table.insert(parts, 'WinBarNC:OpencodeContextBar') + + vim.api.nvim_set_option_value('winhighlight', table.concat(parts, ','), { win = win_id }) +end + +function M.setup() + state.subscribe({ 'current_context_config', 'current_code_buf', 'opencode_focused', 'context_updated_at' }, function() + M.render() + end) +end + +function M.render(windows) + vim.schedule(function() + windows = windows or state.windows + local win = windows and windows.input_win + if not win then + return + end + local segments = create_winbar_segments() + + vim.wo[win].winbar = format_winbar_text(segments) + update_winbar_highlights(win) + end) +end + +return M diff --git a/lua/opencode/ui/icons.lua b/lua/opencode/ui/icons.lua index 4d6bec69..f4183e0c 100644 --- a/lua/opencode/ui/icons.lua +++ b/lua/opencode/ui/icons.lua @@ -10,7 +10,7 @@ local presets = { header_assistant = '๐Ÿค–', -- actions/tools run = '๐Ÿ’ป', - task = '๐Ÿ’ป', + task = '๐Ÿงฐ', read = '๐Ÿ‘€', edit = 'โœ๏ธ', write = '๐Ÿ“', @@ -22,12 +22,20 @@ local presets = { snapshot = '๐Ÿ“ธ', restore_point = '๐Ÿ•›', file = '๐Ÿ“„', + attached_file = '๐Ÿ“Ž', + agent = '๐Ÿค–', -- statuses status_on = '๐ŸŸข', status_off = 'โšซ', guard_on = '๐Ÿšซ', -- borders and misc border = 'โ–Œ', + -- context bar + cursor_data = '๐Ÿ“', + context = '๐Ÿ“š ', + error = 'โ›” ', + warning = 'โš ๏ธ', + info = 'โ„น๏ธ', }, nerdfonts = { -- headers @@ -47,12 +55,20 @@ local presets = { snapshot = '๓ฐป› ', restore_point = '๓ฑ—š ', file = '๏…› ', + attached_file = '๓ฐŒท ', + agent = '๓ฐšฉ ', -- statuses status_on = '๏ˆ… ', status_off = '๏ˆ„ ', guard_on = '๏”“', -- borders and misc border = 'โ–Œ', + -- context bar + cursor_data = '๓ฐ—ง ', + context = '๎ฎข ', + error = '๏— ', + warning = '๏ฑ ', + info = '๏š ', }, text = { -- headers @@ -71,13 +87,21 @@ local presets = { tool = '::', snapshot = '::', restore_point = '::', - file = '::', + file = '@', + attached_file = '@', + agent = '@', -- statuses status_on = 'ON', status_off = 'OFF', guard_on = 'X', -- borders and misc border = 'โ–Œ', + -- context bar + cursor_data = '[|] ', + context = '[Ctx] ', + error = '[E]', + warning = '[W]', + info = '[I] ', }, } diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 6f3bec9b..773edf8d 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -110,6 +110,10 @@ function M.setup(windows) M.refresh_placeholder(windows) M.setup_keymaps(windows) M.recover_input(windows) + + require('opencode.ui.context_bar').render(windows) + + M.add_winbar_padding(windows) end function M.update_dimensions(windows) @@ -191,6 +195,36 @@ function M.set_content(text, windows) local lines = type(text) == 'table' and text or vim.split(tostring(text), '\n') vim.api.nvim_buf_set_lines(windows.input_buf, 0, -1, false, lines) + M.add_winbar_padding(windows) +end + +function M.set_current_line(text, windows) + windows = windows or state.windows + if not M.mounted(windows) then + return + end + + vim.api.nvim_set_current_line(text) + M.add_winbar_padding(windows) +end + +function M.remove_mention(mention_name, windows) + windows = windows or state.windows + if not M.mounted(windows) then + return + end + + local lines = vim.api.nvim_buf_get_lines(windows.input_buf, 0, -1, false) + for i, line in ipairs(lines) do + local updated_line = line:gsub(config.keymap.window.mention .. mention_name, '') + if updated_line ~= line then + lines[i] = updated_line + end + end + + vim.api.nvim_buf_set_lines(windows.input_buf, 0, -1, false, lines) + require('opencode.ui.mention').highlight_all_mentions(windows.input_buf) + M.add_winbar_padding(windows) end function M.is_empty() @@ -203,6 +237,34 @@ function M.is_empty() return #lines == 0 or (#lines == 1 and lines[1] == '') end +function M.add_winbar_padding(windows) + if not M.mounted(windows) then + return + end + + local ns_id = vim.api.nvim_create_namespace('winbar_padding') + vim.api.nvim_buf_clear_namespace(windows.input_buf, ns_id, 0, -1) + + vim.api.nvim_buf_set_extmark(windows.input_buf, ns_id, 0, 0, { + virt_lines = { { { ' ' } } }, + virt_lines_above = true, + }) + + M.apply_topfill_workaround(windows) +end + +function M.apply_topfill_workaround(windows) + if not M.mounted(windows) then + return + end + + local topfill = 1 + local win = windows.input_win + if win and vim.api.nvim_win_is_valid(win) then + vim.fn.win_execute(win, 'lua vim.fn.winrestview({ topfill = ' .. topfill .. ' })') + end +end + function M.setup_keymaps(windows) local keymap = require('opencode.keymap') keymap.setup_window_keymaps(config.keymap.input_window, windows.input_buf) @@ -215,6 +277,8 @@ function M.setup_autocmds(windows, group) callback = function() M.refresh_placeholder(windows) state.last_focused_opencode_window = 'input' + require('opencode.ui.context_bar').render() + M.apply_topfill_workaround(windows) end, }) @@ -224,6 +288,10 @@ function M.setup_autocmds(windows, group) local input_lines = vim.api.nvim_buf_get_lines(windows.input_buf, 0, -1, false) state.input_content = input_lines M.refresh_placeholder(windows, input_lines) + require('opencode.ui.context_bar').render() + if #input_lines == 0 or (#input_lines == 1 and input_lines[1] == '') then + M.add_winbar_padding(windows) + end end, }) diff --git a/lua/opencode/ui/mention.lua b/lua/opencode/ui/mention.lua index f45c4eee..5ffad9f4 100644 --- a/lua/opencode/ui/mention.lua +++ b/lua/opencode/ui/mention.lua @@ -108,6 +108,7 @@ end function M.mention(get_name) local windows = require('opencode.state').windows + local mention_key = require('opencode.config').get('keymap').window.mention_file get_name(function(name) vim.schedule(function() diff --git a/lua/opencode/ui/output_window.lua b/lua/opencode/ui/output_window.lua index ccf76277..82cd2cb1 100644 --- a/lua/opencode/ui/output_window.lua +++ b/lua/opencode/ui/output_window.lua @@ -49,6 +49,7 @@ function M.setup(windows) vim.api.nvim_set_option_value('winfixwidth', true, { win = windows.output_win }) vim.api.nvim_set_option_value('signcolumn', 'yes', { scope = 'local', win = windows.output_win }) vim.api.nvim_set_option_value('list', false, { scope = 'local', win = windows.output_win }) + vim.api.nvim_set_option_value('statuscolumn', '', { win = windows.output_win }) M.update_dimensions(windows) M.setup_keymaps(windows) diff --git a/lua/opencode/ui/ui.lua b/lua/opencode/ui/ui.lua index 3db2368d..6d09c41d 100644 --- a/lua/opencode/ui/ui.lua +++ b/lua/opencode/ui/ui.lua @@ -82,9 +82,9 @@ function M.create_windows() local autocmds = require('opencode.ui.autocmds') - if not M.is_opencode_focused() then - require('opencode.context').load() + if not require('opencode.ui.ui').is_opencode_focused() then state.last_code_win_before_opencode = vim.api.nvim_get_current_win() + state.current_code_buf = vim.api.nvim_get_current_buf() end local buffers = M.setup_buffers() diff --git a/lua/opencode/util.lua b/lua/opencode/util.lua index d6e6038b..233b88a0 100644 --- a/lua/opencode/util.lua +++ b/lua/opencode/util.lua @@ -11,10 +11,10 @@ function M.uid() return tostring(os.time()) .. '-' .. tostring(math.random(1000, 9999)) end -function M.is_current_buf_a_file() - local bufnr = vim.api.nvim_get_current_buf() +function M.is_buf_a_file(bufnr) + bufnr = bufnr or vim.api.nvim_get_current_buf() local buftype = vim.bo[bufnr].buftype - local filepath = vim.fn.expand('%:p') + local filepath = vim.api.nvim_buf_get_name(bufnr) -- Valid files have empty buftype -- This excludes special buffers like help, terminal, nofile, etc. From 50f922dc6861f1f0f2af5771932fa22630fbf053 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 16 Oct 2025 15:27:29 -0400 Subject: [PATCH 02/48] fix: issues with backmerge --- lua/opencode/api.lua | 7 +++++ lua/opencode/config.lua | 1 + lua/opencode/init.lua | 1 + lua/opencode/types.lua | 30 ++----------------- lua/opencode/ui/completion/context.lua | 5 ++-- .../ui/completion/engines/blink_cmp.lua | 4 +++ 6 files changed, 18 insertions(+), 30 deletions(-) diff --git a/lua/opencode/api.lua b/lua/opencode/api.lua index 312d2bcc..b6a0b00c 100644 --- a/lua/opencode/api.lua +++ b/lua/opencode/api.lua @@ -299,6 +299,13 @@ function M.mention() require('opencode.ui.completion').trigger_completion(char)() end +function M.context_items() + local config = require('opencode.config') + local char = config.get_key_for_function('input_window', 'context_items') + ui.focus_input({ restore_position = true, start_insert = true }) + require('opencode.ui.completion').trigger_completion(char)() +end + function M.slash_commands() local config = require('opencode.config') local char = config.get_key_for_function('input_window', 'slash_commands') diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index 7d0d9435..2a944e98 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -56,6 +56,7 @@ M.defaults = { ['~'] = { 'mention_file', mode = 'i' }, ['@'] = { 'mention', mode = 'i' }, ['/'] = { 'slash_commands', mode = 'i' }, + ['#'] = { 'context_items', mode = 'i' }, [''] = { 'toggle_pane', mode = { 'n', 'i' } }, [''] = { 'prev_prompt_history', mode = { 'n', 'i' } }, [''] = { 'next_prompt_history', mode = { 'n', 'i' } }, diff --git a/lua/opencode/init.lua b/lua/opencode/init.lua index b34dd0ac..7aa630c1 100644 --- a/lua/opencode/init.lua +++ b/lua/opencode/init.lua @@ -13,6 +13,7 @@ function M.setup(opts) require('opencode.keymap').setup(config.keymap) require('opencode.ui.completion').setup() require('opencode.event_manager').setup() + require('opencode.ui.context_bar').setup() end return M diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index 983d2607..f7d6772f 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -53,7 +53,8 @@ ---@field share? SessionShareInfo ---@class OpencodeKeymapEntry ----@field [1] string # Function name +---@field [1] string # Function nam + ---@field mode? string|string[] # Mode(s) for the keymap ---@field desc? string # Keymap description @@ -66,28 +67,6 @@ ---@field accept_all string ---@field deny string -<<<<<<< HEAD -======= ----@class OpencodeKeymapWindow ----@field submit string ----@field submit_insert string ----@field close string ----@field stop string ----@field next_message string ----@field prev_message string ----@field mention_file string # mention files with a file picker ----@field mention string # mention subagents or files with a completion popup ----@field slash_commands string ----@field context_items string # select context items with a completion popup ----@field toggle_pane string ----@field prev_prompt_history string ----@field next_prompt_history string ----@field focus_input string ----@field debug_message string ----@field debug_output string ----@field switch_mode string ----@field select_child_session string ->>>>>>> 31b9b62 (wip: context bar) ---@class OpencodeKeymap ---@field editor OpencodeKeymapEditor ---@field input_window OpencodeKeymapInputWindow @@ -140,13 +119,8 @@ ---@class OpencodeContextConfig ---@field enabled boolean ---@field cursor_data { enabled: boolean } -<<<<<<< HEAD ----@field diagnostics { info: boolean, warning: boolean, error: boolean } ----@field current_file { enabled: boolean, show_full_path: boolean } -======= ---@field diagnostics { enabled:boolean, info: boolean, warning: boolean, error: boolean } ---@field current_file { enabled: boolean } ->>>>>>> 31b9b62 (wip: context bar) ---@field selection { enabled: boolean } ---@field subagents { enabled: boolean } diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index f4150b6a..fafe57c5 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -1,4 +1,4 @@ -local config = require('opencode.config').get() +local config = require('opencode.config') local context = require('opencode.context') local state = require('opencode.state') local icons = require('opencode.ui.icons') @@ -89,7 +89,8 @@ local context_source = { complete = function(completion_context) local input = completion_context.input or '' - if completion_context.trigger_char ~= '#' then + local expected_trigger = config.get_key_for_function('input_window', 'context_items') + if completion_context.trigger_char ~= expected_trigger then return {} end diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index 7357168d..1b20d671 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -12,6 +12,7 @@ function Source:get_trigger_characters() local config = require('opencode.config') local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') + local context_key = config.get_key_for_function('input_window', 'context_items') local triggers = {} if mention_key then table.insert(triggers, mention_key) @@ -19,6 +20,9 @@ function Source:get_trigger_characters() if slash_key then table.insert(triggers, slash_key) end + if context_key then + table.insert(triggers, context_key) + end return triggers end From 472b69e66f0b507a7fe27cbc8c2ad39935c5e6bf Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 27 Oct 2025 16:17:57 -0400 Subject: [PATCH 03/48] fix: main rebase --- lua/opencode/ui/autocmds.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/opencode/ui/autocmds.lua b/lua/opencode/ui/autocmds.lua index d6a72912..c42dc388 100644 --- a/lua/opencode/ui/autocmds.lua +++ b/lua/opencode/ui/autocmds.lua @@ -29,6 +29,7 @@ function M.setup_autocmds(windows) if args.file == '' then return end + local state = require('opencode.state') state.last_code_win_before_opencode = vim.api.nvim_get_current_win() state.current_code_buf = vim.api.nvim_get_current_buf() end, From 3a95eeeb1c83907ae731a5c8b8f136fc29a1557e Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 27 Oct 2025 21:33:10 -0400 Subject: [PATCH 04/48] fix(context_completion): get key for new keymaps --- lua/opencode/ui/completion/context.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index fafe57c5..014b6f29 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -206,7 +206,8 @@ local context_source = { local _, col = unpack(vim.api.nvim_win_get_cursor(0)) local line = vim.api.nvim_get_current_line() - if col > 0 and line:sub(col, col) == config.keymap.window.context_items then + local key = config.get_key_for_function('input_window', 'context_items') + if col > 0 and line:sub(col, col) == key then line = line:sub(1, col - 1) .. line:sub(col + 1) input_win.set_current_line(line) vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') From ae9f106898f8c69be77ec2241fa2a3df319a3c67 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 27 Oct 2025 21:36:12 -0400 Subject: [PATCH 05/48] fix(context): load context on opening --- lua/opencode/ui/ui.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/opencode/ui/ui.lua b/lua/opencode/ui/ui.lua index 6d09c41d..c8b38c6a 100644 --- a/lua/opencode/ui/ui.lua +++ b/lua/opencode/ui/ui.lua @@ -83,6 +83,7 @@ function M.create_windows() local autocmds = require('opencode.ui.autocmds') if not require('opencode.ui.ui').is_opencode_focused() then + require('opencode.context').load() state.last_code_win_before_opencode = vim.api.nvim_get_current_win() state.current_code_buf = vim.api.nvim_get_current_buf() end From 75c093e201ba1500bc2868ccba432e9f489f9335 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 27 Oct 2025 21:50:08 -0400 Subject: [PATCH 06/48] fix(context): toggle items was not working anymore --- lua/opencode/context.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 0cd7530a..e6df3caf 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -55,7 +55,11 @@ function M.is_context_enabled(context_key) local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled') local is_state_enabled = vim.tbl_get(state, 'current_context_config', context_key, 'enabled') - return is_state_enabled ~= nil and is_state_enabled or is_enabled + if is_state_enabled ~= nil then + return is_state_enabled + else + return is_enabled + end end function M.get_diagnostics(buf) From f8ba46dc6646b6cd9ac6966561b1a166d1cadb36 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 27 Oct 2025 21:56:05 -0400 Subject: [PATCH 07/48] fix(context): state subscription were not registered The setup method was not called anymore in init.lua --- lua/opencode/context.lua | 2 +- lua/opencode/init.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index e6df3caf..9320b3a3 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -452,7 +452,7 @@ function M.extract_legacy_tag(tag, text) end function M.setup() - state.subscribe({ 'current_code_buf', 'current_context_config', 'opencode_focused' }, function() + state.subscribe({ 'current_code_buf', 'current_context_config', 'is_opencode_focused' }, function(a) M.load() end) diff --git a/lua/opencode/init.lua b/lua/opencode/init.lua index 7aa630c1..13c51b02 100644 --- a/lua/opencode/init.lua +++ b/lua/opencode/init.lua @@ -13,6 +13,7 @@ function M.setup(opts) require('opencode.keymap').setup(config.keymap) require('opencode.ui.completion').setup() require('opencode.event_manager').setup() + require('opencode.context').setup() require('opencode.ui.context_bar').setup() end From 6230e7f55464a5d666737bd6c504a405243eb025 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 07:14:43 -0400 Subject: [PATCH 08/48] feat(context_bar): add highlights --- lua/opencode/ui/highlight.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index f76cab60..1420d990 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -23,6 +23,14 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { bg = '#757575', fg = '#424242', bold = false, default = true }) vim.api.nvim_set_hl(0, 'OpencodeHint', { link = 'Comment', default = true }) vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#F44336', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'Comment', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = 'Comment', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = 'Visual', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = 'DiagnosticError', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) else vim.api.nvim_set_hl(0, 'OpencodeBorder', { fg = '#616161', default = true }) vim.api.nvim_set_hl(0, 'OpencodeBackground', { link = 'Normal', default = true }) @@ -43,6 +51,14 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { bg = '#616161', fg = '#CCCCCC', bold = false, default = true }) vim.api.nvim_set_hl(0, 'OpencodeHint', { link = 'Comment', default = true }) vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#EF5350', bold = true, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'Comment', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = 'Comment', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = 'Visual', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = 'DiagnosticError', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) end end From 9b99ac3060fa450d5e6446037b87c09cadc76806 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 07:28:04 -0400 Subject: [PATCH 09/48] fix(context): add missing function after rebase clear_subagents and clear_subagents were missing after rebase This causes history navigation to throw an error --- lua/opencode/context.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 9320b3a3..d95de0aa 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -143,6 +143,10 @@ function M.remove_file(file) state.context_updated_at = vim.uv.now() end +function M.clear_files() + M.context.mentioned_files = nil +end + function M.add_subagent(subagent) if not M.context.mentioned_subagents then M.context.mentioned_subagents = {} @@ -168,6 +172,10 @@ function M.remove_subagent(subagent) state.context_updated_at = vim.uv.now() end +function M.clear_subagents() + M.context.mentioned_subagents = nil +end + ---@param opts? OpencodeContextConfig function M.delta_context(opts) opts = opts or config.context From df552dd82ff5ad0850450ccafb821baaffb39c40 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 07:29:20 -0400 Subject: [PATCH 10/48] fix(mention): remove dead code --- lua/opencode/ui/mention.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/opencode/ui/mention.lua b/lua/opencode/ui/mention.lua index 5ffad9f4..f45c4eee 100644 --- a/lua/opencode/ui/mention.lua +++ b/lua/opencode/ui/mention.lua @@ -108,7 +108,6 @@ end function M.mention(get_name) local windows = require('opencode.state').windows - local mention_key = require('opencode.config').get('keymap').window.mention_file get_name(function(name) vim.schedule(function() From c06dfc590f8785144795971d60e7f0764693be06 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 07:49:10 -0400 Subject: [PATCH 11/48] fix(context-completion): remove agent/files The remove agents/files was referring to the old keymap structure --- lua/opencode/context.lua | 4 ++++ lua/opencode/ui/completion/context.lua | 11 +++++++++-- lua/opencode/ui/input_window.lua | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index d95de0aa..72b615f3 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -51,6 +51,9 @@ function M.load() state.context_updated_at = vim.uv.now() end +-- Checks if a context feature is enabled in config or state +---@param context_key string +---@return boolean function M.is_context_enabled(context_key) local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled') local is_state_enabled = vim.tbl_get(state, 'current_context_config', context_key, 'enabled') @@ -177,6 +180,7 @@ function M.clear_subagents() end ---@param opts? OpencodeContextConfig +---@return OpencodeContext function M.delta_context(opts) opts = opts or config.context if opts.enabled == false then diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 014b6f29..335ec89a 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -64,6 +64,7 @@ local function format_selections(selections) end ---@param cursor_data OpencodeContextCursorData +---@return string local function format_cursor_data(cursor_data) if context.is_context_enabled('cursor_data') == false then return 'Enable cursor data context.' @@ -114,7 +115,7 @@ local context_source = { local filename = vim.fn.fnamemodify(file, ':~:.') table.insert( items, - create_context_item(filename, 'mentioned_file', true, 'Remove ' .. filename, icons.get_glyph('file')) + create_context_item(filename, 'mentioned_file', true, 'Select to remove file ' .. filename, icons.get('file')) ) end end @@ -133,7 +134,13 @@ local context_source = { for _, subagent in ipairs(ctx.mentioned_subagents) do table.insert( items, - create_context_item(subagent .. ' (agent)', 'subagent', true, 'Remove ' .. subagent, icons.get_glyph('agent')) + create_context_item( + subagent .. ' (agent)', + 'subagent', + true, + 'Select to remove agent ' .. subagent, + icons.get('agent') + ) ) end end diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 773edf8d..994421e3 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -216,7 +216,8 @@ function M.remove_mention(mention_name, windows) local lines = vim.api.nvim_buf_get_lines(windows.input_buf, 0, -1, false) for i, line in ipairs(lines) do - local updated_line = line:gsub(config.keymap.window.mention .. mention_name, '') + local mention_key = config.get_key_for_function('input_window', 'mention') + local updated_line = line:gsub(mention_key .. mention_name, '') if updated_line ~= line then lines[i] = updated_line end From dab53b6824c5a36277cd9734979419b968633407 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 08:32:25 -0400 Subject: [PATCH 12/48] refactor(context-completion): cleanup the menu creation --- lua/opencode/context.lua | 1 + lua/opencode/ui/completion/context.lua | 154 ++++++++++++++----------- 2 files changed, 87 insertions(+), 68 deletions(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 72b615f3..f9e10907 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -6,6 +6,7 @@ local state = require('opencode.state') local M = {} +---@type OpencodeContext M.context = { -- current file current_file = nil, diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 335ec89a..547c5f23 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -63,7 +63,7 @@ local function format_selections(selections) return table.concat(content, '\n') end ----@param cursor_data OpencodeContextCursorData +---@param cursor_data? OpencodeContextCursorData ---@return string local function format_cursor_data(cursor_data) if context.is_context_enabled('cursor_data') == false then @@ -83,6 +83,83 @@ local function format_cursor_data(cursor_data) return table.concat(parts, '\n') end +---@param ctx OpencodeContext +---@return CompletionItem +local function add_current_file_item(ctx) + local current_file_available = context.is_context_enabled('current_file') + return create_context_item( + 'Current File', + 'current_file', + current_file_available, + string.format('Current file: %s', ctx.current_file and vim.fn.fnamemodify(ctx.current_file.path, ':~:.')) + ) +end + +---@param ctx OpencodeContext +---@return CompletionItem[] +local function add_mentioned_files_items(ctx) + local items = {} + if context.is_context_enabled('files') and ctx.mentioned_files and #ctx.mentioned_files > 0 then + for _, file in ipairs(ctx.mentioned_files) do + local filename = vim.fn.fnamemodify(file, ':~:.') + table.insert( + items, + create_context_item(filename, 'mentioned_file', true, 'Select to remove file ' .. filename, icons.get('file')) + ) + end + end + return items +end + +---@param ctx OpencodeContext +---@return CompletionItem +local function add_selection_item(ctx) + return create_context_item( + 'Selection', + 'selection', + context.is_context_enabled('selection'), + format_selections(ctx.selections or {}) + ) +end + +---@param ctx OpencodeContext +---@return CompletionItem[] +local function add_subagents_items(ctx) + if not (context.is_context_enabled('agents') or ctx.mentioned_subagents) then + return {} + end + local items = {} + for _, agent in ipairs(ctx.mentioned_subagents or {}) do + table.insert( + items, + create_context_item(agent .. ' (agent)', 'subagent', true, 'Select to remove agent ' .. agent, icons.get('agent')) + ) + end + return items +end + +---@param ctx OpencodeContext +---@return CompletionItem +local function add_diagnostics_item(ctx) + return create_context_item( + 'Diagnostics', + 'diagnostics', + context.is_context_enabled('diagnostics'), + format_diagnostics(ctx.linter_errors) + ) +end + +---@param ctx OpencodeContext +---@return CompletionItem +local function add_cursor_data_item(ctx) + return create_context_item( + 'Cursor Data', + 'cursor_data', + context.is_context_enabled('cursor_data'), + format_cursor_data(ctx.cursor_data) + ) +end + ---@type CompletionSource local context_source = { name = 'context', @@ -95,75 +172,16 @@ local context_source = { return {} end - local items = {} local ctx = context.delta_context() - local current_file_available = context.is_context_enabled('current_file') - - table.insert( - items, - create_context_item( - 'Current File', - 'current_file', - current_file_available, - string.format('Current file: %s', ctx.current_file and vim.fn.fnamemodify(ctx.current_file.path, ':~:.')) - ) - ) - - if context.is_context_enabled('files') and ctx.mentioned_files and #ctx.mentioned_files > 0 then - for _, file in ipairs(ctx.mentioned_files) do - local filename = vim.fn.fnamemodify(file, ':~:.') - table.insert( - items, - create_context_item(filename, 'mentioned_file', true, 'Select to remove file ' .. filename, icons.get('file')) - ) - end - end - - table.insert( - items, - create_context_item( - 'Selection', - 'selection', - context.is_context_enabled('selection'), - format_selections(ctx.selections or {}) - ) - ) - - if context.is_context_enabled('agents') and ctx.mentioned_subagents then - for _, subagent in ipairs(ctx.mentioned_subagents) do - table.insert( - items, - create_context_item( - subagent .. ' (agent)', - 'subagent', - true, - 'Select to remove agent ' .. subagent, - icons.get('agent') - ) - ) - end - end - - table.insert( - items, - create_context_item( - 'Diagnostics', - 'diagnostics', - context.is_context_enabled('diagnostics'), - format_diagnostics(ctx.linter_errors) - ) - ) - - table.insert( - items, - create_context_item( - 'Cursor Data', - 'cursor_data', - context.is_context_enabled('cursor_data'), - format_cursor_data(ctx.cursor_data) - ) - ) + local items = { + add_current_file_item(ctx), + add_selection_item(ctx), + add_diagnostics_item(ctx), + add_cursor_data_item(ctx), + } + vim.list_extend(items, add_mentioned_files_items(ctx)) + vim.list_extend(items, add_subagents_items(ctx)) if #input > 0 then items = vim.tbl_filter(function(item) From 81daac487fb97b883b0f5d0b6104cdb228a62268 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 08:41:23 -0400 Subject: [PATCH 13/48] feat(core): load context when opening the window --- lua/opencode/core.lua | 4 ++++ lua/opencode/ui/ui.lua | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/opencode/core.lua b/lua/opencode/core.lua index 992af0e2..97b78521 100644 --- a/lua/opencode/core.lua +++ b/lua/opencode/core.lua @@ -49,6 +49,10 @@ function M.open(opts) local are_windows_closed = state.windows == nil + if not require('opencode.ui.ui').is_opencode_focused() then + require('opencode.context').load() + end + if are_windows_closed then -- Check if whether prompting will be allowed local mentioned_files = context.context.mentioned_files or {} diff --git a/lua/opencode/ui/ui.lua b/lua/opencode/ui/ui.lua index c8b38c6a..6d09c41d 100644 --- a/lua/opencode/ui/ui.lua +++ b/lua/opencode/ui/ui.lua @@ -83,7 +83,6 @@ function M.create_windows() local autocmds = require('opencode.ui.autocmds') if not require('opencode.ui.ui').is_opencode_focused() then - require('opencode.context').load() state.last_code_win_before_opencode = vim.api.nvim_get_current_win() state.current_code_buf = vim.api.nvim_get_current_buf() end From a7e4abffe24d6c3e09c20b4ad8b66cf3351d0b45 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 09:46:52 -0400 Subject: [PATCH 14/48] fix(context): don't add selection if empty --- lua/opencode/context.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index f9e10907..0748bce9 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -278,6 +278,10 @@ function M.get_current_selection() vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'nx', true) vim.fn.setpos('.', current_pos) + if not text or text == '' then + return nil + end + return { text = text and text:match('[^%s]') and text or nil, lines = start_line .. ', ' .. end_line, From 7be67e1c510ae9e2a936cb54acb2733ae3c26df6 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 11:19:34 -0400 Subject: [PATCH 15/48] feat(context-completion): selections are now multiple like files --- lua/opencode/context.lua | 21 +++++++++-- lua/opencode/ui/completion/context.lua | 48 +++++++++++++++----------- lua/opencode/ui/context_bar.lua | 4 +-- lua/opencode/ui/highlight.lua | 14 ++++---- lua/opencode/ui/icons.lua | 35 ++----------------- 5 files changed, 57 insertions(+), 65 deletions(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 0748bce9..719cc804 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -110,10 +110,25 @@ function M.add_selection(selection) state.context_updated_at = vim.uv.now() end -function M.add_file(file) - --- TODO: probably need a way to remove a file once it's been added? - --- maybe a keymap like clear all context? +function M.remove_selection(selection) + if not M.context.selections then + return + end + + for i, sel in ipairs(M.context.selections) do + if sel.file.path == selection.file.path and sel.lines == selection.lines then + table.remove(M.context.selections, i) + break + end + end + state.context_updated_at = vim.uv.now() +end +function M.clear_selections() + M.context.selections = nil +end + +function M.add_file(file) if not M.context.mentioned_files then M.context.mentioned_files = {} end diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 547c5f23..4a93d33e 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -5,13 +5,15 @@ local icons = require('opencode.ui.icons') local M = {} +---@generic T ---@param name string ---@param type string ---@param available boolean ---@param documentation string|nil ---@param icon string|nil +---@param additional_data? T ---@return CompletionItem -local function create_context_item(name, type, available, documentation, icon) +local function create_context_item(name, type, available, documentation, icon, additional_data) local label = name return { @@ -22,7 +24,7 @@ local function create_context_item(name, type, available, documentation, icon) documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'), insert_text = '', source_name = 'context', - data = { type = type, name = name, available = available }, + data = { type = type, name = name, available = available, additional_data = additional_data }, } end @@ -52,15 +54,9 @@ local function format_diagnostics(diagnostics) return table.concat(parts, ', ') end -local function format_selections(selections) - local content = {} - for _, sel in ipairs(selections or {}) do - local lang = sel.file and sel.file.extension or '' - local text = string.format('```%s\n%s\n```', lang, sel.content) - - table.insert(content, text) - end - return table.concat(content, '\n') +local function format_selection(selection) + local lang = selection.file and selection.file.extension or '' + return string.format('```%s\n%s\n```', lang, selection.content) end ---@param cursor_data? OpencodeContextCursorData @@ -112,14 +108,24 @@ local function add_mentioned_files_items(ctx) end ---@param ctx OpencodeContext ----@return CompletionItem -local function add_selection_item(ctx) - return create_context_item( - 'Selection', - 'selection', - context.is_context_enabled('selection'), - format_selections(ctx.selections or {}) - ) +---@return CompletionItem[] +local function add_selection_items(ctx) + local items = { + create_context_item( + 'Selection' .. (ctx.selections and #ctx.selections > 0 and string.format(' (%d)', #ctx.selections) or ''), + 'selection', + context.is_context_enabled('selection') + ), + } + + for i, selection in ipairs(ctx.selections or {}) do + local label = 'Selection ' .. (selection.file and vim.fn.fnamemodify(selection.file.path, ':t')) or i + table.insert( + items, + create_context_item(label, 'selection_item', true, format_selection(selection), icons.get('selection'), selection) + ) + end + return items end ---@param ctx OpencodeContext @@ -176,10 +182,10 @@ local context_source = { local items = { add_current_file_item(ctx), - add_selection_item(ctx), add_diagnostics_item(ctx), add_cursor_data_item(ctx), } + vim.list_extend(items, add_selection_items(ctx)) vim.list_extend(items, add_mentioned_files_items(ctx)) vim.list_extend(items, add_subagents_items(ctx)) @@ -224,6 +230,8 @@ local context_source = { local subagent_name = item.data.name:gsub(' %(agent%)$', '') context.remove_subagent(subagent_name) input_win.remove_mention(subagent_name) + elseif type == 'selection_item' then + context.remove_selection(item.data.additional_data --[[@as OpencodeContextSelection]]) end vim.schedule(function() diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua index 7a615a53..5f2df260 100644 --- a/lua/opencode/ui/context_bar.lua +++ b/lua/opencode/ui/context_bar.lua @@ -83,8 +83,8 @@ local function create_winbar_segments() if context.is_context_enabled('selection') and has_selection(ctx) then table.insert(segments, { - icon = '', - text = "'<'> Sel", + icon = icons.get('selection'), + text = '(' .. #ctx.selections .. ')', highlight = 'OpencodeContextSelection', }) end diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index 1420d990..35df9695 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -25,10 +25,10 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#F44336', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'Comment', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = 'Comment', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = 'Visual', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = 'DiagnosticError', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'OpencodeContext', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = '@label', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = '@label', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) else @@ -53,9 +53,9 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#EF5350', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'Comment', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = 'Comment', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = 'Visual', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = '@label', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = '@label', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = 'DiagnosticError', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) diff --git a/lua/opencode/ui/icons.lua b/lua/opencode/ui/icons.lua index f4183e0c..faf9a3b5 100644 --- a/lua/opencode/ui/icons.lua +++ b/lua/opencode/ui/icons.lua @@ -4,39 +4,6 @@ local config = require('opencode.config') local M = {} local presets = { - emoji = { - -- headers - header_user = 'โ–Œ๐Ÿ’ฌ', - header_assistant = '๐Ÿค–', - -- actions/tools - run = '๐Ÿ’ป', - task = '๐Ÿงฐ', - read = '๐Ÿ‘€', - edit = 'โœ๏ธ', - write = '๐Ÿ“', - plan = '๐Ÿ“ƒ', - search = '๐Ÿ”', - web = '๐ŸŒ', - list = '๐Ÿ“‚', - tool = '๐Ÿ”ง', - snapshot = '๐Ÿ“ธ', - restore_point = '๐Ÿ•›', - file = '๐Ÿ“„', - attached_file = '๐Ÿ“Ž', - agent = '๐Ÿค–', - -- statuses - status_on = '๐ŸŸข', - status_off = 'โšซ', - guard_on = '๐Ÿšซ', - -- borders and misc - border = 'โ–Œ', - -- context bar - cursor_data = '๐Ÿ“', - context = '๐Ÿ“š ', - error = 'โ›” ', - warning = 'โš ๏ธ', - info = 'โ„น๏ธ', - }, nerdfonts = { -- headers header_user = 'โ–Œ๓ฐญป ', @@ -69,6 +36,7 @@ local presets = { error = '๏— ', warning = '๏ฑ ', info = '๏š ', + selection = '๓ฐซ™ ', }, text = { -- headers @@ -102,6 +70,7 @@ local presets = { error = '[E]', warning = '[W]', info = '[I] ', + selection = "'<'> ", }, } From 681d263ce6a68d012a7623f19265c545145745f3 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 11:36:06 -0400 Subject: [PATCH 16/48] chore(context):fix warnings --- lua/opencode/ui/completion/context.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 4a93d33e..70b08245 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -19,7 +19,7 @@ local function create_context_item(name, type, available, documentation, icon, a return { label = label, kind = 'context', - kind_icon = icon or (available and '๏ˆ… ' or '๏ˆ„ '), + kind_icon = icon or (available and icons.get('status_on') or icons.get('status_off')), detail = name, documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'), insert_text = '', @@ -69,7 +69,7 @@ local function format_cursor_data(cursor_data) return 'No cursor data available.' end - local filetype = context.context.current_file.extension + local filetype = context.context.current_file and context.context.current_file.extension local parts = { 'Line: ' .. (cursor_data.line or 'N/A'), (cursor_data.column or ''), @@ -119,7 +119,8 @@ local function add_selection_items(ctx) } for i, selection in ipairs(ctx.selections or {}) do - local label = 'Selection ' .. (selection.file and vim.fn.fnamemodify(selection.file.path, ':t')) or i + local label = + string.format('Selection %d %s (%s)', i, selection.file and selection.file.name or 'Untitled', selection.lines) table.insert( items, create_context_item(label, 'selection_item', true, format_selection(selection), icons.get('selection'), selection) @@ -211,7 +212,7 @@ local context_source = { end local type = item.data.type - local context_cfg = vim.deepcopy(state.current_context_config) or {} + local context_cfg = vim.deepcopy(state.current_context_config or {}) if not context_cfg or not context_cfg[type] then context_cfg[type] = vim.deepcopy(config.context[type]) end From 5fffbfb7dbd8c7461d9df51bd77cd56d4b7c353a Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 11:46:37 -0400 Subject: [PATCH 17/48] feat(input_window): add context legend to input --- lua/opencode/ui/input_window.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 994421e3..2f3e2898 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -144,6 +144,7 @@ function M.refresh_placeholder(windows, input_lines) local slash_key = config.get_key_for_function('input_window', 'slash_commands') local mention_key = config.get_key_for_function('input_window', 'mention') local mention_file_key = config.get_key_for_function('input_window', 'mention_file') + local context_key = config.get_key_for_function('input_window', 'context_items') vim.api.nvim_buf_set_extmark(windows.input_buf, ns_id, 0, 0, { virt_text = { @@ -153,7 +154,9 @@ function M.refresh_placeholder(windows, input_lines) { mention_key or '@', 'OpencodeInputLegend' }, { ' mentions ', 'OpenCodeHint' }, { mention_file_key or '~', 'OpencodeInputLegend' }, - { ' to pick files' .. padding, 'OpenCodeHint' }, + { ' files ', 'OpenCodeHint' }, + { context_key or '#', 'OpencodeInputLegend' }, + { ' context' .. padding, 'OpenCodeHint' }, }, virt_text_pos = 'overlay', From 7b50203e7364e413ed3d19e232e10abaaaddeffa Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 12:52:20 -0400 Subject: [PATCH 18/48] feat(context): persist config from cmd arguments --- lua/opencode/core.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/opencode/core.lua b/lua/opencode/core.lua index 97b78521..a22c7161 100644 --- a/lua/opencode/core.lua +++ b/lua/opencode/core.lua @@ -113,13 +113,16 @@ function M.send_message(prompt, opts) if opts.model then local provider, model = opts.model:match('^(.-)/(.+)$') params.model = { providerID = provider, modelID = model } + state.current_model = opts.model end if opts.agent then params.agent = opts.agent + state.current_mode = opts.agent end params.parts = context.format_message(prompt, opts.context) + state.current_context_config = opts.context M.before_run(opts) From 210e69a65436f9f478cc87309ac1fdd3bcd061d4 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 13:20:57 -0400 Subject: [PATCH 19/48] test(core): add test for persisting options when sending a message --- tests/unit/core_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/core_spec.lua b/tests/unit/core_spec.lua index 4633baba..df2ccec7 100644 --- a/tests/unit/core_spec.lua +++ b/tests/unit/core_spec.lua @@ -5,6 +5,7 @@ local ui = require('opencode.ui.ui') local session = require('opencode.session') local Promise = require('opencode.promise') local stub = require('luassert.stub') +local assert = require('luassert') -- Provide a mock api_client for tests that need it local function mock_api_client() @@ -236,6 +237,28 @@ describe('opencode.core', function() assert.equal('sess-new', new.id) state.api_client.create_session = orig_session end) + + it('persist options in state when sending message', function() + local orig = state.api_client.create_message + state.windows = { mock = 'windows' } + state.active_session = { id = 'sess1' } + + state.api_client.create_message = function(_, sid, params) + create_called = true + assert.equal('sess1', sid) + assert.truthy(params.parts) + return Promise.new():resolve({ id = 'm1' }) + end + + core.send_message( + 'hello world', + { context = { current_file = { enabled = false } }, agent = 'plan', model = 'test/model' } + ) + assert.same(state.current_context_config, { current_file = { enabled = false } }) + assert.equal(state.current_mode, 'plan') + assert.equal(state.current_model, 'test/model') + state.api_client.create_message = orig + end) end) describe('opencode_ok (version checks)', function() From 6309ed22fb51ce9da9a9e4f7e883bc0218ac4883 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 13:24:45 -0400 Subject: [PATCH 20/48] test(core): fix invalid win errors in tests --- lua/opencode/ui/context_bar.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua index 5f2df260..c9c0333d 100644 --- a/lua/opencode/ui/context_bar.lua +++ b/lua/opencode/ui/context_bar.lua @@ -175,7 +175,7 @@ function M.render(windows) vim.schedule(function() windows = windows or state.windows local win = windows and windows.input_win - if not win then + if not (win and vim.api.nvim_win_is_valid(win)) then return end local segments = create_winbar_segments() From b9d54016e2fb655ef7ad5ac369bce4fc2a2e65dc Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Tue, 28 Oct 2025 14:55:00 -0400 Subject: [PATCH 21/48] test(context-bar): add unit tests for context-bar rendering --- tests/unit/context_bar_spec.lua | 263 ++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 tests/unit/context_bar_spec.lua diff --git a/tests/unit/context_bar_spec.lua b/tests/unit/context_bar_spec.lua new file mode 100644 index 00000000..f77146e7 --- /dev/null +++ b/tests/unit/context_bar_spec.lua @@ -0,0 +1,263 @@ +local context_bar = require('opencode.ui.context_bar') +local context = require('opencode.context') +local state = require('opencode.state') +local icons = require('opencode.ui.icons') +local assert = require('luassert') + +describe('opencode.ui.context_bar', function() + local original_delta_context + local original_is_context_enabled + local original_get_icon + local original_subscribe + local original_schedule + local original_api_win_is_valid + local original_api_get_option_value + local original_api_set_option_value + local original_vim_tbl_contains + local original_wo + local mock_context + + local function create_mock_window(win_id) + local captured_winbar = {} + vim.wo[win_id] = setmetatable({}, { + __newindex = function(_, key, value) + if key == 'winbar' then + captured_winbar.value = value + captured_winbar.set = true + end + end, + }) + return captured_winbar + end + + before_each(function() + original_delta_context = context.delta_context + original_is_context_enabled = context.is_context_enabled + original_get_icon = icons.get + original_subscribe = state.subscribe + original_schedule = vim.schedule + original_api_win_is_valid = vim.api.nvim_win_is_valid + original_api_get_option_value = vim.api.nvim_get_option_value + original_api_set_option_value = vim.api.nvim_set_option_value + original_vim_tbl_contains = vim.tbl_contains + original_wo = vim.wo + + mock_context = { + current_file = nil, + mentioned_files = nil, + mentioned_subagents = nil, + selections = nil, + linter_errors = nil, + cursor_data = nil, + } + + context.delta_context = function() + return mock_context + end + + context.is_context_enabled = function(_) + return true -- Enable all context types by default + end + + state.subscribe = function(_, _) + -- Mock implementation + end + + vim.schedule = function(callback) + callback() -- Execute immediately for tests + end + + vim.api.nvim_win_is_valid = function(_) + return true + end + + vim.api.nvim_get_option_value = function(_, _) + return 'StatusLine:MyStatusLine' + end + + vim.api.nvim_set_option_value = function(_, _, _) + -- Mock implementation + end + + vim.tbl_contains = function(table, value) + for _, v in ipairs(table) do + if v == value then + return true + end + end + return false + end + + vim.wo = {} + + -- Reset state + state.windows = nil + end) + + after_each(function() + -- Restore original functions + context.delta_context = original_delta_context + context.is_context_enabled = original_is_context_enabled + icons.get = original_get_icon + state.subscribe = original_subscribe + vim.schedule = original_schedule + vim.api.nvim_win_is_valid = original_api_win_is_valid + vim.api.nvim_get_option_value = original_api_get_option_value + vim.api.nvim_set_option_value = original_api_set_option_value + vim.tbl_contains = original_vim_tbl_contains + vim.wo = original_wo + end) + + describe('opencode.ui.context_bar', function() + it('renders minimal winbar with context icon only', function() + local mock_input_win = 2001 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('context'))) + end) + + it('renders winbar with current file when present', function() + mock_context.current_file = { + name = 'test.lua', + path = '/tmp/test.lua', + } + + local mock_input_win = 2002 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('attached_file') .. 'test%.lua')) + end) + + it('renders winbar with multiple context elements', function() + mock_context.current_file = { name = 'main.lua', path = '/src/main.lua' } + mock_context.mentioned_files = { '/file1.lua', '/file2.lua' } + mock_context.mentioned_subagents = { 'agent1' } + mock_context.selections = { { text = 'code' } } + mock_context.cursor_data = { line = 10, col = 5 } + + local mock_input_win = 2003 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('attached_file') .. 'main%.lua')) + assert.is_not_nil(winbar_capture.value:find(icons.get('file') .. '%(2%)')) + assert.is_not_nil(winbar_capture.value:find(icons.get('agent') .. '%(1%)')) + assert.is_not_nil(winbar_capture.value:find('L:10')) -- Cursor data + end) + + it('renders winbar with diagnostics', function() + mock_context.linter_errors = { + { severity = 1 }, -- ERROR + { severity = 1 }, -- ERROR + { severity = 2 }, -- WARN + { severity = 3 }, -- INFO + } + + local mock_input_win = 2004 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('error') .. '%(2%)')) -- 2 errors + assert.is_not_nil(winbar_capture.value:find(icons.get('warning') .. '%(1%)')) -- Warning icon + assert.is_not_nil(winbar_capture.value:find(icons.get('info') .. '%(1%)')) -- Info icon + end) + + it('respects context enabled settings', function() + context.is_context_enabled = function(context_type) + return context_type == 'current_file' -- Only enable current_file + end + + mock_context.current_file = { name = 'test.lua', path = '/test.lua' } + mock_context.mentioned_files = { '/file1.lua' } + mock_context.selections = { { text = 'code' } } + + local mock_input_win = 2005 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('attached_file') .. 'test%.lua')) -- attahced file icon + assert.is_nil(winbar_capture.value:find(icons.get('file') .. '%(1%)')) + assert.is_nil(winbar_capture.value:find(icons.get('selection') .. '%(1%)')) + end) + + it('handles empty winbar gracefully', function() + mock_context = {} -- Empty context + + local mock_input_win = 2006 + local winbar_capture = create_mock_window(mock_input_win) + + state.windows = { input_win = mock_input_win } + context_bar.render() + + assert.is_string(winbar_capture.value) + assert.is_not_nil(winbar_capture.value:find(icons.get('context'))) -- Should still have context icon + end) + + it('does nothing when window is invalid', function() + vim.api.nvim_win_is_valid = function(_) + return false + end + + local mock_input_win = 2007 + local winbar_capture = create_mock_window(mock_input_win) + + context_bar.render({ input_win = mock_input_win }) + assert.is_nil(winbar_capture.set) + end) + + it('uses provided windows parameter', function() + local custom_windows = { input_win = 2008 } + local winbar_capture = create_mock_window(2008) + + context_bar.render(custom_windows) + assert.is_string(winbar_capture.value) + end) + end) + + describe('setup', function() + it('subscribes to state changes', function() + local subscription_called = false + local captured_keys = nil + + state.subscribe = function(keys, callback) + subscription_called = true + captured_keys = keys + assert.is_table(keys) + assert.is_function(callback) + end + + context_bar.setup() + assert.is_true(subscription_called) + assert.is_table(captured_keys) + + local expected_keys = { 'current_context_config', 'current_code_buf', 'opencode_focused', 'context_updated_at' } + for _, expected_key in ipairs(expected_keys) do + local found = false + for _, key in ipairs(captured_keys) do + if key == expected_key then + found = true + break + end + end + assert.is_true(found, 'Expected key not found: ' .. expected_key) + end + end) + end) +end) From d7a38f3623cea531a0545835969eaf7cdae669d8 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 29 Oct 2025 07:24:56 -0400 Subject: [PATCH 22/48] feat(completion): make it work with vim_complete --- lua/opencode/ui/completion/engines/vim_complete.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lua/opencode/ui/completion/engines/vim_complete.lua b/lua/opencode/ui/completion/engines/vim_complete.lua index 3b579525..e11bbdd2 100644 --- a/lua/opencode/ui/completion/engines/vim_complete.lua +++ b/lua/opencode/ui/completion/engines/vim_complete.lua @@ -30,6 +30,7 @@ function M._get_trigger(before_cursor) local config = require('opencode.config') local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') + local context_key = config.get_key_for_function('input_window', 'context_items') local triggers = {} if mention_key then table.insert(triggers, mention_key) @@ -37,6 +38,9 @@ function M._get_trigger(before_cursor) if slash_key then table.insert(triggers, slash_key) end + if context_key then + table.insert(triggers, context_key) + end local trigger_chars = table.concat(vim.tbl_map(vim.pesc, triggers), '') local trigger_char, trigger_match = before_cursor:match('.*([' .. trigger_chars .. '])([%w_%-%.]*)') return trigger_char, trigger_match @@ -88,8 +92,8 @@ function M._update() item.insert_text = item.insert_text:sub(2) end table.insert(items, { - word = item.insert_text, - abbr = item.label, + word = #item.insert_text > 0 and item.insert_text or item.label, + abbr = (item.kind_icon or '') .. item.label, menu = source.name, kind = item.kind:sub(1, 1):upper(), user_data = item, From 27566153fcd67e1bac21c0d36f06c0f16d08c1b0 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 29 Oct 2025 14:52:32 -0400 Subject: [PATCH 23/48] test(context_completion): add tests for context completion --- tests/unit/context_completion_spec.lua | 533 +++++++++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100644 tests/unit/context_completion_spec.lua diff --git a/tests/unit/context_completion_spec.lua b/tests/unit/context_completion_spec.lua new file mode 100644 index 00000000..0a4c5b4c --- /dev/null +++ b/tests/unit/context_completion_spec.lua @@ -0,0 +1,533 @@ +local helpers = require('tests.helpers') +local context_completion = require('opencode.ui.completion.context') + +local function find_item_by_label(items, label) + for _, item in ipairs(items) do + if item.label == label then + return item + end + end + return nil +end + +local function find_item_by_pattern(items, pattern) + for _, item in ipairs(items) do + if item.label:find(pattern, 1, true) then + return item + end + end + return nil +end + +describe('context completion', function() + local mock_config, mock_context, mock_state, mock_icons, mock_input_win + + before_each(function() + mock_config = { + get_key_for_function = function(category, key) + if category == 'input_window' and key == 'context_items' then + return '#' + end + return nil + end, + context = { + current_file = { enabled = true }, + selection = { enabled = true }, + diagnostics = { enabled = false }, + cursor_data = { enabled = false }, + files = { enabled = true }, + agents = { enabled = true }, + }, + } + + mock_context = { + is_context_enabled = function(context_type) + return mock_config.context[context_type] and mock_config.context[context_type].enabled or false + end, + delta_context = function() + return { + current_file = { path = '/test/file.lua', name = 'file.lua', extension = 'lua' }, + mentioned_files = { '/test/other.lua', '/test/helper.js' }, + selections = { + { + file = { name = 'test.lua', extension = 'lua' }, + content = 'local x = 1', + lines = '1-1', + }, + }, + mentioned_subagents = { 'review', 'test' }, + linter_errors = { + { severity = _G.vim.diagnostic.severity.ERROR }, + { severity = _G.vim.diagnostic.severity.WARN }, + }, + cursor_data = { + line = 42, + column = 10, + line_content = 'local test = "hello"', + }, + } + end, + remove_file = function() end, + remove_subagent = function() end, + remove_selection = function() end, + context = { + current_file = { extension = 'lua' }, + }, + } + + mock_state = { + current_context_config = nil, + } + + mock_input_win = { + remove_mention = function() end, + set_current_line = function() end, + } + + package.loaded['opencode.config'] = mock_config + package.loaded['opencode.context'] = mock_context + package.loaded['opencode.state'] = mock_state + package.loaded['opencode.ui.input_window'] = mock_input_win + end) + + after_each(function() + package.loaded['opencode.config'] = nil + package.loaded['opencode.context'] = nil + package.loaded['opencode.state'] = nil + package.loaded['opencode.ui.input_window'] = nil + package.loaded['opencode.ui.completion.context'] = nil + end) + + describe('get_source', function() + it('should return a completion source', function() + local source = context_completion.get_source() + + assert.are.equal('context', source.name) + assert.are.equal(1, source.priority) + assert.is_function(source.complete) + assert.is_function(source.on_complete) + end) + end) + + describe('complete function', function() + local source + + before_each(function() + context_completion = require('opencode.ui.completion.context') + source = context_completion.get_source() + end) + + it('should return empty table when trigger char does not match', function() + local completion_context = { + trigger_char = '/', -- Different from expected '#' + input = '', + } + + local items = source.complete(completion_context) + assert.are.same({}, items) + end) + + it('should return context items when trigger char matches', function() + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + + assert.is_true(#items >= 3) -- current_file, diagnostics, cursor_data + + local current_file_item = find_item_by_label(items, 'Current File') + assert.is_not_nil(current_file_item) + assert.are.equal('context', current_file_item.kind) + assert.are.equal('current_file', current_file_item.data.type) + end) + + it('should include selection items when selections exist', function() + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + + local selection_item = find_item_by_label(items, 'Selection (1)') + assert.is_not_nil(selection_item) + assert.are.equal('selection', selection_item.data.type) + + local selection_detail = find_item_by_pattern(items, 'Selection 1') + assert.is_not_nil(selection_detail) + assert.are.equal('selection_item', selection_detail.data.type) + end) + + it('should include mentioned files when they exist', function() + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + + mock_config.context.files = { enabled = true } + + local items_with_files = source.complete(completion_context) + local mentioned_files = vim.tbl_filter(function(item) + return item.data.type == 'mentioned_file' + end, items_with_files) + + assert.are.equal(2, #mentioned_files) + end) + + it('should include subagent items when they exist', function() + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + + local subagent_items = vim.tbl_filter(function(item) + return item.data.type == 'subagent' + end, items) + + assert.are.equal(2, #subagent_items) + + local review_agent = find_item_by_label(items, 'review (agent)') + assert.is_not_nil(review_agent) + assert.are.equal('subagent', review_agent.data.type) + end) + + it('should filter items based on input', function() + local completion_context = { + trigger_char = '#', + input = 'file', + } + + local items = source.complete(completion_context) + + for _, item in ipairs(items) do + assert.is_true(item.label:lower():find('file', 1, true) ~= nil) + end + end) + + it('should sort items with available items first', function() + mock_context.is_context_enabled = function(type) + return type == 'current_file' + end + + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + + assert.is_true(items[1].data.available) + + local first_unavailable_idx = nil + for i, item in ipairs(items) do + if not item.data.available then + first_unavailable_idx = i + break + end + end + + if first_unavailable_idx then + for i = 1, first_unavailable_idx - 1 do + assert.is_true(items[i].data.available) + end + end + end) + end) + + describe('on_complete function', function() + local source + + before_each(function() + context_completion = require('opencode.ui.completion.context') + source = context_completion.get_source() + + vim.fn = vim.fn or {} + vim.fn.feedkeys = function() end + vim.fn.fnamemodify = function(path, modifier) + if modifier == ':~:.' then + return path:gsub('^/test/', '') + end + return path + end + + vim.api = vim.api or {} + vim.api.nvim_win_get_cursor = function(...) + return { 1, 6 } + end -- Position after '#' + vim.api.nvim_get_current_line = function() + return 'test #content' + end + vim.api.nvim_replace_termcodes = function(str) + return str + end + + vim.schedule = function(fn) + fn() + end + end) + + it('should handle nil item gracefully', function() + assert.has_no.errors(function() + source.on_complete(nil) + end) + end) + + it('should handle item without data gracefully', function() + local item = { label = 'test' } + assert.has_no.errors(function() + source.on_complete(item) + end) + end) + + it('should toggle context enabled state for toggleable items', function() + local item = { + label = 'Current File', + data = { + type = 'current_file', + name = 'Current File', + available = true, + }, + } + + source.on_complete(item) + + local state_module = require('opencode.state') + + assert.is_not_nil(state_module.current_context_config) + assert.is_not_nil(state_module.current_context_config.current_file) + assert.is_false(state_module.current_context_config.current_file.enabled) + end) + + it('should remove mentioned file when selected', function() + local remove_file_called = false + local remove_mention_called = false + + local context_module = require('opencode.context') + local input_win_module = require('opencode.ui.input_window') + + context_module.remove_file = function(name) + remove_file_called = true + assert.are.equal('test.lua', name) + end + + input_win_module.remove_mention = function(name) + remove_mention_called = true + assert.are.equal('test.lua', name) + end + + local item = { + label = 'test.lua', + data = { + type = 'mentioned_file', + name = 'test.lua', + available = true, + }, + } + + source.on_complete(item) + + assert.is_true(remove_file_called) + assert.is_true(remove_mention_called) + end) + + it('should remove subagent when selected', function() + local remove_subagent_called = false + local remove_mention_called = false + + local context_module = require('opencode.context') + local input_win_module = require('opencode.ui.input_window') + + context_module.remove_subagent = function(name) + remove_subagent_called = true + assert.are.equal('review', name) + end + + input_win_module.remove_mention = function(name) + remove_mention_called = true + assert.are.equal('review', name) + end + + local item = { + label = 'review (agent)', + data = { + type = 'subagent', + name = 'review (agent)', + available = true, + }, + } + + source.on_complete(item) + + assert.is_true(remove_subagent_called) + assert.is_true(remove_mention_called) + end) + + it('should remove selection when selection item selected', function() + local remove_selection_called = false + local selection_data = { content = 'test', lines = '1-1' } + + local context_module = require('opencode.context') + + context_module.remove_selection = function(selection) + remove_selection_called = true + assert.are.same(selection_data, selection) + end + + local item = { + label = 'Selection 1', + data = { + type = 'selection_item', + name = 'Selection 1', + available = true, + additional_data = selection_data, + }, + } + + source.on_complete(item) + + assert.is_true(remove_selection_called) + end) + + it('should clean up trigger character from current line', function() + local set_current_line_called = false + + local input_win_module = require('opencode.ui.input_window') + + input_win_module.set_current_line = function(line) + set_current_line_called = true + assert.are.equal('test content', line) + end + + local item = { + label = 'test', + data = { + type = 'current_file', + name = 'test', + available = true, + }, + } + + source.on_complete(item) + + assert.is_true(set_current_line_called) + end) + end) + + describe('formatting functions', function() + it('should format diagnostics correctly', function() + mock_context.is_context_enabled = function(type) + if type == 'diagnostics' then + return true + end + return mock_config.context[type] and mock_config.context[type].enabled or false + end + + local source = require('opencode.ui.completion.context').get_source() + + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + local diagnostics_item = find_item_by_label(items, 'Diagnostics') + + assert.is_not_nil(diagnostics_item) + assert.is_string(diagnostics_item.documentation) + assert.is_true(diagnostics_item.documentation:find('Error') ~= nil) + assert.is_true(diagnostics_item.documentation:find('Warning') ~= nil) + end) + + it('should format cursor data correctly', function() + mock_context.is_context_enabled = function(type) + if type == 'cursor_data' then + return true + end + return mock_config.context[type] and mock_config.context[type].enabled or false + end + + local source = require('opencode.ui.completion.context').get_source() + + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = source.complete(completion_context) + local cursor_item = find_item_by_label(items, 'Cursor Data') + + assert.is_not_nil(cursor_item) + assert.is_string(cursor_item.documentation) + assert.is_true(cursor_item.documentation:find('Line: 42') ~= nil) + assert.is_true(cursor_item.documentation:find('local test = "hello"') ~= nil) + end) + + it('should format selection correctly', function() + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = context_completion.get_source().complete(completion_context) + local selection_detail = find_item_by_pattern(items, 'Selection 1') + + assert.is_not_nil(selection_detail) + assert.is_string(selection_detail.documentation) + assert.is_true(selection_detail.documentation:find('```lua') ~= nil) + assert.is_true(selection_detail.documentation:find('local x = 1') ~= nil) + end) + end) + + describe('edge cases', function() + it('should handle empty context gracefully', function() + mock_context.delta_context = function() + return { + current_file = nil, + mentioned_files = {}, + selections = {}, + mentioned_subagents = {}, + linter_errors = {}, + cursor_data = {}, + } + end + + local completion_context = { + trigger_char = '#', + input = '', + } + + local items = context_completion.get_source().complete(completion_context) + + assert.is_true(#items >= 3) + end) + + it('should handle disabled contexts correctly', function() + local original_is_enabled = mock_context.is_context_enabled + mock_context.is_context_enabled = function() + return false + end + + local completion_context = { + trigger_char = '#', + input = '', + } + + local source = require('opencode.ui.completion.context').get_source() + local items = source.complete(completion_context) + + mock_context.is_context_enabled = original_is_enabled + + for _, item in ipairs(items) do + if vim.tbl_contains({ 'current_file', 'selection', 'diagnostics', 'cursor_data' }, item.data.type) then + assert.is_false(item.data.available) + end + end + end) + end) +end) From 133f74fa13155bc916a398be625842657d049dce Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 29 Oct 2025 15:11:21 -0400 Subject: [PATCH 24/48] feat(selection-context): add better description for selection menu --- lua/opencode/ui/completion/context.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 70b08245..fdefbecb 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -114,7 +114,9 @@ local function add_selection_items(ctx) create_context_item( 'Selection' .. (ctx.selections and #ctx.selections > 0 and string.format(' (%d)', #ctx.selections) or ''), 'selection', - context.is_context_enabled('selection') + context.is_context_enabled('selection'), + ctx.selections and #ctx.selections > 0 and 'Manage your current selections individually' + or 'No selections available.' ), } From 292ce5a97d786d40845d2d430e628b90d97ee416 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 29 Oct 2025 15:28:53 -0400 Subject: [PATCH 25/48] docs(context-bar): add docs for the context-bar/completion --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 43b68960..cf42b931 100644 --- a/README.md +++ b/README.md @@ -427,6 +427,14 @@ The following editor context is automatically captured and included in your conv You can reference files in your project directly in your conversations with Opencode. This is useful when you want to ask about or provide context about specific files. Type `@` in the input window to trigger the file picker. Supported pickers include [`fzf-lua`](https://github.com/ibhagwan/fzf-lua), [`telescope`](https://github.com/nvim-telescope/telescope.nvim), [`mini.pick`](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-pick.md), [`snacks`](https://github.com/folke/snacks.nvim/blob/main/docs/picker.md) +### Context bar + +You can quiclkly see the current context items in the context bar at the top of the input window: + +
+ Opencode.nvim context bar +
+ ### Context Items Completion You can quickly reference available context items by typing `#` in the input window. This will show a completion menu with all available context items: @@ -436,9 +444,17 @@ You can quickly reference available context items by typing `#` in the input win - **Diagnostics** - LSP diagnostics from the current file - **Cursor Data** - Current cursor position and line content - **[filename]** - Files that have been mentioned in the conversation +- **Agents** - Available agents to switch to +- **Selections** - Previously made selections in visual mode Context items that are not currently available will be shown as disabled in the completion menu. +You should also see the list of files agents and selections in the menu, selecting them in the menu will remove them from the context. + +
+ Opencode.nvim context items completion +
+ ## ๐Ÿ”„ Agents Opencode provides two built-in agents and supports custom ones: From ebeea1d2cd215dab6af6276c09a1e0a0b05fb284 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Wed, 29 Oct 2025 15:31:46 -0400 Subject: [PATCH 26/48] fix(highlight): fix highlight for context-bar file --- lua/opencode/ui/context_bar.lua | 2 +- lua/opencode/ui/highlight.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua index c9c0333d..1531c5af 100644 --- a/lua/opencode/ui/context_bar.lua +++ b/lua/opencode/ui/context_bar.lua @@ -77,7 +77,7 @@ local function create_winbar_segments() table.insert(segments, { icon = icons.get('file'), text = '(' .. attached_count .. ')', - highlight = 'OpencodeContext', + highlight = 'OpencodeContextFile', }) end diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index 35df9695..45fc3c45 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -23,8 +23,8 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { bg = '#757575', fg = '#424242', bold = false, default = true }) vim.api.nvim_set_hl(0, 'OpencodeHint', { link = 'Comment', default = true }) vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#F44336', bold = true, default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextFile', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = 'OpencodeContext', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = '@label', default = true }) @@ -51,8 +51,8 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { bg = '#616161', fg = '#CCCCCC', bold = false, default = true }) vim.api.nvim_set_hl(0, 'OpencodeHint', { link = 'Comment', default = true }) vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#EF5350', bold = true, default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContext', { fg = '#3b4261', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextFile', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextCurrentFile', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextAgent', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = '@label', default = true }) From f8163dab49dd171fba5654b0a057fe7d670a2c9d Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 08:55:41 -0400 Subject: [PATCH 27/48] feat(completion): add icons to sources --- lua/opencode/ui/completion/commands.lua | 5 ++--- lua/opencode/ui/completion/files.lua | 2 ++ lua/opencode/ui/icons.lua | 4 ++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lua/opencode/ui/completion/commands.lua b/lua/opencode/ui/completion/commands.lua index 4c6b4092..d77a2b73 100644 --- a/lua/opencode/ui/completion/commands.lua +++ b/lua/opencode/ui/completion/commands.lua @@ -1,3 +1,4 @@ +local icons = require('lua.opencode.ui.icons') local M = {} local function get_available_commands() @@ -24,9 +25,6 @@ local command_source = { name = 'commands', priority = 1, complete = function(context) - local config = require('opencode.config') - local input_text = vim.api.nvim_buf_get_lines(0, 0, -1, false) - if not context.line:match('^' .. vim.pesc(context.trigger_char) .. '[^%s/]*$') then return {} end @@ -49,6 +47,7 @@ local command_source = { local item = { label = command.name .. (command.args and ' *' or ''), kind = 'command', + kind_icon = icons.get('command'), detail = command.description, documentation = command.documentation .. (command.args and '\n\n* This command takes arguments.' or ''), insert_text = command.name, diff --git a/lua/opencode/ui/completion/files.lua b/lua/opencode/ui/completion/files.lua index 85dcbca5..3f4c944a 100644 --- a/lua/opencode/ui/completion/files.lua +++ b/lua/opencode/ui/completion/files.lua @@ -1,4 +1,5 @@ local config = require('opencode.config') +local icons = require('opencode.ui.icons') local M = {} local last_successful_tool = nil @@ -95,6 +96,7 @@ local function create_file_item(file, suffix) return { label = display_label .. (suffix or ''), kind = kind, + kind_icon = icons.get(kind), detail = detail, documentation = 'Path: ' .. detail, insert_text = file_path, diff --git a/lua/opencode/ui/icons.lua b/lua/opencode/ui/icons.lua index faf9a3b5..8535cfd3 100644 --- a/lua/opencode/ui/icons.lua +++ b/lua/opencode/ui/icons.lua @@ -22,6 +22,7 @@ local presets = { snapshot = '๓ฐป› ', restore_point = '๓ฑ—š ', file = '๏…› ', + folder = '๏ป ', attached_file = '๓ฐŒท ', agent = '๓ฐšฉ ', -- statuses @@ -37,6 +38,7 @@ local presets = { warning = '๏ฑ ', info = '๏š ', selection = '๓ฐซ™ ', + command = '๏’‰ ', }, text = { -- headers @@ -56,6 +58,7 @@ local presets = { snapshot = '::', restore_point = '::', file = '@', + folder = '[@]', attached_file = '@', agent = '@', -- statuses @@ -71,6 +74,7 @@ local presets = { warning = '[W]', info = '[I] ', selection = "'<'> ", + command = '::', }, } From 86e4802d89b79b3d5d674b8f89d2cb0b357fd75b Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 09:34:15 -0400 Subject: [PATCH 28/48] feat(completion): rely on kind_icon instead of deducing it --- lua/opencode/ui/completion/engines/blink_cmp.lua | 2 +- lua/opencode/ui/completion/engines/nvim_cmp.lua | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index 1b20d671..7c61e75a 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -59,7 +59,7 @@ function Source:get_completions(ctx, callback) for i, item in ipairs(source_items) do table.insert(items, { label = item.label, - kind = item.kind == 'file' and 17 or item.kind == 'folder' and 19 or 1, -- 17: File, 19: Folder, 1: Text + kind = item.kind, kind_icon = item.kind_icon, detail = item.detail, documentation = item.documentation, diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index 955c88d0..b9922bd7 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -55,9 +55,7 @@ function M.setup(completion_sources) for j, item in ipairs(source_items) do table.insert(items, { label = item.label, - kind = item.kind == 'file' and cmp.lsp.CompletionItemKind.File - or item.kind == 'folder' and cmp.lsp.CompletionItemKind.Folder - or cmp.lsp.CompletionItemKind.Text, + kind = item.kind, cmp = { kind_text = item.kind_icon, }, From 617dd6cb13d7cf7c443eda02021d725607fc75d3 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 11:03:31 -0400 Subject: [PATCH 29/48] feat(completion): better sorting for context items --- lua/opencode/types.lua | 1 + lua/opencode/ui/completion/context.lua | 45 ++++++++++++++----- .../ui/completion/engines/blink_cmp.lua | 11 ++++- .../ui/completion/engines/nvim_cmp.lua | 2 +- .../ui/completion/engines/vim_complete.lua | 9 +++- lua/opencode/ui/completion/files.lua | 7 +-- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index f7d6772f..f5495e3e 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -303,6 +303,7 @@ ---@field documentation string Documentation text ---@field insert_text string Text to insert when selected ---@field source_name string Name of the completion source +---@field priority? number Optional priority for individual item sorting (lower numbers have higher priority) ---@field data table Additional data associated with the item ---@class CompletionSource diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index fdefbecb..e28c3fcd 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -4,6 +4,11 @@ local state = require('opencode.state') local icons = require('opencode.ui.icons') local M = {} +local kind_priority = { + selection_item = 3, + mentioned_file = 4, + subagent = 5, +} ---@generic T ---@param name string @@ -13,7 +18,7 @@ local M = {} ---@param icon string|nil ---@param additional_data? T ---@return CompletionItem -local function create_context_item(name, type, available, documentation, icon, additional_data) +local function create_context_item(name, type, available, documentation, icon, additional_data, priority) local label = name return { @@ -24,6 +29,7 @@ local function create_context_item(name, type, available, documentation, icon, a documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'), insert_text = '', source_name = 'context', + priority = priority or (available and 100 or 200), data = { type = type, name = name, available = available, additional_data = additional_data }, } end @@ -100,7 +106,15 @@ local function add_mentioned_files_items(ctx) local filename = vim.fn.fnamemodify(file, ':~:.') table.insert( items, - create_context_item(filename, 'mentioned_file', true, 'Select to remove file ' .. filename, icons.get('file')) + create_context_item( + filename, + 'mentioned_file', + true, + 'Select to remove file ' .. filename, + icons.get('file'), + nil, + kind_priority.mentioned_file + ) ) end end @@ -125,7 +139,15 @@ local function add_selection_items(ctx) string.format('Selection %d %s (%s)', i, selection.file and selection.file.name or 'Untitled', selection.lines) table.insert( items, - create_context_item(label, 'selection_item', true, format_selection(selection), icons.get('selection'), selection) + create_context_item( + label, + 'selection_item', + true, + format_selection(selection), + icons.get('selection'), + selection, + kind_priority.selection_item + ) ) end return items @@ -141,7 +163,15 @@ local function add_subagents_items(ctx) for _, agent in ipairs(ctx.mentioned_subagents or {}) do table.insert( items, - create_context_item(agent .. ' (agent)', 'subagent', true, 'Select to remove agent ' .. agent, icons.get('agent')) + create_context_item( + agent .. ' (agent)', + 'subagent', + true, + 'Select to remove agent ' .. agent, + icons.get('agent'), + nil, + kind_priority.subagent + ) ) end return items @@ -198,13 +228,6 @@ local context_source = { end, items) end - table.sort(items, function(a, b) - if a.data.available ~= b.data.available then - return a.data.available - end - return a.label < b.label - end) - return items end, on_complete = function(item) diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index 7c61e75a..bd6ade75 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -64,8 +64,15 @@ function Source:get_completions(ctx, callback) detail = item.detail, documentation = item.documentation, insertText = item.insert_text or item.label, - sortText = string.format('%02d_%02d_%s', completion_source.priority or 999, i, item.label), - score_offset = -(completion_source.priority or 999) * 1000, + sortText = string.format( + '%02d_%02d_%02d_%s', + completion_source.priority or 999, + item.priority or 999, + i, + item.label + ), + score_offset = -(completion_source.priority or 999) * 1000 + (item.priority or 999), + data = { original_item = item, }, diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index b9922bd7..faaf6a34 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -62,7 +62,7 @@ function M.setup(completion_sources) detail = item.detail, documentation = item.documentation, insertText = item.insert_text or item.label, - sortText = string.format('%02d_%02d_%s', completion_source.priority or 999, j, item.label), + sortText = string.format('%02d_%02d_%02d_%s', completion_source.priority or 999, item.priority or 999, j, item.label), data = { original_item = item, }, diff --git a/lua/opencode/ui/completion/engines/vim_complete.lua b/lua/opencode/ui/completion/engines/vim_complete.lua index e11bbdd2..27dd6b43 100644 --- a/lua/opencode/ui/completion/engines/vim_complete.lua +++ b/lua/opencode/ui/completion/engines/vim_complete.lua @@ -87,20 +87,27 @@ function M._update() local items = {} for _, source in ipairs(M._completion_sources or {}) do local source_items = source.complete(context) - for _, item in ipairs(source_items) do + for i, item in ipairs(source_items) do if vim.startswith(item.insert_text or '', trigger_char) then item.insert_text = item.insert_text:sub(2) end + local source_priority = source.priority or 999 + local item_priority = item.priority or 999 table.insert(items, { word = #item.insert_text > 0 and item.insert_text or item.label, abbr = (item.kind_icon or '') .. item.label, menu = source.name, kind = item.kind:sub(1, 1):upper(), user_data = item, + _sort_text = string.format('%02d_%02d_%02d_%s', source_priority, item_priority, i, item.label), }) end end + table.sort(items, function(a, b) + return a._sort_text < b._sort_text + end) + if #items > 0 then local start_col = before_cursor:find(vim.pesc(trigger_char) .. '[%w_%-%.]*$') if start_col then diff --git a/lua/opencode/ui/completion/files.lua b/lua/opencode/ui/completion/files.lua index 3f4c944a..c00ab476 100644 --- a/lua/opencode/ui/completion/files.lua +++ b/lua/opencode/ui/completion/files.lua @@ -79,7 +79,7 @@ end ---@param file string ---@return CompletionItem -local function create_file_item(file, suffix) +local function create_file_item(file, suffix, priority) local filename = vim.fn.fnamemodify(file, ':t') local dir = vim.fn.fnamemodify(file, ':h') local file_path = dir == '.' and filename or dir .. '/' .. filename @@ -101,6 +101,7 @@ local function create_file_item(file, suffix) documentation = 'Path: ' .. detail, insert_text = file_path, source_name = 'files', + priority = priority, data = { name = filename, full_path = full_path }, } end @@ -126,7 +127,7 @@ local file_source = { end local files_and_dirs = find_files_fast(input) - local items = vim.tbl_map(create_file_item, files_and_dirs) + local items = vim.tbl_map(function(file) return create_file_item(file, nil, 10) end, files_and_dirs) sort_util.sort_by_relevance(items, input, function(item) return vim.fn.fnamemodify(item.label, ':t') end, function(a, b) @@ -155,7 +156,7 @@ function M.get_recent_files() if result then for _, file in ipairs(result) do local suffix = table.concat({ file.added and '+' .. file.added, file.removed and '-' .. file.removed }, ' ') - table.insert(recent_files, create_file_item(file.path, ' ' .. suffix)) + table.insert(recent_files, create_file_item(file.path, ' ' .. suffix, 1)) end end return recent_files From 64baa573514602e24266c73536ef12c479ae64c8 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 11:42:44 -0400 Subject: [PATCH 30/48] fix(completion): fix wrong icons import --- lua/opencode/ui/completion/commands.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/opencode/ui/completion/commands.lua b/lua/opencode/ui/completion/commands.lua index d77a2b73..33fabbc5 100644 --- a/lua/opencode/ui/completion/commands.lua +++ b/lua/opencode/ui/completion/commands.lua @@ -1,4 +1,3 @@ -local icons = require('lua.opencode.ui.icons') local M = {} local function get_available_commands() @@ -25,6 +24,7 @@ local command_source = { name = 'commands', priority = 1, complete = function(context) + local icons = require('opencode.ui.icons') if not context.line:match('^' .. vim.pesc(context.trigger_char) .. '[^%s/]*$') then return {} end From 79c0519c19c3648500f6310d2a6b09caf5f9a650 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 11:43:34 -0400 Subject: [PATCH 31/48] feat(completion): add context trigger to nvim_cmp engine --- lua/opencode/ui/completion/engines/nvim_cmp.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index faaf6a34..c9905942 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -15,6 +15,7 @@ function M.setup(completion_sources) local config = require('opencode.config') local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') + local context_key = config.get_key_for_function('input_window', 'context_items') local triggers = {} if mention_key then table.insert(triggers, mention_key) @@ -22,6 +23,9 @@ function M.setup(completion_sources) if slash_key then table.insert(triggers, slash_key) end + if context_key then + table.insert(triggers, context_key) + end return triggers end @@ -55,14 +59,20 @@ function M.setup(completion_sources) for j, item in ipairs(source_items) do table.insert(items, { label = item.label, - kind = item.kind, + kind = 1, cmp = { kind_text = item.kind_icon, }, detail = item.detail, documentation = item.documentation, - insertText = item.insert_text or item.label, - sortText = string.format('%02d_%02d_%02d_%s', completion_source.priority or 999, item.priority or 999, j, item.label), + insertText = item.insert_text or '', + sortText = string.format( + '%02d_%02d_%02d_%s', + completion_source.priority or 999, + item.priority or 999, + j, + item.label + ), data = { original_item = item, }, From 504255c6e0f51d16b6cbc56436657cdd709469d1 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 11:47:46 -0400 Subject: [PATCH 32/48] fix(completion): remove text/trigger after context completion --- lua/opencode/ui/completion/context.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index e28c3fcd..3b6a02f6 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -260,17 +260,27 @@ local context_source = { context.remove_selection(item.data.additional_data --[[@as OpencodeContextSelection]]) end + -- Remove the inserted completion text from the input buffer vim.schedule(function() vim.fn.feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n') local _, col = unpack(vim.api.nvim_win_get_cursor(0)) local line = vim.api.nvim_get_current_line() local key = config.get_key_for_function('input_window', 'context_items') - if col > 0 and line:sub(col, col) == key then + + local completion_text = key .. (item.label or item.insert_text or '') + local text_start = col - #completion_text + + if text_start >= 0 and line:sub(text_start + 1, col) == completion_text then + line = line:sub(1, text_start) .. line:sub(col + 1) + input_win.set_current_line(line) + vim.api.nvim_win_set_cursor(0, { vim.api.nvim_win_get_cursor(0)[1], text_start }) + elseif col > 0 and line:sub(col, col) == key then line = line:sub(1, col - 1) .. line:sub(col + 1) input_win.set_current_line(line) - vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') end + + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') end) end, } From 8d8849ad2c82c5e4b2ae3d07edbe7e0fb0fd4041 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 12:44:52 -0400 Subject: [PATCH 33/48] chore(completion): general cleanup --- lua/opencode/context.lua | 2 +- lua/opencode/ui/completion/context.lua | 46 +++++++++++-------- .../ui/completion/engines/blink_cmp.lua | 15 ++---- .../ui/completion/engines/nvim_cmp.lua | 16 ++----- .../ui/completion/engines/vim_complete.lua | 15 ++---- 5 files changed, 42 insertions(+), 52 deletions(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 719cc804..201c6d90 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -1,7 +1,7 @@ -- Gathers editor context local util = require('opencode.util') -local config = require('opencode.config') +local config = require('opencode.config') --[[@as OpencodeConfig]] local state = require('opencode.state') local M = {} diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index 3b6a02f6..c04fd0fc 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -199,6 +199,31 @@ local function add_cursor_data_item(ctx) ) end +--- Remove the inserted completion text from the input buffer +---@param item CompletionItem +local function remove_inserted_text(item) + local input_win = require('opencode.ui.input_window') + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n') + + local _, col = unpack(vim.api.nvim_win_get_cursor(0)) + local line = vim.api.nvim_get_current_line() + local key = config.get_key_for_function('input_window', 'context_items') + + local completion_text = key .. (item.label or item.insert_text or '') + local text_start = col - #completion_text + + if text_start >= 0 and line:sub(text_start + 1, col) == completion_text then + line = line:sub(1, text_start) .. line:sub(col + 1) + input_win.set_current_line(line) + vim.api.nvim_win_set_cursor(0, { vim.api.nvim_win_get_cursor(0)[1], text_start }) + elseif col > 0 and line:sub(col, col) == key then + line = line:sub(1, col - 1) .. line:sub(col + 1) + input_win.set_current_line(line) + end + + vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') +end + ---@type CompletionSource local context_source = { name = 'context', @@ -260,27 +285,8 @@ local context_source = { context.remove_selection(item.data.additional_data --[[@as OpencodeContextSelection]]) end - -- Remove the inserted completion text from the input buffer vim.schedule(function() - vim.fn.feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'n') - - local _, col = unpack(vim.api.nvim_win_get_cursor(0)) - local line = vim.api.nvim_get_current_line() - local key = config.get_key_for_function('input_window', 'context_items') - - local completion_text = key .. (item.label or item.insert_text or '') - local text_start = col - #completion_text - - if text_start >= 0 and line:sub(text_start + 1, col) == completion_text then - line = line:sub(1, text_start) .. line:sub(col + 1) - input_win.set_current_line(line) - vim.api.nvim_win_set_cursor(0, { vim.api.nvim_win_get_cursor(0)[1], text_start }) - elseif col > 0 and line:sub(col, col) == key then - line = line:sub(1, col - 1) .. line:sub(col + 1) - input_win.set_current_line(line) - end - - vim.fn.feedkeys(vim.api.nvim_replace_termcodes('a', true, false, true), 'n') + remove_inserted_text(item) end) end, } diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index bd6ade75..9a8d3b94 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -14,16 +14,11 @@ function Source:get_trigger_characters() local slash_key = config.get_key_for_function('input_window', 'slash_commands') local context_key = config.get_key_for_function('input_window', 'context_items') local triggers = {} - if mention_key then - table.insert(triggers, mention_key) - end - if slash_key then - table.insert(triggers, slash_key) - end - if context_key then - table.insert(triggers, context_key) - end - return triggers + return { + slash_key or '', + mention_key or '', + context_key or '', + } end function Source:is_available() diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index c9905942..b3fa34b3 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -16,17 +16,11 @@ function M.setup(completion_sources) local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') local context_key = config.get_key_for_function('input_window', 'context_items') - local triggers = {} - if mention_key then - table.insert(triggers, mention_key) - end - if slash_key then - table.insert(triggers, slash_key) - end - if context_key then - table.insert(triggers, context_key) - end - return triggers + return { + slash_key or '', + mention_key or '', + context_key or '', + } end function source:is_available() diff --git a/lua/opencode/ui/completion/engines/vim_complete.lua b/lua/opencode/ui/completion/engines/vim_complete.lua index 27dd6b43..4bdcbcde 100644 --- a/lua/opencode/ui/completion/engines/vim_complete.lua +++ b/lua/opencode/ui/completion/engines/vim_complete.lua @@ -31,16 +31,11 @@ function M._get_trigger(before_cursor) local mention_key = config.get_key_for_function('input_window', 'mention') local slash_key = config.get_key_for_function('input_window', 'slash_commands') local context_key = config.get_key_for_function('input_window', 'context_items') - local triggers = {} - if mention_key then - table.insert(triggers, mention_key) - end - if slash_key then - table.insert(triggers, slash_key) - end - if context_key then - table.insert(triggers, context_key) - end + local triggers = { + slash_key or '', + mention_key or '', + context_key or '', + } local trigger_chars = table.concat(vim.tbl_map(vim.pesc, triggers), '') local trigger_char, trigger_match = before_cursor:match('.*([' .. trigger_chars .. '])([%w_%-%.]*)') return trigger_char, trigger_match From eef92b84705ea8c01f40d584028858e634b1f492 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 12:59:59 -0400 Subject: [PATCH 34/48] fix(context): add actual line content in cursor_data --- lua/opencode/context.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 201c6d90..e8d4e02e 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -347,7 +347,12 @@ end local function format_cursor_data_part(cursor_data) return { type = 'text', - text = vim.json.encode({ context_type = 'cursor-data', line = cursor_data.line, column = cursor_data.column }), + text = vim.json.encode({ + context_type = 'cursor-data', + line = cursor_data.line, + column = cursor_data.column, + line_content = cursor_data.line_content, + }), synthetic = true, } end From 828ba0e7841f495d5428a76a0497a861cb5e9be3 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 13:48:18 -0400 Subject: [PATCH 35/48] feat(context): display cursor_data with the user prompt --- lua/opencode/context.lua | 6 ++++-- lua/opencode/core.lua | 5 ++--- lua/opencode/ui/formatter.lua | 18 ++++++++++++++++++ tests/data/cursor_data.expected.json | 1 + tests/data/cursor_data.json | 1 + 5 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tests/data/cursor_data.expected.json create mode 100644 tests/data/cursor_data.json diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index e8d4e02e..fd0da2ea 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -259,7 +259,7 @@ function M.get_current_cursor_data(buf, win) local cursor_pos = vim.fn.getcurpos(win) local cursor_content = vim.trim(vim.api.nvim_buf_get_lines(buf, cursor_pos[2] - 1, cursor_pos[2], false)[1] or '') - return { line = cursor_pos[2], col = cursor_pos[3], line_content = cursor_content } + return { line = cursor_pos[2], column = cursor_pos[3], line_content = cursor_content } end function M.get_current_selection() @@ -345,13 +345,15 @@ local function format_diagnostics_part(diagnostics) end local function format_cursor_data_part(cursor_data) + local buf = (M.get_current_buf() or 0) --[[@as integer]] + local lang = util.get_markdown_filetype(vim.api.nvim_buf_get_name(buf)) or '' return { type = 'text', text = vim.json.encode({ context_type = 'cursor-data', line = cursor_data.line, column = cursor_data.column, - line_content = cursor_data.line_content, + line_content = string.format('`````%s\n%s\n`````', lang, cursor_data.line_content), }), synthetic = true, } diff --git a/lua/opencode/core.lua b/lua/opencode/core.lua index a22c7161..c4a8bc2c 100644 --- a/lua/opencode/core.lua +++ b/lua/opencode/core.lua @@ -94,7 +94,6 @@ end --- @param prompt string The message prompt to send. --- @param opts? SendMessageOpts function M.send_message(prompt, opts) - -- Check if prompt is allowed local mentioned_files = context.context.mentioned_files or {} local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files) @@ -121,8 +120,9 @@ function M.send_message(prompt, opts) state.current_mode = opts.agent end - params.parts = context.format_message(prompt, opts.context) state.current_context_config = opts.context + context.load() + params.parts = context.format_message(prompt, opts.context) M.before_run(opts) @@ -172,7 +172,6 @@ function M.before_run(opts) local is_new_session = opts and opts.new_session or not state.active_session opts = opts or {} - M.open({ new_session = is_new_session, }) diff --git a/lua/opencode/ui/formatter.lua b/lua/opencode/ui/formatter.lua index 578944ad..d0057556 100644 --- a/lua/opencode/ui/formatter.lua +++ b/lua/opencode/ui/formatter.lua @@ -373,6 +373,23 @@ function M._format_selection_context(output, part) M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3) end +---@param output Output Output object to write to +---@param part OpencodeMessagePart +function M._format_cursor_data_context(output, part) + local json = context_module.decode_json_context(part.text, 'cursor-data') + if not json then + return + end + local start_line = output:get_line_count() + output:add_line('Line ' .. json.line .. ':') + output:add_lines(vim.split(json.line_content or '', '\n')) + output:add_empty_line() + + local end_line = output:get_line_count() + + M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3) +end + ---Format and display the file path in the context ---@param output Output Output object to write to ---@param path string|nil File path @@ -709,6 +726,7 @@ function M.format_part(part, message, is_last_part) if part.type == 'text' and part.text then if part.synthetic == true then M._format_selection_context(output, part) + M._format_cursor_data_context(output, part) else M._format_user_prompt(output, vim.trim(part.text), message) content_added = true diff --git a/tests/data/cursor_data.expected.json b/tests/data/cursor_data.expected.json new file mode 100644 index 00000000..6dd2de85 --- /dev/null +++ b/tests/data/cursor_data.expected.json @@ -0,0 +1 @@ +{"extmarks":[[1,2,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":10,"virt_text":[["โ–Œ๓ฐญป ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-10-30 17:42:54)","OpencodeHint"],[" [msg_a3637244a001FDRDfoBYVPEGpd]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text_win_col":-3}],[2,3,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[3,4,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[4,5,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[5,6,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[6,7,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[7,8,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[8,9,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[9,10,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[10,11,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[11,12,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":4096,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":true,"virt_text_win_col":-3}],[12,14,0,{"virt_text_hide":false,"ns_id":3,"right_gravity":true,"priority":10,"virt_text":[["๎ธ ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-5-mini","OpencodeHint"],[" (2025-10-30 17:42:56)","OpencodeHint"],[" [msg_a36372b9a001M1lQEix4SK5QE5]","OpencodeHint"]],"virt_text_pos":"win_col","virt_text_repeat_linebreak":false,"virt_text_win_col":-3}]],"actions":[],"lines":["","----","","","what is this doing","","[lua/opencode/context.lua](lua/opencode/context.lua)","","Line 59:","`````lua","local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')","`````","","----","","","**Explanation**","","- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.","- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.","- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:"," - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned."," - Otherwise the `is_enabled` value (from `config`) is returned.","- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.","- Why this matters: `vim.tbl_get` provides safe nested access; using it avoids runtime errors when some parts of the nested config are absent.",""],"timestamp":1761846231} \ No newline at end of file diff --git a/tests/data/cursor_data.json b/tests/data/cursor_data.json new file mode 100644 index 00000000..79b99f71 --- /dev/null +++ b/tests/data/cursor_data.json @@ -0,0 +1 @@ +[{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"time":{"created":1761846174794},"id":"msg_a3637244a001FDRDfoBYVPEGpd","role":"user","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a3637244a001FDRDfoBYVPEGpd","text":"what is this doing","id":"prt_a3637244b0011ts76CwACOFqk7","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a3637244a001FDRDfoBYVPEGpd","synthetic":true,"text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/context.lua\"}","id":"prt_a3637244e0015gCGQiQq5R8bn0","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a3637244a001FDRDfoBYVPEGpd","synthetic":true,"text":"\n00001| -- Gathers editor context\n00002| \n00003| local util = require('opencode.util')\n00004| local config = require('opencode.config') --[[@as OpencodeConfig]]\n00005| local state = require('opencode.state')\n00006| \n00007| local M = {}\n00008| \n00009| ---@type OpencodeContext\n00010| M.context = {\n00011| -- current file\n00012| current_file = nil,\n00013| cursor_data = nil,\n00014| \n00015| -- attachments\n00016| mentioned_files = nil,\n00017| selections = {},\n00018| linter_errors = {},\n00019| mentioned_subagents = {},\n00020| }\n00021| \n00022| function M.unload_attachments()\n00023| M.context.mentioned_files = nil\n00024| M.context.selections = nil\n00025| M.context.linter_errors = nil\n00026| end\n00027| \n00028| function M.get_current_buf()\n00029| local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf()\n00030| if util.is_buf_a_file(curr_buf) then\n00031| return curr_buf, state.last_code_win_before_opencode or vim.api.nvim_get_current_win()\n00032| end\n00033| end\n00034| \n00035| function M.load()\n00036| local buf, win = M.get_current_buf()\n00037| \n00038| if buf then\n00039| local current_file = M.get_current_file(buf)\n00040| local cursor_data = M.get_current_cursor_data(buf, win)\n00041| \n00042| M.context.current_file = current_file\n00043| M.context.cursor_data = cursor_data\n00044| M.context.linter_errors = M.get_diagnostics(buf)\n00045| end\n00046| \n00047| local current_selection = M.get_current_selection()\n00048| if current_selection then\n00049| local selection = M.new_selection(M.context.current_file, current_selection.text, current_selection.lines)\n00050| M.add_selection(selection)\n00051| end\n00052| state.context_updated_at = vim.uv.now()\n00053| end\n00054| \n00055| -- Checks if a context feature is enabled in config or state\n00056| ---@param context_key string\n00057| ---@return boolean\n00058| function M.is_context_enabled(context_key)\n00059| local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')\n00060| local is_state_enabled = vim.tbl_get(state, 'current_context_config', context_key, 'enabled')\n00061| \n00062| if is_state_enabled ~= nil then\n00063| return is_state_enabled\n00064| else\n00065| return is_enabled\n00066| end\n00067| end\n00068| \n00069| function M.get_diagnostics(buf)\n00070| if not M.is_context_enabled('diagnostics') then\n00071| return nil\n00072| end\n00073| \n00074| local diagnostic_conf = config.context and state.current_context_config.diagnostics or config.context.diagnostics\n00075| \n00076| local severity_levels = {}\n00077| if diagnostic_conf.error then\n00078| table.insert(severity_levels, vim.diagnostic.severity.ERROR)\n00079| end\n00080| if diagnostic_conf.warning then\n00081| table.insert(severity_levels, vim.diagnostic.severity.WARN)\n00082| end\n00083| if diagnostic_conf.info then\n00084| table.insert(severity_levels, vim.diagnostic.severity.INFO)\n00085| end\n00086| \n00087| local diagnostics = vim.diagnostic.get(buf, { severity = severity_levels })\n00088| if #diagnostics == 0 then\n00089| return {}\n00090| end\n00091| \n00092| return diagnostics\n00093| end\n00094| \n00095| function M.new_selection(file, content, lines)\n00096| return {\n00097| file = file,\n00098| content = util.indent_code_block(content),\n00099| lines = lines,\n00100| }\n00101| end\n00102| \n00103| function M.add_selection(selection)\n00104| if not M.context.selections then\n00105| M.context.selections = {}\n00106| end\n00107| \n00108| table.insert(M.context.selections, selection)\n00109| \n00110| state.context_updated_at = vim.uv.now()\n00111| end\n00112| \n00113| function M.remove_selection(selection)\n00114| if not M.context.selections then\n00115| return\n00116| end\n00117| \n00118| for i, sel in ipairs(M.context.selections) do\n00119| if sel.file.path == selection.file.path and sel.lines == selection.lines then\n00120| table.remove(M.context.selections, i)\n00121| break\n00122| end\n00123| end\n00124| state.context_updated_at = vim.uv.now()\n00125| end\n00126| \n00127| function M.clear_selections()\n00128| M.context.selections = nil\n00129| end\n00130| \n00131| function M.add_file(file)\n00132| if not M.context.mentioned_files then\n00133| M.context.mentioned_files = {}\n00134| end\n00135| \n00136| local is_file = vim.fn.filereadable(file) == 1\n00137| local is_dir = vim.fn.isdirectory(file) == 1\n00138| if not is_file and not is_dir then\n00139| vim.notify('File not added to context. Could not read.')\n00140| return\n00141| end\n00142| \n00143| file = vim.fn.fnamemodify(file, ':p')\n00144| \n00145| if not vim.tbl_contains(M.context.mentioned_files, file) then\n00146| table.insert(M.context.mentioned_files, file)\n00147| end\n00148| end\n00149| \n00150| function M.remove_file(file)\n00151| file = vim.fn.fnamemodify(file, ':p')\n00152| if not M.context.mentioned_files then\n00153| return\n00154| end\n00155| \n00156| for i, f in ipairs(M.context.mentioned_files) do\n00157| if f == file then\n00158| table.remove(M.context.mentioned_files, i)\n00159| break\n00160| end\n00161| end\n00162| state.context_updated_at = vim.uv.now()\n00163| end\n00164| \n00165| function M.clear_files()\n00166| M.context.mentioned_files = nil\n00167| end\n00168| \n00169| function M.add_subagent(subagent)\n00170| if not M.context.mentioned_subagents then\n00171| M.context.mentioned_subagents = {}\n00172| end\n00173| \n00174| if not vim.tbl_contains(M.context.mentioned_subagents, subagent) then\n00175| table.insert(M.context.mentioned_subagents, subagent)\n00176| end\n00177| state.context_updated_at = vim.uv.now()\n00178| end\n00179| \n00180| function M.remove_subagent(subagent)\n00181| if not M.context.mentioned_subagents then\n00182| return\n00183| end\n00184| \n00185| for i, a in ipairs(M.context.mentioned_subagents) do\n00186| if a == subagent then\n00187| table.remove(M.context.mentioned_subagents, i)\n00188| break\n00189| end\n00190| end\n00191| state.context_updated_at = vim.uv.now()\n00192| end\n00193| \n00194| function M.clear_subagents()\n00195| M.context.mentioned_subagents = nil\n00196| end\n00197| \n00198| ---@param opts? OpencodeContextConfig\n00199| ---@return OpencodeContext\n00200| function M.delta_context(opts)\n00201| opts = opts or config.context\n00202| if opts.enabled == false then\n00203| return {\n00204| current_file = nil,\n00205| mentioned_files = nil,\n00206| selections = nil,\n00207| linter_errors = nil,\n00208| cursor_data = nil,\n00209| mentioned_subagents = nil,\n00210| }\n00211| end\n00212| \n00213| local context = vim.deepcopy(M.context)\n00214| local last_context = state.last_sent_context\n00215| if not last_context then\n00216| return context\n00217| end\n00218| \n00219| -- no need to send file context again\n00220| if\n00221| context.current_file\n00222| and last_context.current_file\n00223| and context.current_file.name == last_context.current_file.name\n00224| then\n00225| context.current_file = nil\n00226| end\n00227| \n00228| -- no need to send subagents again\n00229| if\n00230| context.mentioned_subagents\n00231| and last_context.mentioned_subagents\n00232| and vim.deep_equal(context.mentioned_subagents, last_context.mentioned_subagents)\n00233| then\n00234| context.mentioned_subagents = nil\n00235| end\n00236| \n00237| return context\n00238| end\n00239| \n00240| function M.get_current_file(buf)\n00241| if not M.is_context_enabled('current_file') then\n00242| return nil\n00243| end\n00244| local file = vim.api.nvim_buf_get_name(buf)\n00245| if not file or file == '' or vim.fn.filereadable(file) ~= 1 then\n00246| return nil\n00247| end\n00248| return {\n00249| path = file,\n00250| name = vim.fn.fnamemodify(file, ':t'),\n00251| extension = vim.fn.fnamemodify(file, ':e'),\n00252| }\n00253| end\n00254| \n00255| function M.get_current_cursor_data(buf, win)\n00256| if not M.is_context_enabled('cursor_data') then\n00257| return nil\n00258| end\n00259| \n00260| local cursor_pos = vim.fn.getcurpos(win)\n00261| local cursor_content = vim.trim(vim.api.nvim_buf_get_lines(buf, cursor_pos[2] - 1, cursor_pos[2], false)[1] or '')\n00262| return { line = cursor_pos[2], column = cursor_pos[3], line_content = cursor_content }\n00263| end\n00264| \n00265| function M.get_current_selection()\n00266| if not M.is_context_enabled('selection') then\n00267| return nil\n00268| end\n00269| \n00270| -- Return nil if not in a visual mode\n00271| if not vim.fn.mode():match('[vV\\022]') then\n00272| return nil\n00273| end\n00274| \n00275| -- Save current position and register state\n00276| local current_pos = vim.fn.getpos('.')\n00277| local old_reg = vim.fn.getreg('x')\n00278| local old_regtype = vim.fn.getregtype('x')\n00279| \n00280| -- Capture selection text and position\n00281| vim.cmd('normal! \"xy')\n00282| local text = vim.fn.getreg('x')\n00283| \n00284| -- Get line numbers\n00285| vim.cmd('normal! `<')\n00286| local start_line = vim.fn.line('.')\n00287| vim.cmd('normal! `>')\n00288| local end_line = vim.fn.line('.')\n00289| \n00290| -- Restore state\n00291| vim.fn.setreg('x', old_reg, old_regtype)\n00292| vim.cmd('normal! gv')\n00293| vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('', true, false, true), 'nx', true)\n00294| vim.fn.setpos('.', current_pos)\n00295| \n00296| if not text or text == '' then\n00297| return nil\n00298| end\n00299| \n00300| return {\n00301| text = text and text:match('[^%s]') and text or nil,\n00302| lines = start_line .. ', ' .. end_line,\n00303| }\n00304| end\n00305| \n00306| local function format_file_part(path, prompt)\n00307| local rel_path = vim.fn.fnamemodify(path, ':~:.')\n00308| local mention = '@' .. rel_path\n00309| local pos = prompt and prompt:find(mention)\n00310| pos = pos and pos - 1 or 0 -- convert to 0-based index\n00311| \n00312| local file_part = { filename = rel_path, type = 'file', mime = 'text/plain', url = 'file://' .. path }\n00313| if prompt then\n00314| file_part.source = {\n00315| path = path,\n00316| type = 'file',\n00317| text = { start = pos, value = mention, ['end'] = pos + #mention },\n00318| }\n00319| end\n00320| return file_part\n00321| end\n00322| \n00323| ---@param selection OpencodeContextSelection\n00324| local function format_selection_part(selection)\n00325| local lang = util.get_markdown_filetype(selection.file and selection.file.name or '') or ''\n00326| \n00327| return {\n00328| type = 'text',\n00329| text = vim.json.encode({\n00330| context_type = 'selection',\n00331| file = selection.file,\n00332| content = string.format('`````%s\\n%s\\n`````', lang, selection.content),\n00333| lines = selection.lines,\n00334| }),\n00335| synthetic = true,\n00336| }\n00337| end\n00338| \n00339| local function format_diagnostics_part(diagnostics)\n00340| return {\n00341| type = 'text',\n00342| text = vim.json.encode({ context_type = 'diagnostics', content = diagnostics }),\n00343| synthetic = true,\n00344| }\n00345| end\n00346| \n00347| local function format_cursor_data_part(cursor_data)\n00348| local buf = (M.get_current_buf() or 0) --[[@as integer]]\n00349| local lang = util.get_markdown_filetype(vim.api.nvim_buf_get_name(buf)) or ''\n00350| return {\n00351| type = 'text',\n00352| text = vim.json.encode({\n00353| context_type = 'cursor-data',\n00354| line = cursor_data.line,\n00355| column = cursor_data.column,\n00356| line_content = string.format('`````%s\\n%s\\n`````', lang, cursor_data.line_content),\n00357| }),\n00358| synthetic = true,\n00359| }\n00360| end\n00361| \n00362| local function format_subagents_part(agent, prompt)\n00363| local mention = '@' .. agent\n00364| local pos = prompt:find(mention)\n00365| pos = pos and pos - 1 or 0 -- convert to 0-based index\n00366| \n00367| return {\n00368| type = 'agent',\n00369| name = agent,\n00370| source = { value = mention, start = pos, ['end'] = pos + #mention },\n00371| }\n00372| end\n00373| \n00374| --- Formats a prompt and context into message with parts for the opencode API\n00375| ---@param prompt string\n00376| ---@param opts? OpencodeContextConfig|nil\n00377| ---@return OpencodeMessagePart[]\n00378| function M.format_message(prompt, opts)\n00379| opts = opts or config.context\n00380| local context = M.delta_context(opts)\n00381| context.prompt = prompt\n00382| \n00383| local parts = { { type = 'text', text = prompt } }\n00384| \n00385| for _, path in ipairs(context.mentioned_files or {}) do\n00386| -- don't resend current file if it's also mentioned\n00387| if not context.current_file or path ~= context.current_file.path then\n00388| table.insert(parts, format_file_part(path, prompt))\n00389| end\n00390| end\n00391| \n00392| for _, sel in ipairs(context.selections or {}) do\n00393| table.insert(parts, format_selection_part(sel))\n00394| end\n00395| \n00396| for _, agent in ipairs(context.mentioned_subagents or {}) do\n00397| table.insert(parts, format_subagents_part(agent, prompt))\n00398| end\n00399| \n00400| if context.current_file then\n00401| table.insert(parts, format_file_part(context.current_file.path))\n00402| end\n00403| \n00404| if context.linter_errors then\n00405| table.insert(parts, format_diagnostics_part(context.linter_errors))\n00406| end\n00407| \n00408| if context.cursor_data then\n00409| table.insert(parts, format_cursor_data_part(context.cursor_data))\n00410| end\n00411| \n00412| return parts\n00413| end\n00414| \n00415| ---@param text string\n00416| ---@param context_type string|nil\n00417| function M.decode_json_context(text, context_type)\n00418| local ok, result = pcall(vim.json.decode, text)\n00419| if not ok or (context_type and result.context_type ~= context_type) then\n00420| return nil\n00421| end\n00422| return result\n00423| end\n00424| \n00425| --- Extracts context from an OpencodeMessage (with parts)\n00426| ---@param message { parts: OpencodeMessagePart[] }\n00427| ---@return { prompt: string, selected_text: string|nil, current_file: string|nil, mentioned_files: string[]|nil}\n00428| function M.extract_from_opencode_message(message)\n00429| local ctx = { prompt = nil, selected_text = nil, current_file = nil }\n00430| \n00431| local handlers = {\n00432| text = function(part)\n00433| ctx.prompt = ctx.prompt or part.text or ''\n00434| end,\n00435| text_context = function(part)\n00436| local json = M.decode_json_context(part.text, 'selection')\n00437| ctx.selected_text = json and json.content or ctx.selected_text\n00438| end,\n00439| file = function(part)\n00440| if not part.source then\n00441| ctx.current_file = part.filename\n00442| end\n00443| end,\n00444| }\n00445| \n00446| for _, part in ipairs(message and message.parts or {}) do\n00447| local handler = handlers[part.type .. (part.synthetic and '_context' or '')]\n00448| if handler then\n00449| handler(part)\n00450| end\n00451| \n00452| if ctx.prompt and ctx.selected_text and ctx.current_file then\n00453| break\n00454| end\n00455| end\n00456| \n00457| return ctx\n00458| end\n00459| \n00460| function M.extract_from_message_legacy(text)\n00461| local current_file = M.extract_legacy_tag('current-file', text)\n00462| local context = {\n00463| prompt = M.extract_legacy_tag('user-query', text) or text,\n00464| selected_text = M.extract_legacy_tag('manually-added-selection', text),\n00465| current_file = current_file and current_file:match('Path: (.+)') or nil,\n00466| }\n00467| return context\n00468| end\n00469| \n00470| function M.extract_legacy_tag(tag, text)\n00471| local start_tag = '<' .. tag .. '>'\n00472| local end_tag = ''\n00473| \n00474| local pattern = vim.pesc(start_tag) .. '(.-)' .. vim.pesc(end_tag)\n00475| local content = text:match(pattern)\n00476| \n00477| if content then\n00478| return vim.trim(content)\n00479| end\n00480| \n00481| -- Fallback to the original method if pattern matching fails\n00482| local query_start = text:find(start_tag)\n00483| local query_end = text:find(end_tag)\n00484| \n00485| if query_start and query_end then\n00486| local query_content = text:sub(query_start + #start_tag, query_end - 1)\n00487| return vim.trim(query_content)\n00488| end\n00489| \n00490| return nil\n00491| end\n00492| \n00493| function M.setup()\n00494| state.subscribe({ 'current_code_buf', 'current_context_config', 'is_opencode_focused' }, function(a)\n00495| M.load()\n00496| end)\n00497| \n00498| vim.api.nvim_create_autocmd('BufWritePost', {\n00499| pattern = '*',\n00500| callback = function(args)\n00501| local buf = args.buf\n00502| local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf()\n00503| if buf == curr_buf and util.is_buf_a_file(buf) then\n00504| M.load()\n00505| end\n00506| end,\n00507| })\n00508| \n00509| vim.api.nvim_create_autocmd('DiagnosticChanged', {\n00510| pattern = '*',\n00511| callback = function(args)\n00512| local buf = args.buf\n00513| local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf()\n00514| if buf == curr_buf and util.is_buf_a_file(buf) and M.is_context_enabled('diagnostics') then\n00515| M.load()\n00516| end\n00517| end,\n00518| })\n00519| end\n00520| \n00521| return M\n00522| \n","id":"prt_a3637244e0025IN5Ze5THoeXcU","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"file","url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/context.lua","messageID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"prt_a3637244e003lil8R9cdkNVRup","mime":"text/plain","filename":"lua/opencode/context.lua","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a3637244a001FDRDfoBYVPEGpd","synthetic":true,"text":"{\"column\":1,\"line_content\":\"`````lua\\nlocal is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')\\n`````\",\"context_type\":\"cursor-data\",\"line\":59}","id":"prt_a3637244b002S0euEXp3CXpwDw","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"session.updated","properties":{"info":{"version":"0.15.20","directory":"/home/francis/Projects/_nvim/opencode.nvim","title":"New session - 2025-10-30T17:42:54.734Z","time":{"created":1761846174734,"updated":1761846174807},"id":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","projectID":"29d43526f88157cd4edd071b899dd01f240b771b"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"assistant","time":{"created":1761846176666},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","mode":"build","parentID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"msg_a36372b9a001M1lQEix4SK5QE5","modelID":"gpt-5-mini","providerID":"github-copilot","cost":0,"tokens":{"output":0,"input":0,"reasoning":0,"cache":{"write":0,"read":0}},"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n# AGENTS.md spec\n- Repos often contain AGENTS.md files. These files can appear anywhere within the repository.\n- These files are a way for humans to give you (the agent) instructions or tips for working within the container.\n- Some examples might be: coding conventions, info about how code is organized, or instructions for how to run or test code.\n- Instructions in AGENTS.md files:\n - The scope of an AGENTS.md file is the entire directory tree rooted at the folder that contains it.\n - For every file you touch in the final patch, you must obey instructions in any AGENTS.md file whose scope includes that file.\n - Instructions about code style, structure, naming, etc. apply only to code within the AGENTS.md file's scope, unless the file states otherwise.\n - More-deeply-nested AGENTS.md files take precedence in the case of conflicting instructions.\n - Direct system/developer/user instructions (as part of a prompt) take precedence over AGENTS.md instructions.\n- The contents of the AGENTS.md file at the root of the repo and any directories from the CWD up to the root are included with the developer message and don't need to be re-read. When working in a subdirectory of CWD, or a directory outside the CWD, check for any AGENTS.md files that may be applicable.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what youโ€™re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if youโ€™re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences, focused on immediate, tangible next steps. (8โ€“12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with whatโ€™s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n- **Exception**: Avoid adding a preamble for every trivial read (e.g., `cat` a single file) unless itโ€™s part of a larger grouped action.\n\n**Examples:**\n\n- โ€œIโ€™ve explored the repo; now checking the API route definitions.โ€\n- โ€œNext, Iโ€™ll patch the config and update the related tests.โ€\n- โ€œIโ€™m about to scaffold the CLI commands and helper functions.โ€\n- โ€œOk cool, so Iโ€™ve wrapped my head around the repo. Now digging into the API routes.โ€\n- โ€œConfigโ€™s looking tidy. Next up is editing helpers to keep things in sync.โ€\n- โ€œFinished poking at the DB gateway. I will now chase down error handling.โ€\n- โ€œAlright, build pipeline order is interesting. Checking how it reports failures.โ€\n- โ€œSpotted a clever caching util; now hunting where it gets used.โ€\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and renders them to the user. Using the tool helps demonstrate that you've understood the task and convey how you're approaching it. Plans can help to make complex, ambiguous, or multi-phase work clearer and more collaborative for the user. A good plan should break the task into meaningful, logically ordered steps that are easy to verify as you go.\n\nNote that plans are not for padding out simple work with filler steps or stating the obvious. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\nDo not repeat the full contents of the plan after an `todowrite` call โ€” the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nBefore running a command, consider whether or not you have completed the\nprevious step, and make sure to mark it as completed before moving on to the\nnext step. It may be the case that you complete all steps in your plan after a\nsingle pass of implementation. If this is the case, you can simply mark all the\nplanned steps as completed. Sometimes, you may need to change plans in the\nmiddle of a task: call `todowrite` with the updated plan and make sure to provide an `explanation` of the rationale when doing so.\n\nUse a plan when:\n\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level patches, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"ใ€F:README.mdโ€ L5-L14ใ€‘\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n\n- **read-only**: You can only read files.\n- **workspace-write**: You can read files. You can write to files in your workspace folder, but not outside it.\n- **danger-full-access**: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n\n- **restricted**\n- **enabled**\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n\n- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Validating your work\n\nIf the codebase has tests or the ability to build or run, consider using them to verify that your work is complete. \n\nWhen testing, your philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests.\n\nSimilarly, once you're confident in correctness, you can suggest or use formatting commands to ensure that your code is well formatted. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\nBe mindful of whether to run validation commands proactively. In the absence of behavioral guidance:\n\n- When running in non-interactive approval modes like **never** or **on-failure**, proactively run tests, lint and do whatever you need to ensure you've completed the task.\n- When working in interactive approval modes like **untrusted**, or **on-request**, hold off on running tests or lint commands until the user is ready for you to finalize your output, because these commands take time to run and slow down iteration. Instead suggest what you want to do next, and let the user confirm first.\n- When working on test-related tasks, such as adding tests, fixing tests, or reproducing a bug to verify behavior, you may proactively run tests regardless of approval mode. Use your judgement to decide whether this is a test-related task.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the userโ€™s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written unless the user explicitly asks for them. Similarly, if you've created or modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"โ€”just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If thereโ€™s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n\n- Use only when they improve clarity โ€” they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1โ€“3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n\n- Use `-` followed by a space for every bullet.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4โ€“6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether itโ€™s a keyword (`**`) or inline code/path (`` ` ``).\n\n**File References**\nWhen referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspaceโ€‘relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1โ€‘based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5\n\n**Structure**\n\n- Place related bullets together; donโ€™t mix unrelated concepts in the same section.\n- Order sections from general โ†’ specific โ†’ supporting info.\n- For subsections (e.g., โ€œBinariesโ€ under โ€œRust Workspaceโ€), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results โ†’ use clear headers and grouped bullets.\n - Simple results โ†’ minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual โ€” no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., โ€œRuns testsโ€ not โ€œThis will run testsโ€).\n- Keep descriptions self-contained; donโ€™t refer to โ€œaboveโ€ or โ€œbelowโ€.\n- Use parallel structure in lists for consistency.\n\n**Donโ€™t**\n\n- Donโ€™t use literal words โ€œboldโ€ or โ€œmonospaceโ€ in the content.\n- Donโ€™t nest bullets or create deep hierarchies.\n- Donโ€™t output ANSI escape codes directly โ€” the CLI renderer applies them.\n- Donโ€™t cram unrelated keywords into a single bullet; split for clarity.\n- Donโ€™t let keyword lists run long โ€” wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with whatโ€™s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n\n# Tool Guidelines\n\n## Shell commands\n\nWhen using the shell, you must adhere to the following guidelines:\n\n- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)\n- Read files in chunks with a max chunk size of 250 lines. Do not use python scripts to attempt to output larger chunks of a file. Command line output will be truncated after 10 kilobytes or 256 lines of output, regardless of the command used.\n\n## `todowrite`\n\nA tool named `todowrite` is available to you. You can use it to keep an upโ€‘toโ€‘date, stepโ€‘byโ€‘step plan for the task.\n\nTo create a new plan, call `todowrite` with a short list of 1โ€‘sentence steps (no more than 5-7 words each) with a `status` for each step (`pending`, `in_progress`, or `completed`).\n\nWhen steps have been completed, use `todowrite` to mark each finished step as\n`completed` and the next step you are working on as `in_progress`. There should\nalways be exactly one `in_progress` step until everything is done. You can mark\nmultiple items as complete in a single `todowrite` call.\n\nIf all steps are complete, ensure you call `todowrite` to mark all steps as `completed`.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Thu Oct 30 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treactive_state.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"]}}},{"type":"session.updated","properties":{"info":{"version":"0.15.20","directory":"/home/francis/Projects/_nvim/opencode.nvim","title":"New session - 2025-10-30T17:42:54.734Z","time":{"created":1761846174734,"updated":1761846176690},"summary":{"diffs":[]},"id":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","projectID":"29d43526f88157cd4edd071b899dd01f240b771b"}}},{"type":"message.updated","properties":{"info":{"role":"user","time":{"created":1761846174794},"summary":{"diffs":[]},"id":"msg_a3637244a001FDRDfoBYVPEGpd","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"version":"0.15.20","directory":"/home/francis/Projects/_nvim/opencode.nvim","title":"Analyzing opencode/context.lua cursor-data handling","time":{"created":1761846174734,"updated":1761846178487},"summary":{"diffs":[]},"id":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","projectID":"29d43526f88157cd4edd071b899dd01f240b771b"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"step-start","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","snapshot":"41a7223d54ec54b5d1ef4fd276420230fc159812","id":"prt_a36374121001y0L7HUbCtVdq5o","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"_get"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" ("}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" read"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Con","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" Con"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"]."}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context`","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"`"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" intermediate"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" the"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" value"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" key"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n -","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" -"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"enabled"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" returned"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"from"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":".selection"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":".enabled"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" ("}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.\n- Why this matters: `","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.\n- Why this matters: `vim","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":"vim"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.\n- Why this matters: `vim.tbl_get` provides safe nested access; using it","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" it"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"start":1761846182179},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.\n- Why this matters: `vim.tbl_get` provides safe nested access; using it avoids runtime errors when some parts of the nested","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"},"delta":" nested"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"type":"text","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","time":{"end":1761846183728,"start":1761846183728},"text":"**Explanation**\n\n- The line `local is_enabled = vim.tbl_get(config, 'context', context_key, 'enabled')` (in `lua/opencode/context.lua:58`) uses `vim.tbl_get` to safely read a nested field from a table.\n- Concretely it attempts to read `config.context[context_key].enabled` but without throwing an error if `config.context` or `config.context[context_key]` is nil. If any intermediate key is missing it returns `nil`.\n- In the surrounding function `M.is_context_enabled`, that value is the default config value for the given context key. The function then checks the state override:\n - If `state.current_context_config[context_key].enabled` is not `nil`, that state value (true/false) is returned.\n - Otherwise the `is_enabled` value (from `config`) is returned.\n- Example: if `config.context.selection.enabled == true` but `state.current_context_config.selection.enabled == false`, the function returns `false` (state overrides config). If the state value is `nil`, the config value is used.\n- Why this matters: `vim.tbl_get` provides safe nested access; using it avoids runtime errors when some parts of the nested config are absent.","id":"prt_a36374123001u3GzKEsk03I3ZQ","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.part.updated","properties":{"part":{"type":"step-finish","snapshot":"41a7223d54ec54b5d1ef4fd276420230fc159812","id":"prt_a363747330018z5AYX660czh96","messageID":"msg_a36372b9a001M1lQEix4SK5QE5","reason":"stop","cost":0,"tokens":{"output":846,"input":18962,"reasoning":0,"cache":{"write":0,"read":12544}},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"message.updated","properties":{"info":{"role":"assistant","time":{"created":1761846176666},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","mode":"build","parentID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"msg_a36372b9a001M1lQEix4SK5QE5","modelID":"gpt-5-mini","providerID":"github-copilot","cost":0,"tokens":{"output":846,"input":18962,"reasoning":0,"cache":{"write":0,"read":12544}},"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n# AGENTS.md spec\n- Repos often contain AGENTS.md files. These files can appear anywhere within the repository.\n- These files are a way for humans to give you (the agent) instructions or tips for working within the container.\n- Some examples might be: coding conventions, info about how code is organized, or instructions for how to run or test code.\n- Instructions in AGENTS.md files:\n - The scope of an AGENTS.md file is the entire directory tree rooted at the folder that contains it.\n - For every file you touch in the final patch, you must obey instructions in any AGENTS.md file whose scope includes that file.\n - Instructions about code style, structure, naming, etc. apply only to code within the AGENTS.md file's scope, unless the file states otherwise.\n - More-deeply-nested AGENTS.md files take precedence in the case of conflicting instructions.\n - Direct system/developer/user instructions (as part of a prompt) take precedence over AGENTS.md instructions.\n- The contents of the AGENTS.md file at the root of the repo and any directories from the CWD up to the root are included with the developer message and don't need to be re-read. When working in a subdirectory of CWD, or a directory outside the CWD, check for any AGENTS.md files that may be applicable.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what youโ€™re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if youโ€™re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences, focused on immediate, tangible next steps. (8โ€“12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with whatโ€™s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n- **Exception**: Avoid adding a preamble for every trivial read (e.g., `cat` a single file) unless itโ€™s part of a larger grouped action.\n\n**Examples:**\n\n- โ€œIโ€™ve explored the repo; now checking the API route definitions.โ€\n- โ€œNext, Iโ€™ll patch the config and update the related tests.โ€\n- โ€œIโ€™m about to scaffold the CLI commands and helper functions.โ€\n- โ€œOk cool, so Iโ€™ve wrapped my head around the repo. Now digging into the API routes.โ€\n- โ€œConfigโ€™s looking tidy. Next up is editing helpers to keep things in sync.โ€\n- โ€œFinished poking at the DB gateway. I will now chase down error handling.โ€\n- โ€œAlright, build pipeline order is interesting. Checking how it reports failures.โ€\n- โ€œSpotted a clever caching util; now hunting where it gets used.โ€\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and renders them to the user. Using the tool helps demonstrate that you've understood the task and convey how you're approaching it. Plans can help to make complex, ambiguous, or multi-phase work clearer and more collaborative for the user. A good plan should break the task into meaningful, logically ordered steps that are easy to verify as you go.\n\nNote that plans are not for padding out simple work with filler steps or stating the obvious. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\nDo not repeat the full contents of the plan after an `todowrite` call โ€” the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nBefore running a command, consider whether or not you have completed the\nprevious step, and make sure to mark it as completed before moving on to the\nnext step. It may be the case that you complete all steps in your plan after a\nsingle pass of implementation. If this is the case, you can simply mark all the\nplanned steps as completed. Sometimes, you may need to change plans in the\nmiddle of a task: call `todowrite` with the updated plan and make sure to provide an `explanation` of the rationale when doing so.\n\nUse a plan when:\n\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level patches, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"ใ€F:README.mdโ€ L5-L14ใ€‘\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n\n- **read-only**: You can only read files.\n- **workspace-write**: You can read files. You can write to files in your workspace folder, but not outside it.\n- **danger-full-access**: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n\n- **restricted**\n- **enabled**\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n\n- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Validating your work\n\nIf the codebase has tests or the ability to build or run, consider using them to verify that your work is complete. \n\nWhen testing, your philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests.\n\nSimilarly, once you're confident in correctness, you can suggest or use formatting commands to ensure that your code is well formatted. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\nBe mindful of whether to run validation commands proactively. In the absence of behavioral guidance:\n\n- When running in non-interactive approval modes like **never** or **on-failure**, proactively run tests, lint and do whatever you need to ensure you've completed the task.\n- When working in interactive approval modes like **untrusted**, or **on-request**, hold off on running tests or lint commands until the user is ready for you to finalize your output, because these commands take time to run and slow down iteration. Instead suggest what you want to do next, and let the user confirm first.\n- When working on test-related tasks, such as adding tests, fixing tests, or reproducing a bug to verify behavior, you may proactively run tests regardless of approval mode. Use your judgement to decide whether this is a test-related task.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the userโ€™s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written unless the user explicitly asks for them. Similarly, if you've created or modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"โ€”just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If thereโ€™s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n\n- Use only when they improve clarity โ€” they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1โ€“3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n\n- Use `-` followed by a space for every bullet.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4โ€“6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether itโ€™s a keyword (`**`) or inline code/path (`` ` ``).\n\n**File References**\nWhen referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspaceโ€‘relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1โ€‘based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5\n\n**Structure**\n\n- Place related bullets together; donโ€™t mix unrelated concepts in the same section.\n- Order sections from general โ†’ specific โ†’ supporting info.\n- For subsections (e.g., โ€œBinariesโ€ under โ€œRust Workspaceโ€), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results โ†’ use clear headers and grouped bullets.\n - Simple results โ†’ minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual โ€” no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., โ€œRuns testsโ€ not โ€œThis will run testsโ€).\n- Keep descriptions self-contained; donโ€™t refer to โ€œaboveโ€ or โ€œbelowโ€.\n- Use parallel structure in lists for consistency.\n\n**Donโ€™t**\n\n- Donโ€™t use literal words โ€œboldโ€ or โ€œmonospaceโ€ in the content.\n- Donโ€™t nest bullets or create deep hierarchies.\n- Donโ€™t output ANSI escape codes directly โ€” the CLI renderer applies them.\n- Donโ€™t cram unrelated keywords into a single bullet; split for clarity.\n- Donโ€™t let keyword lists run long โ€” wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with whatโ€™s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n\n# Tool Guidelines\n\n## Shell commands\n\nWhen using the shell, you must adhere to the following guidelines:\n\n- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)\n- Read files in chunks with a max chunk size of 250 lines. Do not use python scripts to attempt to output larger chunks of a file. Command line output will be truncated after 10 kilobytes or 256 lines of output, regardless of the command used.\n\n## `todowrite`\n\nA tool named `todowrite` is available to you. You can use it to keep an upโ€‘toโ€‘date, stepโ€‘byโ€‘step plan for the task.\n\nTo create a new plan, call `todowrite` with a short list of 1โ€‘sentence steps (no more than 5-7 words each) with a `status` for each step (`pending`, `in_progress`, or `completed`).\n\nWhen steps have been completed, use `todowrite` to mark each finished step as\n`completed` and the next step you are working on as `in_progress`. There should\nalways be exactly one `in_progress` step until everything is done. You can mark\nmultiple items as complete in a single `todowrite` call.\n\nIf all steps are complete, ensure you call `todowrite` to mark all steps as `completed`.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Thu Oct 30 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treactive_state.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"]}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"role":"assistant","time":{"completed":1761846183769,"created":1761846176666},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","mode":"build","parentID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"msg_a36372b9a001M1lQEix4SK5QE5","modelID":"gpt-5-mini","providerID":"github-copilot","cost":0,"tokens":{"output":846,"input":18962,"reasoning":0,"cache":{"write":0,"read":12544}},"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n# AGENTS.md spec\n- Repos often contain AGENTS.md files. These files can appear anywhere within the repository.\n- These files are a way for humans to give you (the agent) instructions or tips for working within the container.\n- Some examples might be: coding conventions, info about how code is organized, or instructions for how to run or test code.\n- Instructions in AGENTS.md files:\n - The scope of an AGENTS.md file is the entire directory tree rooted at the folder that contains it.\n - For every file you touch in the final patch, you must obey instructions in any AGENTS.md file whose scope includes that file.\n - Instructions about code style, structure, naming, etc. apply only to code within the AGENTS.md file's scope, unless the file states otherwise.\n - More-deeply-nested AGENTS.md files take precedence in the case of conflicting instructions.\n - Direct system/developer/user instructions (as part of a prompt) take precedence over AGENTS.md instructions.\n- The contents of the AGENTS.md file at the root of the repo and any directories from the CWD up to the root are included with the developer message and don't need to be re-read. When working in a subdirectory of CWD, or a directory outside the CWD, check for any AGENTS.md files that may be applicable.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what youโ€™re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if youโ€™re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences, focused on immediate, tangible next steps. (8โ€“12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with whatโ€™s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n- **Exception**: Avoid adding a preamble for every trivial read (e.g., `cat` a single file) unless itโ€™s part of a larger grouped action.\n\n**Examples:**\n\n- โ€œIโ€™ve explored the repo; now checking the API route definitions.โ€\n- โ€œNext, Iโ€™ll patch the config and update the related tests.โ€\n- โ€œIโ€™m about to scaffold the CLI commands and helper functions.โ€\n- โ€œOk cool, so Iโ€™ve wrapped my head around the repo. Now digging into the API routes.โ€\n- โ€œConfigโ€™s looking tidy. Next up is editing helpers to keep things in sync.โ€\n- โ€œFinished poking at the DB gateway. I will now chase down error handling.โ€\n- โ€œAlright, build pipeline order is interesting. Checking how it reports failures.โ€\n- โ€œSpotted a clever caching util; now hunting where it gets used.โ€\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and renders them to the user. Using the tool helps demonstrate that you've understood the task and convey how you're approaching it. Plans can help to make complex, ambiguous, or multi-phase work clearer and more collaborative for the user. A good plan should break the task into meaningful, logically ordered steps that are easy to verify as you go.\n\nNote that plans are not for padding out simple work with filler steps or stating the obvious. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\nDo not repeat the full contents of the plan after an `todowrite` call โ€” the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nBefore running a command, consider whether or not you have completed the\nprevious step, and make sure to mark it as completed before moving on to the\nnext step. It may be the case that you complete all steps in your plan after a\nsingle pass of implementation. If this is the case, you can simply mark all the\nplanned steps as completed. Sometimes, you may need to change plans in the\nmiddle of a task: call `todowrite` with the updated plan and make sure to provide an `explanation` of the rationale when doing so.\n\nUse a plan when:\n\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level patches, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"ใ€F:README.mdโ€ L5-L14ใ€‘\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n\n- **read-only**: You can only read files.\n- **workspace-write**: You can read files. You can write to files in your workspace folder, but not outside it.\n- **danger-full-access**: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n\n- **restricted**\n- **enabled**\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n\n- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Validating your work\n\nIf the codebase has tests or the ability to build or run, consider using them to verify that your work is complete. \n\nWhen testing, your philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests.\n\nSimilarly, once you're confident in correctness, you can suggest or use formatting commands to ensure that your code is well formatted. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\nBe mindful of whether to run validation commands proactively. In the absence of behavioral guidance:\n\n- When running in non-interactive approval modes like **never** or **on-failure**, proactively run tests, lint and do whatever you need to ensure you've completed the task.\n- When working in interactive approval modes like **untrusted**, or **on-request**, hold off on running tests or lint commands until the user is ready for you to finalize your output, because these commands take time to run and slow down iteration. Instead suggest what you want to do next, and let the user confirm first.\n- When working on test-related tasks, such as adding tests, fixing tests, or reproducing a bug to verify behavior, you may proactively run tests regardless of approval mode. Use your judgement to decide whether this is a test-related task.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the userโ€™s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written unless the user explicitly asks for them. Similarly, if you've created or modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"โ€”just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If thereโ€™s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n\n- Use only when they improve clarity โ€” they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1โ€“3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n\n- Use `-` followed by a space for every bullet.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4โ€“6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether itโ€™s a keyword (`**`) or inline code/path (`` ` ``).\n\n**File References**\nWhen referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspaceโ€‘relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1โ€‘based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5\n\n**Structure**\n\n- Place related bullets together; donโ€™t mix unrelated concepts in the same section.\n- Order sections from general โ†’ specific โ†’ supporting info.\n- For subsections (e.g., โ€œBinariesโ€ under โ€œRust Workspaceโ€), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results โ†’ use clear headers and grouped bullets.\n - Simple results โ†’ minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual โ€” no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., โ€œRuns testsโ€ not โ€œThis will run testsโ€).\n- Keep descriptions self-contained; donโ€™t refer to โ€œaboveโ€ or โ€œbelowโ€.\n- Use parallel structure in lists for consistency.\n\n**Donโ€™t**\n\n- Donโ€™t use literal words โ€œboldโ€ or โ€œmonospaceโ€ in the content.\n- Donโ€™t nest bullets or create deep hierarchies.\n- Donโ€™t output ANSI escape codes directly โ€” the CLI renderer applies them.\n- Donโ€™t cram unrelated keywords into a single bullet; split for clarity.\n- Donโ€™t let keyword lists run long โ€” wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with whatโ€™s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n\n# Tool Guidelines\n\n## Shell commands\n\nWhen using the shell, you must adhere to the following guidelines:\n\n- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)\n- Read files in chunks with a max chunk size of 250 lines. Do not use python scripts to attempt to output larger chunks of a file. Command line output will be truncated after 10 kilobytes or 256 lines of output, regardless of the command used.\n\n## `todowrite`\n\nA tool named `todowrite` is available to you. You can use it to keep an upโ€‘toโ€‘date, stepโ€‘byโ€‘step plan for the task.\n\nTo create a new plan, call `todowrite` with a short list of 1โ€‘sentence steps (no more than 5-7 words each) with a `status` for each step (`pending`, `in_progress`, or `completed`).\n\nWhen steps have been completed, use `todowrite` to mark each finished step as\n`completed` and the next step you are working on as `in_progress`. There should\nalways be exactly one `in_progress` step until everything is done. You can mark\nmultiple items as complete in a single `todowrite` call.\n\nIf all steps are complete, ensure you call `todowrite` to mark all steps as `completed`.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Thu Oct 30 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treactive_state.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"]}}},{"type":"message.updated","properties":{"info":{"role":"assistant","time":{"completed":1761846183772,"created":1761846176666},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","mode":"build","parentID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"msg_a36372b9a001M1lQEix4SK5QE5","modelID":"gpt-5-mini","providerID":"github-copilot","cost":0,"tokens":{"output":846,"input":18962,"reasoning":0,"cache":{"write":0,"read":12544}},"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n# AGENTS.md spec\n- Repos often contain AGENTS.md files. These files can appear anywhere within the repository.\n- These files are a way for humans to give you (the agent) instructions or tips for working within the container.\n- Some examples might be: coding conventions, info about how code is organized, or instructions for how to run or test code.\n- Instructions in AGENTS.md files:\n - The scope of an AGENTS.md file is the entire directory tree rooted at the folder that contains it.\n - For every file you touch in the final patch, you must obey instructions in any AGENTS.md file whose scope includes that file.\n - Instructions about code style, structure, naming, etc. apply only to code within the AGENTS.md file's scope, unless the file states otherwise.\n - More-deeply-nested AGENTS.md files take precedence in the case of conflicting instructions.\n - Direct system/developer/user instructions (as part of a prompt) take precedence over AGENTS.md instructions.\n- The contents of the AGENTS.md file at the root of the repo and any directories from the CWD up to the root are included with the developer message and don't need to be re-read. When working in a subdirectory of CWD, or a directory outside the CWD, check for any AGENTS.md files that may be applicable.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what youโ€™re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if youโ€™re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences, focused on immediate, tangible next steps. (8โ€“12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with whatโ€™s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n- **Exception**: Avoid adding a preamble for every trivial read (e.g., `cat` a single file) unless itโ€™s part of a larger grouped action.\n\n**Examples:**\n\n- โ€œIโ€™ve explored the repo; now checking the API route definitions.โ€\n- โ€œNext, Iโ€™ll patch the config and update the related tests.โ€\n- โ€œIโ€™m about to scaffold the CLI commands and helper functions.โ€\n- โ€œOk cool, so Iโ€™ve wrapped my head around the repo. Now digging into the API routes.โ€\n- โ€œConfigโ€™s looking tidy. Next up is editing helpers to keep things in sync.โ€\n- โ€œFinished poking at the DB gateway. I will now chase down error handling.โ€\n- โ€œAlright, build pipeline order is interesting. Checking how it reports failures.โ€\n- โ€œSpotted a clever caching util; now hunting where it gets used.โ€\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and renders them to the user. Using the tool helps demonstrate that you've understood the task and convey how you're approaching it. Plans can help to make complex, ambiguous, or multi-phase work clearer and more collaborative for the user. A good plan should break the task into meaningful, logically ordered steps that are easy to verify as you go.\n\nNote that plans are not for padding out simple work with filler steps or stating the obvious. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\nDo not repeat the full contents of the plan after an `todowrite` call โ€” the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nBefore running a command, consider whether or not you have completed the\nprevious step, and make sure to mark it as completed before moving on to the\nnext step. It may be the case that you complete all steps in your plan after a\nsingle pass of implementation. If this is the case, you can simply mark all the\nplanned steps as completed. Sometimes, you may need to change plans in the\nmiddle of a task: call `todowrite` with the updated plan and make sure to provide an `explanation` of the rationale when doing so.\n\nUse a plan when:\n\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level patches, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"ใ€F:README.mdโ€ L5-L14ใ€‘\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n\n- **read-only**: You can only read files.\n- **workspace-write**: You can read files. You can write to files in your workspace folder, but not outside it.\n- **danger-full-access**: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n\n- **restricted**\n- **enabled**\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n\n- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Validating your work\n\nIf the codebase has tests or the ability to build or run, consider using them to verify that your work is complete. \n\nWhen testing, your philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests.\n\nSimilarly, once you're confident in correctness, you can suggest or use formatting commands to ensure that your code is well formatted. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\nBe mindful of whether to run validation commands proactively. In the absence of behavioral guidance:\n\n- When running in non-interactive approval modes like **never** or **on-failure**, proactively run tests, lint and do whatever you need to ensure you've completed the task.\n- When working in interactive approval modes like **untrusted**, or **on-request**, hold off on running tests or lint commands until the user is ready for you to finalize your output, because these commands take time to run and slow down iteration. Instead suggest what you want to do next, and let the user confirm first.\n- When working on test-related tasks, such as adding tests, fixing tests, or reproducing a bug to verify behavior, you may proactively run tests regardless of approval mode. Use your judgement to decide whether this is a test-related task.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the userโ€™s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written unless the user explicitly asks for them. Similarly, if you've created or modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"โ€”just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If thereโ€™s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n\n- Use only when they improve clarity โ€” they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1โ€“3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n\n- Use `-` followed by a space for every bullet.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4โ€“6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether itโ€™s a keyword (`**`) or inline code/path (`` ` ``).\n\n**File References**\nWhen referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspaceโ€‘relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1โ€‘based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5\n\n**Structure**\n\n- Place related bullets together; donโ€™t mix unrelated concepts in the same section.\n- Order sections from general โ†’ specific โ†’ supporting info.\n- For subsections (e.g., โ€œBinariesโ€ under โ€œRust Workspaceโ€), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results โ†’ use clear headers and grouped bullets.\n - Simple results โ†’ minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual โ€” no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., โ€œRuns testsโ€ not โ€œThis will run testsโ€).\n- Keep descriptions self-contained; donโ€™t refer to โ€œaboveโ€ or โ€œbelowโ€.\n- Use parallel structure in lists for consistency.\n\n**Donโ€™t**\n\n- Donโ€™t use literal words โ€œboldโ€ or โ€œmonospaceโ€ in the content.\n- Donโ€™t nest bullets or create deep hierarchies.\n- Donโ€™t output ANSI escape codes directly โ€” the CLI renderer applies them.\n- Donโ€™t cram unrelated keywords into a single bullet; split for clarity.\n- Donโ€™t let keyword lists run long โ€” wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with whatโ€™s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n\n# Tool Guidelines\n\n## Shell commands\n\nWhen using the shell, you must adhere to the following guidelines:\n\n- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)\n- Read files in chunks with a max chunk size of 250 lines. Do not use python scripts to attempt to output larger chunks of a file. Command line output will be truncated after 10 kilobytes or 256 lines of output, regardless of the command used.\n\n## `todowrite`\n\nA tool named `todowrite` is available to you. You can use it to keep an upโ€‘toโ€‘date, stepโ€‘byโ€‘step plan for the task.\n\nTo create a new plan, call `todowrite` with a short list of 1โ€‘sentence steps (no more than 5-7 words each) with a `status` for each step (`pending`, `in_progress`, or `completed`).\n\nWhen steps have been completed, use `todowrite` to mark each finished step as\n`completed` and the next step you are working on as `in_progress`. There should\nalways be exactly one `in_progress` step until everything is done. You can mark\nmultiple items as complete in a single `todowrite` call.\n\nIf all steps are complete, ensure you call `todowrite` to mark all steps as `completed`.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Thu Oct 30 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treactive_state.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"]}}},{"type":"message.updated","properties":{"info":{"role":"assistant","time":{"completed":1761846183774,"created":1761846176666},"path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","mode":"build","parentID":"msg_a3637244a001FDRDfoBYVPEGpd","id":"msg_a36372b9a001M1lQEix4SK5QE5","modelID":"gpt-5-mini","providerID":"github-copilot","cost":0,"tokens":{"output":846,"input":18962,"reasoning":0,"cache":{"write":0,"read":12544}},"system":["You are a coding agent running in the opencode, a terminal-based coding assistant. opencode is an open source project. You are expected to be precise, safe, and helpful.\n\nYour capabilities:\n\n- Receive user prompts and other context provided by the harness, such as files in the workspace.\n- Communicate with the user by streaming thinking & responses, and by making & updating plans.\n- Emit function calls to run terminal commands and apply edits. Depending on how this specific run is configured, you can request that these function calls be escalated to the user for approval before running. More on this in the \"Sandbox and approvals\" section.\n\nWithin this context, Codex refers to the open-source agentic coding interface (not the old Codex language model built by OpenAI).\n\n# How you work\n\n## Personality\n\nYour default personality and tone is concise, direct, and friendly. You communicate efficiently, always keeping the user clearly informed about ongoing actions without unnecessary detail. You always prioritize actionable guidance, clearly stating assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations about your work.\n\n# AGENTS.md spec\n- Repos often contain AGENTS.md files. These files can appear anywhere within the repository.\n- These files are a way for humans to give you (the agent) instructions or tips for working within the container.\n- Some examples might be: coding conventions, info about how code is organized, or instructions for how to run or test code.\n- Instructions in AGENTS.md files:\n - The scope of an AGENTS.md file is the entire directory tree rooted at the folder that contains it.\n - For every file you touch in the final patch, you must obey instructions in any AGENTS.md file whose scope includes that file.\n - Instructions about code style, structure, naming, etc. apply only to code within the AGENTS.md file's scope, unless the file states otherwise.\n - More-deeply-nested AGENTS.md files take precedence in the case of conflicting instructions.\n - Direct system/developer/user instructions (as part of a prompt) take precedence over AGENTS.md instructions.\n- The contents of the AGENTS.md file at the root of the repo and any directories from the CWD up to the root are included with the developer message and don't need to be re-read. When working in a subdirectory of CWD, or a directory outside the CWD, check for any AGENTS.md files that may be applicable.\n\n## Responsiveness\n\n### Preamble messages\n\nBefore making tool calls, send a brief preamble to the user explaining what youโ€™re about to do. When sending preamble messages, follow these principles and examples:\n\n- **Logically group related actions**: if youโ€™re about to run several related commands, describe them together in one preamble rather than sending a separate note for each.\n- **Keep it concise**: be no more than 1-2 sentences, focused on immediate, tangible next steps. (8โ€“12 words for quick updates).\n- **Build on prior context**: if this is not your first tool call, use the preamble message to connect the dots with whatโ€™s been done so far and create a sense of momentum and clarity for the user to understand your next actions.\n- **Keep your tone light, friendly and curious**: add small touches of personality in preambles feel collaborative and engaging.\n- **Exception**: Avoid adding a preamble for every trivial read (e.g., `cat` a single file) unless itโ€™s part of a larger grouped action.\n\n**Examples:**\n\n- โ€œIโ€™ve explored the repo; now checking the API route definitions.โ€\n- โ€œNext, Iโ€™ll patch the config and update the related tests.โ€\n- โ€œIโ€™m about to scaffold the CLI commands and helper functions.โ€\n- โ€œOk cool, so Iโ€™ve wrapped my head around the repo. Now digging into the API routes.โ€\n- โ€œConfigโ€™s looking tidy. Next up is editing helpers to keep things in sync.โ€\n- โ€œFinished poking at the DB gateway. I will now chase down error handling.โ€\n- โ€œAlright, build pipeline order is interesting. Checking how it reports failures.โ€\n- โ€œSpotted a clever caching util; now hunting where it gets used.โ€\n\n## Planning\n\nYou have access to an `todowrite` tool which tracks steps and progress and renders them to the user. Using the tool helps demonstrate that you've understood the task and convey how you're approaching it. Plans can help to make complex, ambiguous, or multi-phase work clearer and more collaborative for the user. A good plan should break the task into meaningful, logically ordered steps that are easy to verify as you go.\n\nNote that plans are not for padding out simple work with filler steps or stating the obvious. The content of your plan should not involve doing anything that you aren't capable of doing (i.e. don't try to test things that you can't test). Do not use plans for simple or single-step queries that you can just do or answer immediately.\n\nDo not repeat the full contents of the plan after an `todowrite` call โ€” the harness already displays it. Instead, summarize the change made and highlight any important context or next step.\n\nBefore running a command, consider whether or not you have completed the\nprevious step, and make sure to mark it as completed before moving on to the\nnext step. It may be the case that you complete all steps in your plan after a\nsingle pass of implementation. If this is the case, you can simply mark all the\nplanned steps as completed. Sometimes, you may need to change plans in the\nmiddle of a task: call `todowrite` with the updated plan and make sure to provide an `explanation` of the rationale when doing so.\n\nUse a plan when:\n\n- The task is non-trivial and will require multiple actions over a long time horizon.\n- There are logical phases or dependencies where sequencing matters.\n- The work has ambiguity that benefits from outlining high-level goals.\n- You want intermediate checkpoints for feedback and validation.\n- When the user asked you to do more than one thing in a single prompt\n- The user has asked you to use the plan tool (aka \"TODOs\")\n- You generate additional steps while working, and plan to do them before yielding to the user\n\n### Examples\n\n**High-quality plans**\n\nExample 1:\n\n1. Add CLI entry with file args\n2. Parse Markdown via CommonMark library\n3. Apply semantic HTML template\n4. Handle code blocks, images, links\n5. Add error handling for invalid files\n\nExample 2:\n\n1. Define CSS variables for colors\n2. Add toggle with localStorage state\n3. Refactor components to use variables\n4. Verify all views for readability\n5. Add smooth theme-change transition\n\nExample 3:\n\n1. Set up Node.js + WebSocket server\n2. Add join/leave broadcast events\n3. Implement messaging with timestamps\n4. Add usernames + mention highlighting\n5. Persist messages in lightweight DB\n6. Add typing indicators + unread count\n\n**Low-quality plans**\n\nExample 1:\n\n1. Create CLI tool\n2. Add Markdown parser\n3. Convert to HTML\n\nExample 2:\n\n1. Add dark mode toggle\n2. Save preference\n3. Make styles look good\n\nExample 3:\n\n1. Create single-file HTML game\n2. Run quick sanity check\n3. Summarize usage instructions\n\nIf you need to write a plan, only write high quality plans, not low quality ones.\n\n## Task execution\n\nYou are a coding agent. Please keep going until the query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. Autonomously resolve the query to the best of your ability, using the tools available to you, before coming back to the user. Do NOT guess or make up an answer.\n\nYou MUST adhere to the following criteria when solving queries:\n\n- Working on the repo(s) in the current environment is allowed, even if they are proprietary.\n- Analyzing code for vulnerabilities is allowed.\n- Showing user code and tool call details is allowed.\n- Use the `edit` tool to edit files \n\nIf completing the user's task requires writing or modifying files, your code and final answer should follow these coding guidelines, though user instructions (i.e. AGENTS.md) may override these guidelines:\n\n- Fix the problem at the root cause rather than applying surface-level patches, when possible.\n- Avoid unneeded complexity in your solution.\n- Do not attempt to fix unrelated bugs or broken tests. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n- Update documentation as necessary.\n- Keep changes consistent with the style of the existing codebase. Changes should be minimal and focused on the task.\n- Use `git log` and `git blame` to search the history of the codebase if additional context is required.\n- NEVER add copyright or license headers unless specifically requested.\n- Do not waste tokens by re-reading files after calling `edit` on them. The tool call will fail if it didn't work. The same goes for making folders, deleting folders, etc.\n- Do not `git commit` your changes or create new git branches unless explicitly requested.\n- Do not add inline comments within code unless explicitly requested.\n- Do not use one-letter variable names unless explicitly requested.\n- NEVER output inline citations like \"ใ€F:README.mdโ€ L5-L14ใ€‘\" in your outputs. The CLI is not able to render these so they will just be broken in the UI. Instead, if you output valid filepaths, users will be able to click on them to open the files in their editor.\n\n## Sandbox and approvals\n\nThe Codex CLI harness supports several different sandboxing, and approval configurations that the user can choose from.\n\nFilesystem sandboxing prevents you from editing files without user approval. The options are:\n\n- **read-only**: You can only read files.\n- **workspace-write**: You can read files. You can write to files in your workspace folder, but not outside it.\n- **danger-full-access**: No filesystem sandboxing.\n\nNetwork sandboxing prevents you from accessing network without approval. Options are\n\n- **restricted**\n- **enabled**\n\nApprovals are your mechanism to get user consent to perform more privileged actions. Although they introduce friction to the user because your work is paused until the user responds, you should leverage them to accomplish your important work. Do not let these settings or the sandbox deter you from attempting to accomplish the user's task. Approval options are\n\n- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe \"read\" commands.\n- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox.\n- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the `shell` command description.)\n- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is pared with `danger-full-access`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding.\n\nWhen you are running with approvals `on-request`, and sandboxing enabled, here are scenarios where you'll need to request approval:\n\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /tmp)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for\n- (For all of these, you should weigh alternative paths that do not require approval.)\n\nNote that when sandboxing is set to read-only, you'll need to request approval for any command that isn't a read.\n\nYou will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing ON, and approval on-failure.\n\n## Validating your work\n\nIf the codebase has tests or the ability to build or run, consider using them to verify that your work is complete. \n\nWhen testing, your philosophy should be to start as specific as possible to the code you changed so that you can catch issues efficiently, then make your way to broader tests as you build confidence. If there's no test for the code you changed, and if the adjacent patterns in the codebases show that there's a logical place for you to add a test, you may do so. However, do not add tests to codebases with no tests.\n\nSimilarly, once you're confident in correctness, you can suggest or use formatting commands to ensure that your code is well formatted. If there are issues you can iterate up to 3 times to get formatting right, but if you still can't manage it's better to save the user time and present them a correct solution where you call out the formatting in your final message. If the codebase does not have a formatter configured, do not add one.\n\nFor all of testing, running, building, and formatting, do not attempt to fix unrelated bugs. It is not your responsibility to fix them. (You may mention them to the user in your final message though.)\n\nBe mindful of whether to run validation commands proactively. In the absence of behavioral guidance:\n\n- When running in non-interactive approval modes like **never** or **on-failure**, proactively run tests, lint and do whatever you need to ensure you've completed the task.\n- When working in interactive approval modes like **untrusted**, or **on-request**, hold off on running tests or lint commands until the user is ready for you to finalize your output, because these commands take time to run and slow down iteration. Instead suggest what you want to do next, and let the user confirm first.\n- When working on test-related tasks, such as adding tests, fixing tests, or reproducing a bug to verify behavior, you may proactively run tests regardless of approval mode. Use your judgement to decide whether this is a test-related task.\n\n## Ambition vs. precision\n\nFor tasks that have no prior context (i.e. the user is starting something brand new), you should feel free to be ambitious and demonstrate creativity with your implementation.\n\nIf you're operating in an existing codebase, you should make sure you do exactly what the user asks with surgical precision. Treat the surrounding codebase with respect, and don't overstep (i.e. changing filenames or variables unnecessarily). You should balance being sufficiently ambitious and proactive when completing tasks of this nature.\n\nYou should use judicious initiative to decide on the right level of detail and complexity to deliver based on the user's needs. This means showing good judgment that you're capable of doing the right extras without gold-plating. This might be demonstrated by high-value, creative touches when scope of the task is vague; while being surgical and targeted when scope is tightly specified.\n\n## Sharing progress updates\n\nFor especially longer tasks that you work on (i.e. requiring many tool calls, or a plan with multiple steps), you should provide progress updates back to the user at reasonable intervals. These updates should be structured as a concise sentence or two (no more than 8-10 words long) recapping progress so far in plain language: this update demonstrates your understanding of what needs to be done, progress so far (i.e. files explores, subtasks complete), and where you're going next.\n\nBefore doing large chunks of work that may incur latency as experienced by the user (i.e. writing a new file), you should send a concise message to the user with an update indicating what you're about to do to ensure they know what you're spending time on. Don't start editing or writing large files before informing the user what you are doing and why.\n\nThe messages you send before tool calls should describe what is immediately about to be done next in very concise language. If there was previous work done, this preamble message should also include a note about the work done so far to bring the user along.\n\n## Presenting your work and final message\n\nYour final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the userโ€™s style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.\n\nYou can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.\n\nThe user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written unless the user explicitly asks for them. Similarly, if you've created or modified files using `edit`, there's no need to tell users to \"save the file\" or \"copy the code into a file\"โ€”just reference the file path.\n\nIf there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If thereโ€™s something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.\n\nBrevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding.\n\n### Final answer structure and style guidelines\n\nYou are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value.\n\n**Section Headers**\n\n- Use only when they improve clarity โ€” they are not mandatory for every answer.\n- Choose descriptive names that fit the content\n- Keep headers short (1โ€“3 words) and in `**Title Case**`. Always start headers with `**` and end with `**`\n- Leave no blank line before the first bullet under a header.\n- Section headers should only be used where they genuinely improve scanability; avoid fragmenting the answer.\n\n**Bullets**\n\n- Use `-` followed by a space for every bullet.\n- Merge related points when possible; avoid a bullet for every trivial detail.\n- Keep bullets to one line unless breaking for clarity is unavoidable.\n- Group into short lists (4โ€“6 bullets) ordered by importance.\n- Use consistent keyword phrasing and formatting across sections.\n\n**Monospace**\n\n- Wrap all commands, file paths, env vars, and code identifiers in backticks (`` `...` ``).\n- Apply to inline examples and to bullet keywords if the keyword itself is a literal file/command.\n- Never mix monospace and bold markers; choose one based on whether itโ€™s a keyword (`**`) or inline code/path (`` ` ``).\n\n**File References**\nWhen referencing files in your response, make sure to include the relevant start line and always follow the below rules:\n * Use inline code to make file paths clickable.\n * Each reference should have a stand alone path. Even if it's the same file.\n * Accepted: absolute, workspaceโ€‘relative, a/ or b/ diff prefixes, or bare filename/suffix.\n * Line/column (1โ€‘based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1).\n * Do not use URIs like file://, vscode://, or https://.\n * Do not provide range of lines\n * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5\n\n**Structure**\n\n- Place related bullets together; donโ€™t mix unrelated concepts in the same section.\n- Order sections from general โ†’ specific โ†’ supporting info.\n- For subsections (e.g., โ€œBinariesโ€ under โ€œRust Workspaceโ€), introduce with a bolded keyword bullet, then list items under it.\n- Match structure to complexity:\n - Multi-part or detailed results โ†’ use clear headers and grouped bullets.\n - Simple results โ†’ minimal headers, possibly just a short list or paragraph.\n\n**Tone**\n\n- Keep the voice collaborative and natural, like a coding partner handing off work.\n- Be concise and factual โ€” no filler or conversational commentary and avoid unnecessary repetition\n- Use present tense and active voice (e.g., โ€œRuns testsโ€ not โ€œThis will run testsโ€).\n- Keep descriptions self-contained; donโ€™t refer to โ€œaboveโ€ or โ€œbelowโ€.\n- Use parallel structure in lists for consistency.\n\n**Donโ€™t**\n\n- Donโ€™t use literal words โ€œboldโ€ or โ€œmonospaceโ€ in the content.\n- Donโ€™t nest bullets or create deep hierarchies.\n- Donโ€™t output ANSI escape codes directly โ€” the CLI renderer applies them.\n- Donโ€™t cram unrelated keywords into a single bullet; split for clarity.\n- Donโ€™t let keyword lists run long โ€” wrap or reformat for scanability.\n\nGenerally, ensure your final answers adapt their shape and depth to the request. For example, answers to code explanations should have a precise, structured explanation with code references that answer the question directly. For tasks with a simple implementation, lead with the outcome and supplement only with whatโ€™s needed for clarity. Larger changes can be presented as a logical walkthrough of your approach, grouping related steps, explaining rationale where it adds value, and highlighting next actions to accelerate the user. Your answers should provide the right level of detail while being easily scannable.\n\nFor casual greetings, acknowledgements, or other one-off conversational messages that are not delivering substantive information or structured results, respond naturally without section headers or bullet formatting.\n\n# Tool Guidelines\n\n## Shell commands\n\nWhen using the shell, you must adhere to the following guidelines:\n\n- When searching for text or files, prefer using `rg` or `rg --files` respectively because `rg` is much faster than alternatives like `grep`. (If the `rg` command is not found, then use alternatives.)\n- Read files in chunks with a max chunk size of 250 lines. Do not use python scripts to attempt to output larger chunks of a file. Command line output will be truncated after 10 kilobytes or 256 lines of output, regardless of the command used.\n\n## `todowrite`\n\nA tool named `todowrite` is available to you. You can use it to keep an upโ€‘toโ€‘date, stepโ€‘byโ€‘step plan for the task.\n\nTo create a new plan, call `todowrite` with a short list of 1โ€‘sentence steps (no more than 5-7 words each) with a `status` for each step (`pending`, `in_progress`, or `completed`).\n\nWhen steps have been completed, use `todowrite` to mark each finished step as\n`completed` and the next step you are working on as `in_progress`. There should\nalways be exactly one `in_progress` step until everything is done. You can mark\nmultiple items as complete in a single `todowrite` call.\n\nIf all steps are complete, ensure you call `todowrite` to mark all steps as `completed`.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Thu Oct 30 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treactive_state.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"]}}},{"type":"session.updated","properties":{"info":{"version":"0.15.20","directory":"/home/francis/Projects/_nvim/opencode.nvim","title":"Analyzing opencode/context.lua cursor-data handling","time":{"created":1761846174734,"updated":1761846183792},"summary":{"diffs":[]},"id":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS","projectID":"29d43526f88157cd4edd071b899dd01f240b771b"}}},{"type":"message.updated","properties":{"info":{"role":"user","time":{"created":1761846174794},"summary":{"diffs":[]},"id":"msg_a3637244a001FDRDfoBYVPEGpd","sessionID":"ses_5c9c8dbf1ffeKzKcDjZ2llgPVS"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]}] From bea323b8104d7ef46a061b1dcff3f22e7f8e2869 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Thu, 30 Oct 2025 14:03:13 -0400 Subject: [PATCH 36/48] fix(context): fix diagnostics overwrites --- lua/opencode/config.lua | 2 +- lua/opencode/context.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index 2a944e98..a48ad540 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -149,7 +149,7 @@ M.defaults = { enabled = false, }, diagnostics = { - enabled = false, + enabled = true, info = false, warning = true, error = true, diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index fd0da2ea..e71ce27c 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -71,7 +71,9 @@ function M.get_diagnostics(buf) return nil end - local diagnostic_conf = config.context and state.current_context_config.diagnostics or config.context.diagnostics + local current_conf = vim.tbl_get(state, 'current_context_config', 'diagnostics') or {} + local global_conf = vim.tbl_get(config, 'context', 'diagnostics') or {} + local diagnostic_conf = vim.tbl_deep_extend('force', global_conf, current_conf) or {} local severity_levels = {} if diagnostic_conf.error then From 0c7f72e41969ece56ff19add869de28ff050d819 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:20:39 -0400 Subject: [PATCH 37/48] feat(completion): add highlight to switches in context completion --- lua/opencode/types.lua | 1 + lua/opencode/ui/completion/context.lua | 1 + lua/opencode/ui/completion/engines/blink_cmp.lua | 1 + lua/opencode/ui/completion/engines/nvim_cmp.lua | 1 + lua/opencode/ui/highlight.lua | 3 ++- 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index f5495e3e..a908827e 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -299,6 +299,7 @@ ---@field label string Display text for the completion item ---@field kind string Type of completion item (e.g., 'file', 'subagent') ---@field kind_icon string Icon representing the kind +---@field kind_hl? string Highlight group for the kind ---@field detail string Additional detail text ---@field documentation string Documentation text ---@field insert_text string Text to insert when selected diff --git a/lua/opencode/ui/completion/context.lua b/lua/opencode/ui/completion/context.lua index c04fd0fc..a2305ef9 100644 --- a/lua/opencode/ui/completion/context.lua +++ b/lua/opencode/ui/completion/context.lua @@ -25,6 +25,7 @@ local function create_context_item(name, type, available, documentation, icon, a label = label, kind = 'context', kind_icon = icon or (available and icons.get('status_on') or icons.get('status_off')), + kind_hl = not icon and available and 'OpencodeContextSwitchOn' or nil, detail = name, documentation = documentation or (available and name or 'Enable ' .. name .. ' for this message'), insert_text = '', diff --git a/lua/opencode/ui/completion/engines/blink_cmp.lua b/lua/opencode/ui/completion/engines/blink_cmp.lua index 9a8d3b94..44fdf746 100644 --- a/lua/opencode/ui/completion/engines/blink_cmp.lua +++ b/lua/opencode/ui/completion/engines/blink_cmp.lua @@ -56,6 +56,7 @@ function Source:get_completions(ctx, callback) label = item.label, kind = item.kind, kind_icon = item.kind_icon, + kind_hl = item.kind_hl, detail = item.detail, documentation = item.documentation, insertText = item.insert_text or item.label, diff --git a/lua/opencode/ui/completion/engines/nvim_cmp.lua b/lua/opencode/ui/completion/engines/nvim_cmp.lua index b3fa34b3..0b05cca4 100644 --- a/lua/opencode/ui/completion/engines/nvim_cmp.lua +++ b/lua/opencode/ui/completion/engines/nvim_cmp.lua @@ -57,6 +57,7 @@ function M.setup(completion_sources) cmp = { kind_text = item.kind_icon, }, + kind_hl_group = item.kind_hl, detail = item.detail, documentation = item.documentation, insertText = item.insert_text or '', diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index 45fc3c45..570849f6 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -31,6 +31,7 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSwitchOn', { link = '@label', default = true }) else vim.api.nvim_set_hl(0, 'OpencodeBorder', { fg = '#616161', default = true }) vim.api.nvim_set_hl(0, 'OpencodeBackground', { link = 'Normal', default = true }) @@ -58,7 +59,7 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeContextSelection', { link = '@label', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextError', { link = 'DiagnosticError', default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextWarning', { link = 'DiagnosticWarn', default = true }) - vim.api.nvim_set_hl(0, 'OpencodeContextInfo', { link = 'DiagnosticInfo', default = true }) + vim.api.nvim_set_hl(0, 'OpencodeContextSwitchOn', { link = '@label', default = true }) end end From c1d3f9e1d278bcbeaf475eed4c223da60f507f3b Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:24:37 -0400 Subject: [PATCH 38/48] chore(mention): escape chars in mention pattern --- lua/opencode/ui/input_window.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index 2f3e2898..cc8f53d0 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -220,7 +220,8 @@ function M.remove_mention(mention_name, windows) local lines = vim.api.nvim_buf_get_lines(windows.input_buf, 0, -1, false) for i, line in ipairs(lines) do local mention_key = config.get_key_for_function('input_window', 'mention') - local updated_line = line:gsub(mention_key .. mention_name, '') + local pattern = vim.pesc(mention_key .. mention_name) + local updated_line = line:gsub(pattern, '') if updated_line ~= line then lines[i] = updated_line end From 428a046b3cdc8cdd2a310c581a35a757d5974d21 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:29:58 -0400 Subject: [PATCH 39/48] chore(types): fix config typings --- lua/opencode/config.lua | 2 +- lua/opencode/context.lua | 2 +- lua/opencode/types.lua | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index a48ad540..7e7e523f 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -305,4 +305,4 @@ return setmetatable(M, { __tostring = function(_) return vim.inspect(M.values) end, -}) +}) --[[@as OpencodeConfig]] diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index e71ce27c..467ba16b 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -1,7 +1,7 @@ -- Gathers editor context local util = require('opencode.util') -local config = require('opencode.config') --[[@as OpencodeConfig]] +local config = require('opencode.config') local state = require('opencode.state') local M = {} diff --git a/lua/opencode/types.lua b/lua/opencode/types.lua index a908827e..7379c8ed 100644 --- a/lua/opencode/types.lua +++ b/lua/opencode/types.lua @@ -53,8 +53,7 @@ ---@field share? SessionShareInfo ---@class OpencodeKeymapEntry ----@field [1] string # Function nam - +---@field [1] string # Function name ---@field mode? string|string[] # Mode(s) for the keymap ---@field desc? string # Keymap description @@ -122,7 +121,7 @@ ---@field diagnostics { enabled:boolean, info: boolean, warning: boolean, error: boolean } ---@field current_file { enabled: boolean } ---@field selection { enabled: boolean } ----@field subagents { enabled: boolean } +---@field agents { enabled: boolean } ---@class OpencodeDebugConfig ---@field enabled boolean From 2fceec78b6ef368a6e38012b02b712af9dfece41 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:40:42 -0400 Subject: [PATCH 40/48] chore(context): add augroup to autocmds --- lua/opencode/context.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 467ba16b..90580d82 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -497,8 +497,10 @@ function M.setup() M.load() end) + local augroup = vim.api.nvim_create_augroup('OpenCodeContext', { clear = true }) vim.api.nvim_create_autocmd('BufWritePost', { pattern = '*', + group = augroup, callback = function(args) local buf = args.buf local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf() @@ -510,6 +512,7 @@ function M.setup() vim.api.nvim_create_autocmd('DiagnosticChanged', { pattern = '*', + group = augroup, callback = function(args) local buf = args.buf local curr_buf = state.current_code_buf or vim.api.nvim_get_current_buf() From 5a322a6faa565d3de6ff2a68a5f56fbc6b757558 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:49:33 -0400 Subject: [PATCH 41/48] chore: remove uneeded file --- lua/opencode/reactive_state.lua | 140 -------------------------------- 1 file changed, 140 deletions(-) delete mode 100644 lua/opencode/reactive_state.lua diff --git a/lua/opencode/reactive_state.lua b/lua/opencode/reactive_state.lua deleted file mode 100644 index df1a02b6..00000000 --- a/lua/opencode/reactive_state.lua +++ /dev/null @@ -1,140 +0,0 @@ -local M = {} - -local function shallow_copy(obj) - if type(obj) ~= 'table' then - return obj - end - - local copy = {} - for key, value in pairs(obj) do - copy[key] = value - end - return copy -end - -local function merge_array(t1, t2) - local result = shallow_copy(t1 or {}) - return vim.list_extend(result, t2 or {}) -end - -local function update_path(obj, path_parts, value) - if #path_parts == 0 then - return value - end - - local key = path_parts[1] - local rest = vim.list_slice(path_parts, 2) - - local new_obj = shallow_copy(obj) - - new_obj[key] = update_path(new_obj[key] or {}, rest, value) - - return new_obj -end - ----@generic T ---- Create a new reactive state manager ----@param initial_state T Initial state ----@return table state manager with set, watch, and get methods -function M.create(initial_state) - initial_state = initial_state or {} - - local _state = shallow_copy(initial_state) - - ---@type table - local _listeners = {} - - local function split_path(path) - return type(path) == 'string' and vim.split(path, '.', { plain = true }) or path - end - - local function get_by_path(obj, path) - path = split_path(path) - - local current = obj - for _, key in ipairs(path) do - if type(current) ~= 'table' then - return nil - end - current = current[key] - end - return current - end - - local function notify(path, new_val, old_val) - local listeners = merge_array(_listeners[path], _listeners['*']) - for _, cb in ipairs(listeners) do - pcall(cb, path, new_val, old_val) - end - end - - local state_manager = {} - - --- Set state value at path or using producer function - ---@generic T - ---@param path_or_producer string|fun(draft:T):T|nil Path to set or producer function - ---@param value any - function state_manager.set(path_or_producer, value) - if type(path_or_producer) == 'function' then - local producer = path_or_producer - local draft = shallow_copy(_state) - - local result = producer(draft) - local new_state = result or draft - - local old_state = _state - _state = shallow_copy(new_state) - - local all_keys = merge_array(vim.tbl_keys(old_state), vim.tbl_keys(_state)) - - for _, k in ipairs(all_keys) do - local old_val = old_state[k] - local new_val = _state[k] - if old_val ~= new_val then - notify(k, new_val, old_val) - end - end - else - local path = path_or_producer - local path_parts = split_path(path) - local old_val = get_by_path(_state, path_parts) - - if old_val ~= value then - _state = update_path(_state, path_parts, value) - notify(path, value, old_val) - end - end - end - - --- Watch for changes to a specific path or all changes - ---@param path string|nil Path to watch, or nil/'*' for all changes - ---@param callback fun(path:string, new_val:any, old_val:any) - ---@return fun() unsubscribe function - function state_manager.watch(path, callback) - path = path or '*' - - _listeners[path] = _listeners[path] or {} - table.insert(_listeners[path], callback) - - local unsub = function() - _listeners[path] = vim.tbl_filter(function(cb) - return cb ~= callback - end, _listeners[path] or {}) - end - return unsub - end - - --- Get current state or value at path - ---@param path string|nil Path to get, or nil for entire state - ---@return any - function state_manager.get(path) - if path == nil or path == '' then - return shallow_copy(_state) - end - return get_by_path(_state, path) - end - - return state_manager -end - -return M From e53aeaae45502e964b277dd8d26d6a1def94dd06 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 07:57:28 -0400 Subject: [PATCH 42/48] chore(state): remove unused field --- lua/opencode/state.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/opencode/state.lua b/lua/opencode/state.lua index 0420bae7..4974a30a 100644 --- a/lua/opencode/state.lua +++ b/lua/opencode/state.lua @@ -42,7 +42,6 @@ local config = require('opencode.config') ---@field append fun( key:string, value:any) ---@field remove fun( key:string, idx:number) ---@field subscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any)) ----@field opencode_server_job OpencodeServer ---@field subscribe fun( key:string|string[]|nil, cb:fun(key:string, new_val:any, old_val:any)) ---@field unsubscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any)) ---@field is_running fun():boolean From f173ffcf45334db38e823ea8bda9e4d433668cd4 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 08:05:55 -0400 Subject: [PATCH 43/48] feat(context-bar): align the bar to the right With the bar aligned to the right there is no need for the icon anymore --- lua/opencode/ui/context_bar.lua | 13 ++++------- lua/opencode/ui/icons.lua | 2 -- lua/opencode/ui/input_window.lua | 37 -------------------------------- tests/unit/context_bar_spec.lua | 7 +++--- 4 files changed, 7 insertions(+), 52 deletions(-) diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua index 1531c5af..7b238835 100644 --- a/lua/opencode/ui/context_bar.lua +++ b/lua/opencode/ui/context_bar.lua @@ -46,13 +46,7 @@ end local function create_winbar_segments() local ctx = context.delta_context() - local segments = { - { - icon = icons.get('context'), - text = '', - highlight = 'OpencodeContext', - }, - } + local segments = {} local current_file = get_current_file_info(ctx) if context.is_context_enabled('current_file') and current_file then @@ -127,8 +121,9 @@ local function create_winbar_segments() end local function format_winbar_text(segments) + local right_align = '%=' if #segments == 0 then - return '' + return right_align end local parts = {} @@ -144,7 +139,7 @@ local function format_winbar_text(segments) end end - return ' ' .. table.concat(parts, '') + return right_align .. table.concat(parts, '') end local function update_winbar_highlights(win_id) diff --git a/lua/opencode/ui/icons.lua b/lua/opencode/ui/icons.lua index 8535cfd3..72aab7ed 100644 --- a/lua/opencode/ui/icons.lua +++ b/lua/opencode/ui/icons.lua @@ -33,7 +33,6 @@ local presets = { border = 'โ–Œ', -- context bar cursor_data = '๓ฐ—ง ', - context = '๎ฎข ', error = '๏— ', warning = '๏ฑ ', info = '๏š ', @@ -69,7 +68,6 @@ local presets = { border = 'โ–Œ', -- context bar cursor_data = '[|] ', - context = '[Ctx] ', error = '[E]', warning = '[W]', info = '[I] ', diff --git a/lua/opencode/ui/input_window.lua b/lua/opencode/ui/input_window.lua index cc8f53d0..f605f4e9 100644 --- a/lua/opencode/ui/input_window.lua +++ b/lua/opencode/ui/input_window.lua @@ -112,8 +112,6 @@ function M.setup(windows) M.recover_input(windows) require('opencode.ui.context_bar').render(windows) - - M.add_winbar_padding(windows) end function M.update_dimensions(windows) @@ -198,7 +196,6 @@ function M.set_content(text, windows) local lines = type(text) == 'table' and text or vim.split(tostring(text), '\n') vim.api.nvim_buf_set_lines(windows.input_buf, 0, -1, false, lines) - M.add_winbar_padding(windows) end function M.set_current_line(text, windows) @@ -208,7 +205,6 @@ function M.set_current_line(text, windows) end vim.api.nvim_set_current_line(text) - M.add_winbar_padding(windows) end function M.remove_mention(mention_name, windows) @@ -229,7 +225,6 @@ function M.remove_mention(mention_name, windows) vim.api.nvim_buf_set_lines(windows.input_buf, 0, -1, false, lines) require('opencode.ui.mention').highlight_all_mentions(windows.input_buf) - M.add_winbar_padding(windows) end function M.is_empty() @@ -242,34 +237,6 @@ function M.is_empty() return #lines == 0 or (#lines == 1 and lines[1] == '') end -function M.add_winbar_padding(windows) - if not M.mounted(windows) then - return - end - - local ns_id = vim.api.nvim_create_namespace('winbar_padding') - vim.api.nvim_buf_clear_namespace(windows.input_buf, ns_id, 0, -1) - - vim.api.nvim_buf_set_extmark(windows.input_buf, ns_id, 0, 0, { - virt_lines = { { { ' ' } } }, - virt_lines_above = true, - }) - - M.apply_topfill_workaround(windows) -end - -function M.apply_topfill_workaround(windows) - if not M.mounted(windows) then - return - end - - local topfill = 1 - local win = windows.input_win - if win and vim.api.nvim_win_is_valid(win) then - vim.fn.win_execute(win, 'lua vim.fn.winrestview({ topfill = ' .. topfill .. ' })') - end -end - function M.setup_keymaps(windows) local keymap = require('opencode.keymap') keymap.setup_window_keymaps(config.keymap.input_window, windows.input_buf) @@ -283,7 +250,6 @@ function M.setup_autocmds(windows, group) M.refresh_placeholder(windows) state.last_focused_opencode_window = 'input' require('opencode.ui.context_bar').render() - M.apply_topfill_workaround(windows) end, }) @@ -294,9 +260,6 @@ function M.setup_autocmds(windows, group) state.input_content = input_lines M.refresh_placeholder(windows, input_lines) require('opencode.ui.context_bar').render() - if #input_lines == 0 or (#input_lines == 1 and input_lines[1] == '') then - M.add_winbar_padding(windows) - end end, }) diff --git a/tests/unit/context_bar_spec.lua b/tests/unit/context_bar_spec.lua index f77146e7..35120b59 100644 --- a/tests/unit/context_bar_spec.lua +++ b/tests/unit/context_bar_spec.lua @@ -95,7 +95,6 @@ describe('opencode.ui.context_bar', function() end) after_each(function() - -- Restore original functions context.delta_context = original_delta_context context.is_context_enabled = original_is_context_enabled icons.get = original_get_icon @@ -109,7 +108,7 @@ describe('opencode.ui.context_bar', function() end) describe('opencode.ui.context_bar', function() - it('renders minimal winbar with context icon only', function() + it('renders minimal winbar with right aligh token only', function() local mock_input_win = 2001 local winbar_capture = create_mock_window(mock_input_win) @@ -117,7 +116,7 @@ describe('opencode.ui.context_bar', function() context_bar.render() assert.is_string(winbar_capture.value) - assert.is_not_nil(winbar_capture.value:find(icons.get('context'))) + assert.is_equal(winbar_capture.value, '%=') end) it('renders winbar with current file when present', function() @@ -207,7 +206,7 @@ describe('opencode.ui.context_bar', function() context_bar.render() assert.is_string(winbar_capture.value) - assert.is_not_nil(winbar_capture.value:find(icons.get('context'))) -- Should still have context icon + assert.is_equal(winbar_capture.value, '%=') end) it('does nothing when window is invalid', function() From 8585f5e955428e0faf3f559adc5f6bae86d6415e Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 08:32:15 -0400 Subject: [PATCH 44/48] feat(docs): update README with new screenshots --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cf42b931..03fff0ec 100644 --- a/README.md +++ b/README.md @@ -432,7 +432,7 @@ Supported pickers include [`fzf-lua`](https://github.com/ibhagwan/fzf-lua), [`te You can quiclkly see the current context items in the context bar at the top of the input window:
- Opencode.nvim context bar + Opencode.nvim context bar
### Context Items Completion @@ -452,7 +452,7 @@ Context items that are not currently available will be shown as disabled in the You should also see the list of files agents and selections in the menu, selecting them in the menu will remove them from the context.
- Opencode.nvim context items completion + Opencode.nvim context items completion
## ๐Ÿ”„ Agents From a6df8a2fe0c1a1daad1e1d6ae0a9679168ac2972 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Fri, 31 Oct 2025 15:30:17 -0400 Subject: [PATCH 45/48] feat(context-bar): move prompt-guard icon to the context bar --- lua/opencode/ui/context_bar.lua | 5 ++++- lua/opencode/ui/icons.lua | 2 +- lua/opencode/ui/topbar.lua | 17 +++-------------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lua/opencode/ui/context_bar.lua b/lua/opencode/ui/context_bar.lua index 7b238835..22c11f30 100644 --- a/lua/opencode/ui/context_bar.lua +++ b/lua/opencode/ui/context_bar.lua @@ -3,6 +3,7 @@ local M = {} local context = require('opencode.context') local icons = require('opencode.ui.icons') local state = require('opencode.state') +local prompt_guard_indicator = require('opencode.ui.prompt_guard_indicator') local function get_current_file_info(ctx) local current_file = ctx.current_file @@ -139,7 +140,9 @@ local function format_winbar_text(segments) end end - return right_align .. table.concat(parts, '') + local show_guard_indicator = prompt_guard_indicator.is_denied() + local left = show_guard_indicator and prompt_guard_indicator.get_formatted() or '' + return left .. right_align .. table.concat(parts, '') end local function update_winbar_highlights(win_id) diff --git a/lua/opencode/ui/icons.lua b/lua/opencode/ui/icons.lua index 72aab7ed..b8db41ce 100644 --- a/lua/opencode/ui/icons.lua +++ b/lua/opencode/ui/icons.lua @@ -28,7 +28,7 @@ local presets = { -- statuses status_on = '๏ˆ… ', status_off = '๏ˆ„ ', - guard_on = '๏”“', + guard_on = '๏”“ ', -- borders and misc border = 'โ–Œ', -- context bar diff --git a/lua/opencode/ui/topbar.lua b/lua/opencode/ui/topbar.lua index 046761b7..9582a2c8 100644 --- a/lua/opencode/ui/topbar.lua +++ b/lua/opencode/ui/topbar.lua @@ -4,7 +4,6 @@ local M = {} local state = require('opencode.state') local config_file = require('opencode.config_file') -local prompt_guard_indicator = require('opencode.ui.prompt_guard_indicator') local LABELS = { NEW_SESSION_TITLE = 'New session', @@ -43,14 +42,10 @@ local function get_mode_highlight() end end -local function create_winbar_text(description, model_info, mode_info, show_guard_indicator, win_width) +local function create_winbar_text(description, model_info, mode_info, win_width) local left_content = '' local right_content = '' - if show_guard_indicator then - left_content = left_content .. prompt_guard_indicator.get_formatted() .. ' ' - end - right_content = model_info .. ' ' .. get_mode_highlight() .. mode_info .. '%*' local desc_width = win_width - util.strdisplaywidth(left_content) - util.strdisplaywidth(right_content) @@ -110,14 +105,8 @@ function M.render() -- topbar needs to at least have a value to make sure footer is positioned correctly vim.wo[win].winbar = ' ' - local show_guard_indicator = prompt_guard_indicator.is_denied() - vim.wo[win].winbar = create_winbar_text( - get_session_desc(), - format_model_info(), - format_mode_info(), - show_guard_indicator, - vim.api.nvim_win_get_width(win) - ) + vim.wo[win].winbar = + create_winbar_text(get_session_desc(), format_model_info(), format_mode_info(), vim.api.nvim_win_get_width(win)) update_winbar_highlights(win) end) From ee89d250b74b3fcbfbe5608ba0bfb8a6a8a9c2c1 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Sun, 2 Nov 2025 10:49:17 -0500 Subject: [PATCH 46/48] feat(formatter): display diagnostics sent in user prompt --- lua/opencode/config.lua | 2 +- lua/opencode/ui/formatter.lua | 45 ++++++++++++++++++++++++++++++++--- lua/opencode/ui/highlight.lua | 2 +- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index 7e7e523f..a13d7c4b 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -305,4 +305,4 @@ return setmetatable(M, { __tostring = function(_) return vim.inspect(M.values) end, -}) --[[@as OpencodeConfig]] +}) --[[@as OpencodeConfig & OpencodeConfigModule]] diff --git a/lua/opencode/ui/formatter.lua b/lua/opencode/ui/formatter.lua index d0057556..1b027a3b 100644 --- a/lua/opencode/ui/formatter.lua +++ b/lua/opencode/ui/formatter.lua @@ -360,12 +360,12 @@ end ---@param output Output Output object to write to ---@param part OpencodeMessagePart function M._format_selection_context(output, part) - local json = context_module.decode_json_context(part.text, 'selection') + local json = context_module.decode_json_context(part.text or '', 'selection') if not json then return end local start_line = output:get_line_count() - output:add_lines(vim.split(json.content, '\n')) + output:add_lines(vim.split(json.content or '', '\n')) output:add_empty_line() local end_line = output:get_line_count() @@ -376,7 +376,7 @@ end ---@param output Output Output object to write to ---@param part OpencodeMessagePart function M._format_cursor_data_context(output, part) - local json = context_module.decode_json_context(part.text, 'cursor-data') + local json = context_module.decode_json_context(part.text or '', 'cursor-data') if not json then return end @@ -390,6 +390,44 @@ function M._format_cursor_data_context(output, part) M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3) end +---@param output Output Output object to write to +---@param part OpencodeMessagePart +function M._format_diagnostics_context(output, part) + local json = context_module.decode_json_context(part.text or '', 'diagnostics') + if not json then + return + end + local start_line = output:get_line_count() + local diagnostics = json.content --[[@as vim.Diagnostic[] ]] + if not diagnostics or type(diagnostics) ~= 'table' or #diagnostics == 0 then + return + end + + local diagnostics_count = { error = 0, warn = 0, info = 0 } + local diagnostics_icons = { + error = icons.get('error'), + warn = icons.get('warning'), + info = icons.get('info'), + } + + for _, diag in ipairs(diagnostics) do + local name = vim.diagnostic.severity[diag.severity]:lower() + diagnostics_count[name] = diagnostics_count[name] + 1 + end + + local diag_line = '**Diagnostics:**' + for name, count in pairs(diagnostics_count) do + if count > 0 then + diag_line = diag_line .. (string.format(' %s(%d)', diagnostics_icons[name], count)) + end + end + output:add_line(diag_line) + output:add_empty_line() + local end_line = output:get_line_count() + + M._add_vertical_border(output, start_line, end_line, 'OpencodeMessageRoleUser', -3) +end + ---Format and display the file path in the context ---@param output Output Output object to write to ---@param path string|nil File path @@ -727,6 +765,7 @@ function M.format_part(part, message, is_last_part) if part.synthetic == true then M._format_selection_context(output, part) M._format_cursor_data_context(output, part) + M._format_diagnostics_context(output, part) else M._format_user_prompt(output, vim.trim(part.text), message) content_added = true diff --git a/lua/opencode/ui/highlight.lua b/lua/opencode/ui/highlight.lua index 570849f6..84903073 100644 --- a/lua/opencode/ui/highlight.lua +++ b/lua/opencode/ui/highlight.lua @@ -49,7 +49,7 @@ function M.setup() vim.api.nvim_set_hl(0, 'OpencodeAgentBuild', { bg = '#616161', fg = '#FFFFFF', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeAgentCustom', { bg = '#3b4261', fg = '#FFFFFF', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextualActions', { bg = '#3b4261', fg = '#61AFEF', bold = true, default = true }) - vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { bg = '#616161', fg = '#CCCCCC', bold = false, default = true }) + vim.api.nvim_set_hl(0, 'OpencodeInputLegend', { link = '@label', bold = false, default = true }) vim.api.nvim_set_hl(0, 'OpencodeHint', { link = 'Comment', default = true }) vim.api.nvim_set_hl(0, 'OpencodeGuardDenied', { fg = '#EF5350', bold = true, default = true }) vim.api.nvim_set_hl(0, 'OpencodeContextBar', { fg = '#3b4261', default = true }) From 81fd96a349c01f10fd5d638484838970d6fd6ea6 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 3 Nov 2025 08:33:40 -0500 Subject: [PATCH 47/48] fix(context): merge context config properly before sending message --- lua/opencode/context.lua | 4 ++++ lua/opencode/core.lua | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lua/opencode/context.lua b/lua/opencode/context.lua index 90580d82..926af7e4 100644 --- a/lua/opencode/context.lua +++ b/lua/opencode/context.lua @@ -72,6 +72,10 @@ function M.get_diagnostics(buf) end local current_conf = vim.tbl_get(state, 'current_context_config', 'diagnostics') or {} + if current_conf.enabled == false then + return {} + end + local global_conf = vim.tbl_get(config, 'context', 'diagnostics') or {} local diagnostic_conf = vim.tbl_deep_extend('force', global_conf, current_conf) or {} diff --git a/lua/opencode/core.lua b/lua/opencode/core.lua index c4a8bc2c..a6a26d0b 100644 --- a/lua/opencode/core.lua +++ b/lua/opencode/core.lua @@ -103,7 +103,10 @@ function M.send_message(prompt, opts) end opts = opts or {} - opts.context = opts.context or config.context + + opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {}) + state.current_context_config = opts.context + context.load() opts.model = opts.model or state.current_model opts.agent = opts.agent or state.current_mode or config.default_mode @@ -120,10 +123,7 @@ function M.send_message(prompt, opts) state.current_mode = opts.agent end - state.current_context_config = opts.context - context.load() params.parts = context.format_message(prompt, opts.context) - M.before_run(opts) state.api_client From c70b858944a04c53eb2830328169550002a26011 Mon Sep 17 00:00:00 2001 From: Francis Belanger Date: Mon, 3 Nov 2025 08:41:02 -0500 Subject: [PATCH 48/48] test(diagnostics): add snapshot test for diagnostics --- tests/data/diagnostics.expected.json | 1 + tests/data/diagnostics.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 tests/data/diagnostics.expected.json create mode 100644 tests/data/diagnostics.json diff --git a/tests/data/diagnostics.expected.json b/tests/data/diagnostics.expected.json new file mode 100644 index 00000000..91eb0c5b --- /dev/null +++ b/tests/data/diagnostics.expected.json @@ -0,0 +1 @@ +{"actions":[{"display_line":59,"range":{"to":59,"from":59},"type":"diff_revert_selected_file","args":["8e7903714919009004aad8754db0035fb47ecb24"],"text":"[R]evert file","key":"R"},{"display_line":59,"range":{"to":59,"from":59},"type":"diff_revert_all","args":["8e7903714919009004aad8754db0035fb47ecb24"],"text":"Revert [A]ll","key":"A"},{"display_line":59,"range":{"to":59,"from":59},"type":"diff_open","args":["8e7903714919009004aad8754db0035fb47ecb24"],"text":"[D]iff","key":"D"},{"display_line":96,"range":{"to":96,"from":96},"type":"diff_revert_selected_file","args":["f33f38a70b284207e092c2c578a24e96fdd1bd4d"],"text":"[R]evert file","key":"R"},{"display_line":96,"range":{"to":96,"from":96},"type":"diff_revert_all","args":["f33f38a70b284207e092c2c578a24e96fdd1bd4d"],"text":"Revert [A]ll","key":"A"},{"display_line":96,"range":{"to":96,"from":96},"type":"diff_open","args":["f33f38a70b284207e092c2c578a24e96fdd1bd4d"],"text":"[D]iff","key":"D"}],"extmarks":[[1,2,0,{"virt_text_hide":false,"virt_text":[["โ–Œ๓ฐญป ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2025-11-03 13:34:57)","OpencodeHint"],[" [msg_a49ed91d6001coTsjFq9x6FF5W]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true,"virt_text_repeat_linebreak":false}],[2,3,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[3,4,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[4,5,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[5,6,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[6,7,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[7,8,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[8,9,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeMessageRoleUser"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[9,11,0,{"virt_text_hide":false,"virt_text":[["๎ธ ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-11-03 13:34:59)","OpencodeHint"],[" [msg_a49ed9828001mN6CDcWPnGnpHS]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true,"virt_text_repeat_linebreak":false}],[10,40,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[11,41,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[12,42,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[13,43,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[14,44,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[15,45,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[16,46,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[17,47,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":48,"hl_eol":true,"hl_group":"OpencodeDiffAdd","end_right_gravity":false}],[18,47,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[19,48,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":49,"hl_eol":true,"hl_group":"OpencodeDiffAdd","end_right_gravity":false}],[20,48,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[21,49,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":50,"hl_eol":true,"hl_group":"OpencodeDiffAdd","end_right_gravity":false}],[22,49,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[23,50,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":51,"hl_eol":true,"hl_group":"OpencodeDiffAdd","end_right_gravity":false}],[24,50,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[25,51,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[26,52,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[27,53,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[28,54,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[29,55,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[30,56,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[31,61,0,{"virt_text_hide":false,"virt_text":[["๎ธ ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-11-03 13:35:06)","OpencodeHint"],[" [msg_a49edb694001syExFxMUW1ik3n]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true,"virt_text_repeat_linebreak":false}],[32,79,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[33,80,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[34,81,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[35,82,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[36,83,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[37,84,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[38,85,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[39,86,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["-","OpencodeDiffDelete"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":87,"hl_eol":true,"hl_group":"OpencodeDiffDelete","end_right_gravity":false}],[40,86,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[41,87,0,{"virt_text_hide":false,"ns_id":3,"virt_text_pos":"overlay","priority":5000,"virt_text":[["+","OpencodeDiffAdd"]],"right_gravity":true,"virt_text_repeat_linebreak":false,"end_col":0,"end_row":88,"hl_eol":true,"hl_group":"OpencodeDiffAdd","end_right_gravity":false}],[42,87,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[43,88,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[44,89,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[45,90,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[46,91,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[47,92,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[48,93,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[49,98,0,{"virt_text_hide":false,"virt_text":[["๎ธ ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-11-03 13:35:10)","OpencodeHint"],[" [msg_a49edc4640017DZPFVUPHCm7Ji]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true,"virt_text_repeat_linebreak":false}],[50,106,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[51,107,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[52,108,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[53,109,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[54,110,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[55,111,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[56,112,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[57,113,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[58,114,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[59,115,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[60,116,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[61,117,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[62,118,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[63,119,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[64,120,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[65,121,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[66,122,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[67,123,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[68,124,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[69,125,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[70,126,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[71,127,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[72,128,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[73,129,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[74,130,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[75,131,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[76,132,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[77,133,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[78,134,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[79,135,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[80,136,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[81,137,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[82,138,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[83,139,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[84,140,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[85,141,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[86,142,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[87,143,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[88,144,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[89,145,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[90,146,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[91,147,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[92,148,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[93,149,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[94,150,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[95,151,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[96,152,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[97,153,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[98,154,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[99,155,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[100,156,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[101,157,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[102,158,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[103,159,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[104,160,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[105,161,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[106,162,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[107,163,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[108,164,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[109,165,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[110,166,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[111,167,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[112,168,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[113,169,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[114,170,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[115,171,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[116,172,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[117,173,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[118,174,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[119,175,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[120,176,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[121,177,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[122,178,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[123,179,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[124,180,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[125,181,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[126,182,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[127,183,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[128,184,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[129,185,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[130,186,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[131,187,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[132,188,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[133,189,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[134,190,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[135,191,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[136,192,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[137,193,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[138,194,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[139,195,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[140,196,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[141,197,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[142,198,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[143,199,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[144,200,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[145,201,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[146,202,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[147,203,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[148,204,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[149,205,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[150,206,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[151,207,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[152,208,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[153,209,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[154,210,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[155,211,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[156,212,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[157,213,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[158,214,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[159,215,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[160,216,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[161,217,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[162,218,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[163,219,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[164,220,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[165,221,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[166,222,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[167,223,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[168,224,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[169,225,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[170,226,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[171,227,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[172,228,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[173,229,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[174,230,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[175,231,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[176,232,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[177,233,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[178,234,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[179,235,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[180,236,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[181,237,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[182,238,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[183,239,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[184,240,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[185,241,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[186,242,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[187,243,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[188,244,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[189,245,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[190,246,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[191,247,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[192,248,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[193,249,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[194,250,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[195,251,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[196,252,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[197,253,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[198,254,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[199,255,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[200,256,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[201,257,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[202,258,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[203,259,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[204,260,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[205,261,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[206,262,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[207,263,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[208,264,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[209,265,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[210,266,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[211,267,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[212,268,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[213,269,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[214,270,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[215,271,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[216,272,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[217,273,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[218,274,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[219,275,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[220,276,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[221,277,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[222,278,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[223,279,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[224,280,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[225,281,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[226,282,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[227,283,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[228,284,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[229,285,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[230,286,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[231,287,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[232,288,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[233,289,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[234,290,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[235,291,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[236,292,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[237,293,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[238,294,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[239,295,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[240,296,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[241,297,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[242,298,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[243,299,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[244,300,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[245,301,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[246,302,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[247,303,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[248,304,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[249,305,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[250,306,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[251,307,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[252,308,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[253,309,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[254,310,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[255,311,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[256,312,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[257,313,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[258,314,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[259,315,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[260,316,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[261,317,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[262,318,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[263,319,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[264,320,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[265,321,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[266,322,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[267,323,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[268,324,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[269,325,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[270,326,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[271,327,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[272,328,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[273,329,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[274,330,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[275,331,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[276,332,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[277,333,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[278,334,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[279,335,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[280,336,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[281,337,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[282,338,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[283,339,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[284,340,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[285,341,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[286,342,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[287,343,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[288,344,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[289,345,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[290,346,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[291,347,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[292,348,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[293,349,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[294,350,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[295,351,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[296,352,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[297,353,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[298,354,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[299,355,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[300,356,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[301,357,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[302,358,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[303,359,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[304,360,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[305,361,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[306,362,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[307,363,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[308,364,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[309,365,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[310,366,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[311,367,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[312,368,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[313,369,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[314,370,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[315,371,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[316,372,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[317,373,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[318,374,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[319,375,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[320,376,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[321,377,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[322,378,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[323,379,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[324,380,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[325,381,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[326,382,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[327,383,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[328,384,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[329,385,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[330,386,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[331,387,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[332,388,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[333,389,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[334,390,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[335,391,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[336,392,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[337,393,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[338,394,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[339,395,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[340,396,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[341,397,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[342,398,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[343,399,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[344,400,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[345,401,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[346,402,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[347,403,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[348,404,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[349,405,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[350,406,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[351,407,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[352,408,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[353,409,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[354,410,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[355,411,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[356,412,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[357,413,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[358,414,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[359,415,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[360,416,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[361,417,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[362,418,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[363,419,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[364,420,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[365,421,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[366,422,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[367,423,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[368,424,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[369,425,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[370,426,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[371,427,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[372,428,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[373,429,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[374,430,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[375,431,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[376,432,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[377,433,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[378,434,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[379,435,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[380,436,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[381,437,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[382,438,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[383,439,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[384,440,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[385,441,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[386,442,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[387,443,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[388,444,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[389,445,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[390,446,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[391,447,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[392,448,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[393,449,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[394,450,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[395,451,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[396,452,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[397,453,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[398,454,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[399,455,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[400,456,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[401,457,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[402,458,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[403,459,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[404,460,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[405,461,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[406,462,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[407,463,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[408,464,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[409,465,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[410,466,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[411,467,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[412,468,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[413,469,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[414,470,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[415,471,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[416,472,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[417,473,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[418,474,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[419,475,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[420,476,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[421,477,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[422,478,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[423,479,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[424,480,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[425,481,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[426,482,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[427,483,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[428,484,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[429,485,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[430,486,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[431,487,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[432,488,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[433,489,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[434,490,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[435,491,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[436,492,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[437,493,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[438,494,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[439,495,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[440,496,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[441,497,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[442,498,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[443,499,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[444,500,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[445,501,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[446,502,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[447,503,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[448,504,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[449,505,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[450,506,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[451,507,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[452,508,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[453,509,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[454,510,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[455,511,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[456,512,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[457,513,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[458,514,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[459,515,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[460,516,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[461,517,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[462,518,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[463,519,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[464,520,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[465,521,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[466,522,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[467,523,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[468,524,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[469,525,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[470,526,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[471,527,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[472,528,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[473,529,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[474,530,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[475,531,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[476,532,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[477,533,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[478,534,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[479,535,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[480,536,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[481,537,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[482,538,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[483,539,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[484,540,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[485,541,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[486,542,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[487,543,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[488,544,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[489,545,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[490,546,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[491,547,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[492,548,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[493,549,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[494,550,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[495,551,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[496,552,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[497,553,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[498,554,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[499,555,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[500,556,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[501,557,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[502,558,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[503,559,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[504,560,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[505,561,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[506,562,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[507,563,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[508,564,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[509,565,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[510,566,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[511,567,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[512,568,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[513,569,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[514,570,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[515,571,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[516,572,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[517,573,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[518,574,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[519,575,0,{"virt_text_hide":false,"virt_text":[["โ–Œ","OpencodeToolBorder"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-1,"priority":4096,"right_gravity":true,"virt_text_repeat_linebreak":true}],[520,578,0,{"virt_text_hide":false,"virt_text":[["๎ธ ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2025-11-03 13:35:15)","OpencodeHint"],[" [msg_a49edd87f001eOJDDoq5Vb5hra]","OpencodeHint"]],"ns_id":3,"virt_text_pos":"win_col","virt_text_win_col":-3,"priority":10,"right_gravity":true,"virt_text_repeat_linebreak":false}]],"timestamp":1762177144,"lines":["","----","","","help me fix the file","","[lua/opencode/core.lua](lua/opencode/core.lua)","","**Diagnostics:** ๏ฑ (3)","","----","","","Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:","","### 1. `param-type-not-match`: expected `string` but found `string?`","- **Location:** `state.active_session.id` (line 130, col 20)","- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.","- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.","","### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`","- **Location:** `params` argument to `:create_message` (line 130, col 45)","- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.","- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.","","### 3. `need-check-nil`: `state.active_session may be nil`","- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.","","---","","## Step-by-step Fix Plan","","```markdown","- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.","- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.","- [ ] 3. Test the changes to ensure the diagnostics are resolved and the function works as expected.","```","","Let's start with step 1: Add a nil check for `state.active_session` before accessing `.id`.","","**๏‘ˆ edit** `core.lua`","","`````lua"," "," params.parts = context.format_message(prompt, opts.context)"," M.before_run(opts)"," "," if not state.active_session or not state.active_session.id then"," vim.notify('No active session to send message to', vim.log.levels.ERROR)"," return"," end"," state.api_client"," :create_message(state.active_session.id, params)"," :and_then(function(response)"," if not response or not response.info or not response.parts then","","`````","","**๓ฐป› Created Snapshot** `8e790371`","","----","","","Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.","","Now, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.","","Currently, the code is:","```lua","if opts.model then"," local provider, model = opts.model:match('^(.-)/(.+)$')"," params.model = { providerID = provider, modelID = model }"," state.current_model = opts.model","end","```","The expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `modelID` first, then `providerID`. Let's update the assignment to match the expected order.","","I'll fix this now.","","**๏‘ˆ edit** `core.lua`","","`````lua"," local params = {}"," "," if opts.model then"," local provider, model = opts.model:match('^(.-)/(.+)$')"," params.model = { providerID = provider, modelID = model }"," params.model = { modelID = model, providerID = provider }"," state.current_model = opts.model"," end"," "," if opts.agent then","","`````","","**๓ฐป› Created Snapshot** `f33f38a7`","","----","","","Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID = provider }`.","","Now, let's move to step 3: Test the changes to ensure the diagnostics are resolved and the function works as expected.","","I'll run the test suite using the provided script to verify everything is working.","","**๏’‰ run** `Run all tests to verify code changes`","","`````bash","> ./run_tests.sh","","Running tests for opencode.nvim","------------------------------------------------","Starting...Scheduling: ./tests/minimal/plugin_spec.lua","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua\t","Success\t||\topencode.nvim plugin loads the plugin without errors\t","Success\t||\topencode.nvim plugin can be set up with custom config\t","\t","Success: \t2\t","Failed : \t0\t","========================================\t","โœ“ Minimal tests passed","------------------------------------------------","Starting...Scheduling: ./tests/unit/keymap_spec.lua","Scheduling: ./tests/unit/opencode_server_spec.lua","Scheduling: ./tests/unit/context_completion_spec.lua","Scheduling: ./tests/unit/config_file_spec.lua","Scheduling: ./tests/unit/init_spec.lua","Scheduling: ./tests/unit/state_spec.lua","Scheduling: ./tests/unit/render_state_spec.lua","Scheduling: ./tests/unit/server_job_spec.lua","Scheduling: ./tests/unit/config_spec.lua","Scheduling: ./tests/unit/context_bar_spec.lua","Scheduling: ./tests/unit/renderer_spec.lua","Scheduling: ./tests/unit/api_client_spec.lua","Scheduling: ./tests/unit/core_spec.lua","Scheduling: ./tests/unit/session_spec.lua","Scheduling: ./tests/unit/event_manager_spec.lua","Scheduling: ./tests/unit/api_spec.lua","Scheduling: ./tests/unit/context_spec.lua","Scheduling: ./tests/unit/timer_spec.lua","Scheduling: ./tests/unit/util_spec.lua","Scheduling: ./tests/unit/snapshot_spec.lua","Scheduling: ./tests/unit/id_spec.lua","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_completion_spec.lua\t","Success\t||\tcontext completion get_source should return a completion source\t","Success\t||\tcontext completion complete function should return empty table when trigger char does not match\t","Success\t||\tcontext completion complete function should return context items when trigger char matches\t","Success\t||\tcontext completion complete function should include selection items when selections exist\t","Success\t||\tcontext completion complete function should include mentioned files when they exist\t","Success\t||\tcontext completion complete function should include subagent items when they exist\t","Success\t||\tcontext completion complete function should filter items based on input\t","Success\t||\tcontext completion complete function should sort items with available items first\t","Success\t||\tcontext completion on_complete function should handle nil item gracefully\t","Success\t||\tcontext completion on_complete function should handle item without data gracefully\t","Success\t||\tcontext completion on_complete function should toggle context enabled state for toggleable items\t","Success\t||\tcontext completion on_complete function should remove mentioned file when selected\t","Success\t||\tcontext completion on_complete function should remove subagent when selected\t","Success\t||\tcontext completion on_complete function should remove selection when selection item selected\t","Success\t||\tcontext completion on_complete function should clean up trigger character from current line\t","Success\t||\tcontext completion formatting functions should format diagnostics correctly\t","Success\t||\tcontext completion formatting functions should format cursor data correctly\t","Success\t||\tcontext completion formatting functions should format selection correctly\t","Success\t||\tcontext completion edge cases should handle empty context gracefully\t","Success\t||\tcontext completion edge cases should handle disabled contexts correctly\t","\t","Success: \t20\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/keymap_spec.lua\t","Success\t||\topencode.keymap setup sets up keymap with new format configured keys\t","Success\t||\topencode.keymap setup sets up keymap with old format configured keys (normalized)\t","Success\t||\topencode.keymap setup sets up callbacks that execute the correct commands (new format)\t","Success\t||\topencode.keymap setup sets up callbacks that execute the correct commands (old format normalized)\t","Success\t||\topencode.keymap normalize_keymap normalizes old format keymap to new format correctly\t","Success\t||\topencode.keymap normalize_keymap shows error message for unknown API functions\t","Success\t||\topencode.keymap normalize_keymap uses custom description from config_entry\t","Success\t||\topencode.keymap normalize_keymap falls back to API description when no custom desc provided\t","Success\t||\topencode.keymap setup_window_keymaps handles unknown API functions with error message\t","Success\t||\topencode.keymap setup_window_keymaps uses custom description for window keymaps\t","Success\t||\topencode.keymap setup_permission_keymap sets up permission keymaps when there is a current permission\t","Success\t||\topencode.keymap setup_permission_keymap should delete existing permission keymaps if no current permission exists after being set\t","Success\t||\topencode.keymap setup_permission_keymap does not set permission keymaps when there is no current permission\t","\t","Success: \t13\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/opencode_server_spec.lua\t","Success\t||\topencode.opencode_server creates a new server object\t","Success\t||\topencode.opencode_server spawn promise resolves when stdout emits server URL\t","Success\t||\topencode.opencode_server shutdown resolves shutdown_promise and clears fields\t","Success\t||\topencode.opencode_server calls on_error when stderr is triggered\t","Success\t||\topencode.opencode_server calls on_exit and clears fields when process exits\t","\t","Success: \t5\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_file_spec.lua\t","Success\t||\tconfig_file.setup lazily loads config when accessed\t","Success\t||\tconfig_file.setup get_opencode_agents returns primary + defaults\t","Success\t||\tconfig_file.setup get_opencode_agents respects disabled defaults\t","Success\t||\tconfig_file.setup get_opencode_project returns project\t","\t","Success: \t4\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/init_spec.lua\t","Success\t||\topencode has setup function in the public API\t","Success\t||\topencode main module can be required without errors\t","\t","Success: \t2\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/render_state_spec.lua\t","Success\t||\tRenderState new and reset creates a new instance\t","Success\t||\tRenderState new and reset resets to empty state\t","Success\t||\tRenderState set_message sets a new message\t","Success\t||\tRenderState set_message updates line index for message\t","Success\t||\tRenderState set_message updates existing message\t","Success\t||\tRenderState set_part sets a new part\t","Success\t||\tRenderState set_part updates line index for part\t","Success\t||\tRenderState set_part initializes actions array\t","Success\t||\tRenderState get_part_at_line returns part at line\t","Success\t||\tRenderState get_part_at_line returns nil for line without part\t","Success\t||\tRenderState get_message_at_line returns message at line\t","Success\t||\tRenderState get_message_at_line returns nil for line without message\t","Success\t||\tRenderState get_part_by_call_id finds part by call ID\t","Success\t||\tRenderState get_part_by_call_id returns nil when call ID not found\t","Success\t||\tRenderState actions adds actions to part\t","Success\t||\tRenderState actions adds actions with offset\t","Success\t||\tRenderState actions clears actions for part\t","Success\t||\tRenderState actions gets actions at line\t","Success\t||\tRenderState actions gets all actions from all parts\t","Success\t||\tRenderState update_part_lines updates part line positions\t","Success\t||\tRenderState update_part_lines shifts subsequent content when expanding\t","Success\t||\tRenderState update_part_lines shifts subsequent content when shrinking\t","Success\t||\tRenderState update_part_lines returns false for non-existent part\t","Success\t||\tRenderState remove_part removes part and shifts subsequent content\t","Success\t||\tRenderState remove_part clears line index for removed part\t","Success\t||\tRenderState remove_part returns false for non-existent part\t","Success\t||\tRenderState remove_message removes message and shifts subsequent content\t","Success\t||\tRenderState remove_message clears line index for removed message\t","Success\t||\tRenderState remove_message returns false for non-existent message\t","Success\t||\tRenderState shift_all does nothing when delta is 0\t","Success\t||\tRenderState shift_all shifts content at or after from_line\t","Success\t||\tRenderState shift_all shifts actions with parts\t","Success\t||\tRenderState shift_all does not rebuild index when nothing shifted\t","Success\t||\tRenderState shift_all invalidates index when content shifted\t","Success\t||\tRenderState shift_all exits early when content found before from_line\t","Success\t||\tRenderState update_part_data updates part reference\t","Success\t||\tRenderState update_part_data does nothing for non-existent part\t","\t","Success: \t37\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/server_job_spec.lua\t","Success\t||\tserver_job exposes expected public functions\t","Success\t||\tserver_job call_api resolves with decoded json and toggles is_job_running\t","Success\t||\tserver_job call_api rejects on non 2xx\t","Success\t||\tserver_job stream_api forwards chunks\t","Success\t||\tserver_job ensure_server spawns a new opencode server only once\t","\t","Success: \t5\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_spec.lua\t","Success\t||\topencode.config uses default values when no options are provided\t","Success\t||\topencode.config merges user options with defaults\t","\t","Success: \t2\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_bar_spec.lua\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar renders minimal winbar with right aligh token only\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with current file when present\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with multiple context elements\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with diagnostics\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar respects context enabled settings\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar handles empty winbar gracefully\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar does nothing when window is invalid\t","Success\t||\topencode.ui.context_bar opencode.ui.context_bar uses provided windows parameter\t","Success\t||\topencode.ui.context_bar setup subscribes to state changes\t","\t","Success: \t9\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_client_spec.lua\t","Success\t||\tapi_client should create a new client instance\t","Success\t||\tapi_client should remove trailing slash from base_url\t","Success\t||\tapi_client should create client using create factory function\t","Success\t||\tapi_client should have all expected API methods\t","Success\t||\tapi_client should construct URLs correctly with query parameters\t","\t","Success: \t5\t","Failed : \t0\t","========================================\t","Error detected while processing command line:","opencode command not found - please install and configure opencode before using this plugin","Unsupported opencode CLI version: opencode 0.4.1. Requires >= 0.4.2","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/core_spec.lua\t","Success\t||\topencode.core open creates windows if they don't exist\t","Success\t||\topencode.core open handles new session properly\t","Success\t||\topencode.core open focuses the appropriate window\t","Success\t||\topencode.core select_session filters sessions by description and parentID\t","Success\t||\topencode.core send_message sends a message via api_client\t","Success\t||\topencode.core send_message creates new session when none active\t","Success\t||\topencode.core send_message persist options in state when sending message\t","Success\t||\topencode.core opencode_ok (version checks) returns false when opencode executable is missing\t","Success\t||\topencode.core opencode_ok (version checks) returns false when version is below required\t","Success\t||\topencode.core opencode_ok (version checks) returns true when version equals required\t","Success\t||\topencode.core opencode_ok (version checks) returns true when version is above required\t","\t","Success: \t11\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/session_spec.lua\t","Success\t||\topencode.session get_last_workspace_session returns the most recent session for current workspace\t","Success\t||\topencode.session get_last_workspace_session returns nil when no sessions match the workspace\t","Success\t||\topencode.session get_last_workspace_session handles JSON parsing errors\t","Success\t||\topencode.session get_last_workspace_session handles empty session list\t","Success\t||\topencode.session get_by_name returns the session with matching ID\t","Success\t||\topencode.session get_by_name returns nil when no session matches the ID\t","Success\t||\topencode.session read_json_dir returns nil for non-existent directory\t","Success\t||\topencode.session read_json_dir returns nil when directory exists but has no JSON files\t","Success\t||\topencode.session read_json_dir returns decoded JSON content from directory\t","Success\t||\topencode.session read_json_dir skips invalid JSON files\t","Success\t||\topencode.session get_messages returns nil when session is nil\t","Success\t||\topencode.session get_messages returns nil when messages directory does not exist\t","Success\t||\topencode.session get_messages returns messages with their parts\t","\t","Success: \t13\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/state_spec.lua\t","Success\t||\topencode.state (observable) notifies listeners on key change\t","Success\t||\topencode.state (observable) notifies wildcard listeners on any key change\t","Success\t||\topencode.state (observable) can unregister listeners\t","Success\t||\topencode.state (observable) does not notify if value is unchanged\t","\t","Success: \t4\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/event_manager_spec.lua\t","Success\t||\tEventManager should create a new instance\t","Success\t||\tEventManager should subscribe and emit events\t","Success\t||\tEventManager should handle multiple subscribers\t","Success\t||\tEventManager should unsubscribe correctly\t","Success\t||\tEventManager should track subscriber count\t","Success\t||\tEventManager should list event names\t","Success\t||\tEventManager should handle starting and stopping\t","Success\t||\tEventManager should not start multiple times\t","\t","Success: \t8\t","Failed : \t0\t","========================================\t","File not added to context. Could not read.","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_spec.lua\t","Success\t||\textract_from_opencode_message extracts prompt, selected_text, and current_file from tags in parts\t","Success\t||\textract_from_opencode_message returns nils if message or parts missing\t","Success\t||\textract_from_message_legacy extracts legacy tags from text\t","Success\t||\textract_legacy_tag extracts content between tags\t","Success\t||\textract_legacy_tag returns nil if tag not found\t","Success\t||\tformat_message returns a parts array with prompt as first part\t","Success\t||\tformat_message includes mentioned_files and subagents\t","Success\t||\tdelta_context removes current_file if unchanged\t","Success\t||\tdelta_context removes mentioned_subagents if unchanged\t","Success\t||\tadd_file/add_selection/add_subagent adds a file if filereadable\t","Success\t||\tadd_file/add_selection/add_subagent does not add file if not filereadable\t","Success\t||\tadd_file/add_selection/add_subagent adds a selection\t","Success\t||\tadd_file/add_selection/add_subagent adds a subagent\t","\t","Success: \t13\t","Failed : \t0\t","========================================\t",":OpencodeOpenInput is deprecated. Use `:Opencode open input` instead",":OpencodeStop is deprecated. Use `:Opencode cancel` instead",":OpencodeClose is deprecated. Use `:Opencode close` instead","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_spec.lua\t","Success\t||\topencode.api commands table contains the expected commands with proper structure\t","Success\t||\topencode.api setup registers the main Opencode command and legacy commands\t","Success\t||\topencode.api setup sets up legacy command functions that route to main command\t","Success\t||\topencode.api Lua API provides callable functions that match commands\t","Success\t||\topencode.api run command argument parsing parses agent prefix and passes to send_message\t","Success\t||\topencode.api run command argument parsing parses model prefix and passes to send_message\t","Success\t||\topencode.api run command argument parsing parses context prefix and passes to send_message\t","Success\t||\topencode.api run command argument parsing parses multiple prefixes and passes all to send_message\t","Success\t||\topencode.api run command argument parsing works with run_new command\t","Success\t||\topencode.api run command argument parsing requires a prompt after prefixes\t","Success\t||\topencode.api run command argument parsing Lua API accepts opts directly without parsing\t","\t","Success: \t11\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/util_spec.lua\t","Success\t||\tutil.parse_dot_args parses flat booleans\t","Success\t||\tutil.parse_dot_args parses nested dot notation\t","Success\t||\tutil.parse_dot_args parses mixed nesting and booleans\t","Success\t||\tutil.parse_dot_args parses numbers\t","Success\t||\tutil.parse_dot_args handles empty string\t","Success\t||\tutil.parse_run_args parses no prefixes\t","Success\t||\tutil.parse_run_args parses single agent prefix\t","Success\t||\tutil.parse_run_args parses single model prefix\t","Success\t||\tutil.parse_run_args parses single context prefix\t","Success\t||\tutil.parse_run_args parses multiple prefixes in order\t","Success\t||\tutil.parse_run_args parses context with multiple comma-delimited values\t","Success\t||\tutil.parse_run_args handles empty prompt after prefixes\t","Success\t||\tutil.parse_run_args handles empty string\t","Success\t||\tutil.parse_run_args stops parsing at first non-prefix token\t","\t","Success: \t14\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/snapshot_spec.lua\t","Success\t||\tsnapshot.restore runs read-tree and checkout-index and notifies on success\t","Success\t||\tsnapshot.restore notifies error if no active session\t","Success\t||\tsnapshot.restore notifies error if read-tree fails\t","Success\t||\tsnapshot.restore notifies error if checkout-index fails\t","\t","Success: \t4\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/id_spec.lua\t","Success\t||\tID module should generate ascending session IDs\t","Success\t||\tID module should generate descending message IDs\t","Success\t||\tID module should validate given IDs correctly\t","Success\t||\tID module should throw error for invalid given IDs\t","Success\t||\tID module should validate schemas correctly\t","Success\t||\tID module should return available prefixes\t","Success\t||\tID module should generate IDs with correct length structure\t","\t","Success: \t7\t","Failed : \t0\t","========================================\t","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/timer_spec.lua\t","Success\t||\tTimer Timer.new creates a new timer with required options\t","Success\t||\tTimer Timer.new sets repeat_timer to false when explicitly disabled\t","Success\t||\tTimer Timer.new stores optional parameters\t","Success\t||\tTimer Timer:start starts a repeating timer\t","Success\t||\tTimer Timer:start starts a one-shot timer\t","Success\t||\tTimer Timer:start passes arguments to on_tick function\t","Success\t||\tTimer Timer:start stops timer when on_tick returns false\t","Success\t||\tTimer Timer:start stops timer when on_tick throws an error\t","Success\t||\tTimer Timer:start stops previous timer before starting new one\t","Success\t||\tTimer Timer:start throws error when timer creation fails\t","Success\t||\tTimer Timer:stop stops a running timer\t","Success\t||\tTimer Timer:stop calls on_stop callback when provided\t","Success\t||\tTimer Timer:stop does nothing when timer is not running\t","Success\t||\tTimer Timer:stop handles errors in on_stop callback gracefully\t","Success\t||\tTimer Timer:is_running returns false when timer is not started\t","Success\t||\tTimer Timer:is_running returns true when timer is running\t","Success\t||\tTimer Timer:is_running returns false after timer is stopped\t","Success\t||\tTimer Timer:is_running returns false after one-shot timer completes\t","Success\t||\tTimer Integration tests can restart a stopped timer\t","Success\t||\tTimer Integration tests handles rapid start/stop cycles\t","\t","Success: \t20\t","Failed : \t0\t","========================================\t","Two pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc","Two pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO","Two pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc","Two pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO","","========================================\t","Testing: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/renderer_spec.lua\t","Success\t||\trenderer replays ansi-codes correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays ansi-codes correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays ansi-codes correctly (session)\t","Success\t||\trenderer replays api-abort correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays api-abort correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays api-abort correctly (session)\t","Success\t||\trenderer replays api-error correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays api-error correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays api-error correctly (session)\t","Success\t||\trenderer replays cursor_data correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays cursor_data correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays cursor_data correctly (session)\t","Success\t||\trenderer replays diff correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays diff correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays diff correctly (session)\t","Success\t||\trenderer replays markdown-codefence correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays markdown-codefence correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays markdown-codefence correctly (session)\t","Success\t||\trenderer replays mentions-with-ranges correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays mentions-with-ranges correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays mentions-with-ranges correctly (session)\t","Success\t||\trenderer replays message-removal correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays message-removal correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays perf correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays perf correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays perf correctly (session)\t","Success\t||\trenderer replays permission-denied correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays permission-denied correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays permission-denied correctly (session)\t","Success\t||\trenderer replays permission-prompt correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays permission-prompt correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays permission correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays permission correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays permission correctly (session)\t","Success\t||\trenderer replays planning correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays planning correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays planning correctly (session)\t","Success\t||\trenderer replays redo-all correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays redo-all correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays redo-all correctly (session)\t","Success\t||\trenderer replays redo-once correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays redo-once correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays redo-once correctly (session)\t","Success\t||\trenderer replays revert correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays revert correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays revert correctly (session)\t","Success\t||\trenderer replays selection correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays selection correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays selection correctly (session)\t","Success\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays simple-session correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays simple-session correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays simple-session correctly (session)\t","Success\t||\trenderer replays tool-invalid correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays tool-invalid correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays tool-invalid correctly (session)\t","Success\t||\trenderer replays updating-text correctly (event-by-event, collapsing)\t","Success\t||\trenderer replays updating-text correctly (event-by-event, no collapsing)\t","Success\t||\trenderer replays updating-text correctly (session)\t","\t","Success: \t60\t","Failed : \t0\t","========================================\t","โœ“ Unit tests passed","------------------------------------------------","All tests passed successfully!","","`````","","----","","","All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:","","- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.","- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.","- โœ… Verified the fixes by running the full test suiteโ€”no errors or failures.","","Your file is now robust and EmmyLua diagnostics at line 130 are resolved. If you need further tweaks or want to address other diagnostics, let me know!",""]} \ No newline at end of file diff --git a/tests/data/diagnostics.json b/tests/data/diagnostics.json new file mode 100644 index 00000000..a8c6209b --- /dev/null +++ b/tests/data/diagnostics.json @@ -0,0 +1 @@ +[{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176872514},"directory":"/home/francis/Projects/_nvim/opencode.nvim","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"New session - 2025-11-03T13:34:32.514Z","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","id":"msg_a49ed91d6001coTsjFq9x6FF5W","role":"user","time":{"created":1762176897494}}}},{"type":"message.part.updated","properties":{"part":{"text":"help me fix the file","id":"prt_a49ed91d70014tkQ4g5HLMkbpH","type":"text","messageID":"msg_a49ed91d6001coTsjFq9x6FF5W","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"Called the Read tool with the following input: {\"filePath\":\"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\"}","id":"prt_a49ed91db0014Vn7x8yXZAkOxO","synthetic":true,"type":"text","messageID":"msg_a49ed91d6001coTsjFq9x6FF5W","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"\n00001| -- This file was written by an automated tool.\n00002| local state = require('opencode.state')\n00003| local context = require('opencode.context')\n00004| local session = require('opencode.session')\n00005| local ui = require('opencode.ui.ui')\n00006| local server_job = require('opencode.server_job')\n00007| local input_window = require('opencode.ui.input_window')\n00008| local util = require('opencode.util')\n00009| local config = require('opencode.config')\n00010| \n00011| local M = {}\n00012| M._abort_count = 0\n00013| \n00014| ---@param parent_id string?\n00015| function M.select_session(parent_id)\n00016| local all_sessions = session.get_all_workspace_sessions() or {}\n00017| local filtered_sessions = vim.tbl_filter(function(s)\n00018| return s.description ~= '' and s ~= nil and s.parentID == parent_id\n00019| end, all_sessions)\n00020| \n00021| ui.select_session(filtered_sessions, function(selected_session)\n00022| if not selected_session then\n00023| if state.windows then\n00024| ui.focus_input()\n00025| end\n00026| return\n00027| end\n00028| state.active_session = selected_session\n00029| if state.windows then\n00030| state.restore_points = {}\n00031| -- Don't need to update either renderer because they subscribe to\n00032| -- session changes\n00033| ui.focus_input()\n00034| else\n00035| M.open()\n00036| end\n00037| end)\n00038| end\n00039| \n00040| ---@param opts? OpenOpts\n00041| function M.open(opts)\n00042| opts = opts or { focus = 'input', new_session = false }\n00043| \n00044| if not state.opencode_server or not state.opencode_server:is_running() then\n00045| state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n00046| end\n00047| \n00048| M.ensure_current_mode()\n00049| \n00050| local are_windows_closed = state.windows == nil\n00051| \n00052| if not require('opencode.ui.ui').is_opencode_focused() then\n00053| require('opencode.context').load()\n00054| end\n00055| \n00056| if are_windows_closed then\n00057| -- Check if whether prompting will be allowed\n00058| local context_module = require('opencode.context')\n00059| local mentioned_files = context_module.context.mentioned_files or {}\n00060| local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n00061| if not allowed then\n00062| vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n00063| end\n00064| \n00065| state.windows = ui.create_windows()\n00066| end\n00067| \n00068| if opts.new_session then\n00069| state.active_session = nil\n00070| state.last_sent_context = nil\n00071| state.active_session = M.create_new_session()\n00072| else\n00073| if not state.active_session then\n00074| state.active_session = session.get_last_workspace_session()\n00075| else\n00076| if not state.display_route and are_windows_closed then\n00077| -- We're not displaying /help or something like that but we have an active session\n00078| -- and the windows were closed so we need to do a full refresh. This mostly happens\n00079| -- when opening the window after having closed it since we're not currently clearing\n00080| -- the session on api.close()\n00081| ui.render_output(false)\n00082| end\n00083| end\n00084| end\n00085| \n00086| if opts.focus == 'input' then\n00087| ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n00088| elseif opts.focus == 'output' then\n00089| ui.focus_output({ restore_position = are_windows_closed })\n00090| end\n00091| state.is_opencode_focused = true\n00092| end\n00093| \n00094| --- Sends a message to the active session, creating one if necessary.\n00095| --- @param prompt string The message prompt to send.\n00096| --- @param opts? SendMessageOpts\n00097| function M.send_message(prompt, opts)\n00098| local mentioned_files = context.context.mentioned_files or {}\n00099| local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n00100| \n00101| if not allowed then\n00102| vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n00103| return\n00104| end\n00105| \n00106| opts = opts or {}\n00107| \n00108| opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n00109| state.current_context_config = opts.context\n00110| context.load()\n00111| opts.model = opts.model or state.current_model\n00112| opts.agent = opts.agent or state.current_mode or config.default_mode\n00113| \n00114| local params = {}\n00115| \n00116| if opts.model then\n00117| local provider, model = opts.model:match('^(.-)/(.+)$')\n00118| params.model = { providerID = provider, modelID = model }\n00119| state.current_model = opts.model\n00120| end\n00121| \n00122| if opts.agent then\n00123| params.agent = opts.agent\n00124| state.current_mode = opts.agent\n00125| end\n00126| \n00127| params.parts = context.format_message(prompt, opts.context)\n00128| M.before_run(opts)\n00129| \n00130| state.api_client\n00131| :create_message(state.active_session.id, params)\n00132| :and_then(function(response)\n00133| if not response or not response.info or not response.parts then\n00134| -- fall back to full render. incremental render is handled\n00135| -- event manager\n00136| ui.render_output()\n00137| end\n00138| \n00139| M.after_run(prompt)\n00140| end)\n00141| :catch(function(err)\n00142| vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n00143| M.cancel()\n00144| end)\n00145| end\n00146| \n00147| ---@param title? string\n00148| ---@return Session?\n00149| function M.create_new_session(title)\n00150| local session_response = state.api_client\n00151| :create_session(title and { title = title } or false)\n00152| :catch(function(err)\n00153| vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n00154| end)\n00155| :wait()\n00156| \n00157| if session_response and session_response.id then\n00158| local new_session = session.get_by_id(session_response.id)\n00159| return new_session\n00160| end\n00161| end\n00162| \n00163| ---@param prompt string\n00164| function M.after_run(prompt)\n00165| context.unload_attachments()\n00166| state.last_sent_context = vim.deepcopy(context.context)\n00167| require('opencode.history').write(prompt)\n00168| M._abort_count = 0\n00169| end\n00170| \n00171| ---@param opts? SendMessageOpts\n00172| function M.before_run(opts)\n00173| local is_new_session = opts and opts.new_session or not state.active_session\n00174| opts = opts or {}\n00175| \n00176| M.cancel()\n00177| -- ui.clear_output()\n00178| \n00179| M.open({\n00180| new_session = is_new_session,\n00181| })\n00182| end\n00183| \n00184| function M.configure_provider()\n00185| require('opencode.provider').select(function(selection)\n00186| if not selection then\n00187| if state.windows then\n00188| ui.focus_input()\n00189| end\n00190| return\n00191| end\n00192| local model_str = string.format('%s/%s', selection.provider, selection.model)\n00193| state.current_model = model_str\n00194| \n00195| if state.windows then\n00196| require('opencode.ui.topbar').render()\n00197| ui.focus_input()\n00198| else\n00199| vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n00200| end\n00201| end)\n00202| end\n00203| \n00204| function M.cancel()\n00205| if state.windows and state.active_session then\n00206| if state.is_running() then\n00207| M._abort_count = M._abort_count + 1\n00208| \n00209| -- if there's a current permission, reject it\n00210| if state.current_permission then\n00211| require('opencode.api').permission_deny()\n00212| end\n00213| \n00214| local ok, result = pcall(function()\n00215| return state.api_client:abort_session(state.active_session.id):wait()\n00216| end)\n00217| \n00218| if not ok then\n00219| vim.notify('Abort error: ' .. vim.inspect(result))\n00220| end\n00221| \n00222| if M._abort_count >= 3 then\n00223| vim.notify('Re-starting Opencode server')\n00224| M._abort_count = 0\n00225| -- close existing server\n00226| if state.opencode_server then\n00227| state.opencode_server:shutdown():wait()\n00228| end\n00229| \n00230| -- start a new one\n00231| state.opencode_server = nil\n00232| \n00233| -- NOTE: start a new server here to make sure we're subscribed\n00234| -- to server events before a user sends a message\n00235| state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n00236| end\n00237| end\n00238| require('opencode.ui.footer').clear()\n00239| input_window.set_content('')\n00240| require('opencode.history').index = nil\n00241| ui.focus_input()\n00242| end\n00243| end\n00244| \n00245| function M.opencode_ok()\n00246| if vim.fn.executable('opencode') == 0 then\n00247| vim.notify(\n00248| 'opencode command not found - please install and configure opencode before using this plugin',\n00249| vim.log.levels.ERROR\n00250| )\n00251| return false\n00252| end\n00253| \n00254| if not state.opencode_cli_version or state.opencode_cli_version == '' then\n00255| local result = vim.system({ 'opencode', '--version' }):wait()\n00256| local out = (result and result.stdout or ''):gsub('%s+$', '')\n00257| state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n00258| end\n00259| \n00260| local required = state.required_version\n00261| local current_version = state.opencode_cli_version\n00262| \n00263| if not current_version or current_version == '' then\n00264| vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n00265| return false\n00266| end\n00267| \n00268| if not util.is_version_greater_or_equal(current_version, required) then\n00269| vim.notify(\n00270| string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n00271| vim.log.levels.ERROR\n00272| )\n00273| return false\n00274| end\n00275| \n00276| return true\n00277| end\n00278| \n00279| local function on_opencode_server()\n00280| state.current_permission = nil\n00281| end\n00282| \n00283| --- Switches the current mode to the specified agent.\n00284| --- @param mode string The agent/mode to switch to\n00285| --- @return boolean success Returns true if the mode was switched successfully, false otherwise\n00286| function M.switch_to_mode(mode)\n00287| if not mode or mode == '' then\n00288| vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n00289| return false\n00290| end\n00291| \n00292| local config_file = require('opencode.config_file')\n00293| local available_agents = config_file.get_opencode_agents()\n00294| \n00295| if not vim.tbl_contains(available_agents, mode) then\n00296| vim.notify(\n00297| string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n00298| vim.log.levels.ERROR\n00299| )\n00300| return false\n00301| end\n00302| \n00303| state.current_mode = mode\n00304| ui.render_output()\n00305| return true\n00306| end\n00307| \n00308| --- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n00309| --- @return boolean success Returns true if current_mode is set\n00310| function M.ensure_current_mode()\n00311| if state.current_mode == nil then\n00312| local config_file = require('opencode.config_file')\n00313| local available_agents = config_file.get_opencode_agents()\n00314| \n00315| if not available_agents or #available_agents == 0 then\n00316| vim.notify('No available agents found', vim.log.levels.ERROR)\n00317| return false\n00318| end\n00319| \n00320| local default_mode = config.default_mode\n00321| \n00322| -- Try to use the configured default mode if it's available\n00323| if default_mode and vim.tbl_contains(available_agents, default_mode) then\n00324| state.current_mode = default_mode\n00325| else\n00326| -- Fallback to first available agent\n00327| state.current_mode = available_agents[1]\n00328| end\n00329| end\n00330| return true\n00331| end\n00332| \n00333| function M.setup()\n00334| state.subscribe('opencode_server', on_opencode_server)\n00335| \n00336| vim.schedule(function()\n00337| M.opencode_ok()\n00338| end)\n00339| local OpencodeApiClient = require('opencode.api_client')\n00340| state.api_client = OpencodeApiClient.create()\n00341| end\n00342| \n00343| return M\n00344| \n","id":"prt_a49ed91db002IGcvEBKqHjLjcH","synthetic":true,"type":"text","messageID":"msg_a49ed91d6001coTsjFq9x6FF5W","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"url":"file:///home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","id":"prt_a49ed91db00317OxenmCorS0sB","messageID":"msg_a49ed91d6001coTsjFq9x6FF5W","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","mime":"text/plain","type":"file","filename":"lua/opencode/core.lua"}}},{"type":"message.part.updated","properties":{"part":{"text":"{\"content\":[{\"lnum\":130,\"end_lnum\":130,\"bufnr\":13,\"code\":\"param-type-not-match\",\"severity\":2,\"user_data\":{\"lsp\":{\"severity\":2,\"range\":{\"start\":{\"line\":130,\"character\":20},\"end\":{\"line\":130,\"character\":43}},\"message\":\"expected `string` but found `string?`. \",\"source\":\"EmmyLua\",\"code\":\"param-type-not-match\"}},\"namespace\":103,\"_extmark_id\":1,\"end_col\":43,\"message\":\"expected `string` but found `string?`. \",\"source\":\"EmmyLua\",\"col\":20},{\"lnum\":130,\"end_lnum\":130,\"bufnr\":13,\"code\":\"param-type-not-match\",\"severity\":2,\"user_data\":{\"lsp\":{\"severity\":2,\"range\":{\"start\":{\"line\":130,\"character\":45},\"end\":{\"line\":130,\"character\":51}},\"message\":\"expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`. member model not match, expect { modelID: string, providerID: string }?, but got { providerID = string?, modelID = string? }\",\"source\":\"EmmyLua\",\"code\":\"param-type-not-match\"}},\"namespace\":103,\"_extmark_id\":2,\"end_col\":51,\"message\":\"expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`. member model not match, expect { modelID: string, providerID: string }?, but got { providerID = string?, modelID = string? }\",\"source\":\"EmmyLua\",\"col\":45},{\"lnum\":130,\"end_lnum\":130,\"bufnr\":13,\"code\":\"need-check-nil\",\"severity\":2,\"user_data\":{\"lsp\":{\"severity\":2,\"range\":{\"start\":{\"line\":130,\"character\":20},\"end\":{\"line\":130,\"character\":40}},\"message\":\"state.active_session may be nil\",\"source\":\"EmmyLua\",\"code\":\"need-check-nil\"}},\"namespace\":103,\"_extmark_id\":3,\"end_col\":40,\"message\":\"state.active_session may be nil\",\"source\":\"EmmyLua\",\"col\":20}],\"context_type\":\"diagnostics\"}","id":"prt_a49ed91d70021vvuvYgF7OgY5D","synthetic":true,"type":"text","messageID":"msg_a49ed91d6001coTsjFq9x6FF5W","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176897510},"directory":"/home/francis/Projects/_nvim/opencode.nvim","projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"New session - 2025-11-03T13:34:32.514Z","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176899112},"id":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":0,"write":0},"input":0,"output":0},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"id":"msg_a49ed91d6001coTsjFq9x6FF5W","time":{"created":1762176897494},"summary":{"diffs":[]},"role":"user","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176899140},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"New session - 2025-11-03T13:34:32.514Z","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_a49ed9b590016OgTFP0GBP3nPs","snapshot":"8e7903714919009004aad8754db0035fb47ecb24","type":"step-start","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"130"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176900011},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Fixing param-type-not-match and need-check-nil in core.lua line 130","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"-match"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" **"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130,","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":","}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"nil"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" be"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"string"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" nullable"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session`","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"`"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"-not"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID:","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":":"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" tools"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" parts"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts =","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" ="}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"`\n"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" ("}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string?","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"?"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string,","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":","}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, provider","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" provider"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"ity"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" matches"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `{"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"-check"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" **"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" check"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" nil"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"---\n\n"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] ","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" "}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `."}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" expected"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, provider","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" provider"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" diagnostics"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics are resolved","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" resolved"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics are resolved and the function works as expected.\n```\n\n","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"`\n\n"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics are resolved and the function works as expected.\n```\n\nLet's start with step 1: Add a nil check for `state.active_session`","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"`"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics are resolved and the function works as expected.\n```\n\nLet's start with step 1: Add a nil check for `state.active_session` before accessing `.id`.","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176899931},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"`."}},{"type":"message.part.updated","properties":{"part":{"callID":"call_ABJ98MrScaXDP17UCnRACu6s","id":"prt_a49edb4c4001QGmKwYoe4BcZ9j","tool":"edit","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","state":{"status":"running","input":{"newString":" if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)","filePath":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","oldString":" state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)"},"time":{"start":1762176906475}},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"file.edited","properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua"}},{"type":"message.part.updated","properties":{"part":{"text":"Let's address the three EmmyLua diagnostics at line 130 in `lua/opencode/core.lua`:\n\n### 1. `param-type-not-match`: expected `string` but found `string?`\n- **Location:** `state.active_session.id` (line 130, col 20)\n- **Cause:** `state.active_session` may be `nil`, so `state.active_session.id` could error or be `nil`. The function expects a `string`, not a nullable string.\n- **Fix:** Add a nil check for `state.active_session` before accessing `.id`.\n\n### 2. `param-type-not-match`: expected `{ agent: string?, messageID: string?, model: {...}?, parts: Part[], system: string?, tools: table<...>? }` but found `{ model = table, agent = any, parts = OpencodeMessagePart[], ... }`\n- **Location:** `params` argument to `:create_message` (line 130, col 45)\n- **Cause:** The `model` field in `params` is `{ providerID = string?, modelID = string? }`, but the expected type is `{ modelID: string, providerID: string }?`. The order and possibly the optionality are mismatched.\n- **Fix:** Ensure the `model` field matches the expected type exactly: `{ modelID: string, providerID: string }`.\n\n### 3. `need-check-nil`: `state.active_session may be nil`\n- **Location:** Same as #1. This is a reminder to check for nil before accessing `state.active_session.id`.\n\n---\n\n## Step-by-step Fix Plan\n\n```markdown\n- [ ] 1. Add a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- [ ] 2. Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n- [ ] 3. Test the changes to ensure the diagnostics are resolved and the function works as expected.\n```\n\nLet's start with step 1: Add a nil check for `state.active_session` before accessing `.id`.","id":"prt_a49ed9b5b001nHdvHRhJEv3ZRU","time":{"start":1762176906487,"end":1762176906487},"type":"text","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"callID":"call_ABJ98MrScaXDP17UCnRACu6s","id":"prt_a49edb4c4001QGmKwYoe4BcZ9j","tool":"edit","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","state":{"metadata":{"filediff":{"file":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":0,"additions":4,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n+++ /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n@@ -126,8 +126,12 @@\n \n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n \n+if not state.active_session or not state.active_session.id then\n+ vim.notify('No active session to send message to', vim.log.levels.ERROR)\n+ return\n+end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n","diagnostics":{"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/autocmds.lua":[{"severity":2,"range":{"start":{"line":11,"character":2},"end":{"line":11,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":2},"end":{"line":37,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":2},"end":{"line":48,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":2},"end":{"line":58,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":16},"end":{"line":5,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":23},"end":{"line":47,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":9},"end":{"line":16,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":8},"end":{"line":17,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":44},"end":{"line":32,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":31},"end":{"line":33,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":23},"end":{"line":66,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":24},"end":{"line":62,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion.lua":[{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":59},"end":{"line":35,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":6},"end":{"line":90,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":6},"end":{"line":93,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/commands.lua":[{"severity":2,"range":{"start":{"line":81,"character":8},"end":{"line":81,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":37},"end":{"line":27,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":10},"end":{"line":75,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":56},"end":{"line":81,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/config_file.lua":[{"severity":2,"range":{"start":{"line":17,"character":4},"end":{"line":17,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":4},"end":{"line":34,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":14},"end":{"line":61,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":11},"end":{"line":90,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":53},"end":{"line":17,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":74},"end":{"line":17,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":54},"end":{"line":34,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":75},"end":{"line":34,"character":78}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":56},"end":{"line":51,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":77},"end":{"line":51,"character":80}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/blink_cmp.lua":[{"severity":2,"range":{"start":{"line":24,"character":9},"end":{"line":24,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":37},"end":{"line":35,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":49},"end":{"line":35,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/nvim_cmp.lua":[{"severity":2,"range":{"start":{"line":83,"character":18},"end":{"line":83,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":11},"end":{"line":26,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":14},"end":{"line":86,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":39},"end":{"line":34,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":51},"end":{"line":34,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/vim_complete.lua":[{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":116,"character":25},"end":{"line":116,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":21},"end":{"line":20,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":15},"end":{"line":46,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":14},"end":{"line":47,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":15},"end":{"line":64,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":14},"end":{"line":65,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":37},"end":{"line":38,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":9},"end":{"line":85,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":49},"end":{"line":38,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":6},"end":{"line":108,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":6},"end":{"line":9,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":6},"end":{"line":10,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":41},"end":{"line":106,"character":44}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/context.lua":[{"severity":2,"range":{"start":{"line":286,"character":2},"end":{"line":286,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":290,"character":2},"end":{"line":290,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":2},"end":{"line":292,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":297,"character":2},"end":{"line":297,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":296,"character":2},"end":{"line":296,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":2},"end":{"line":298,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":2},"end":{"line":299,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":504,"character":2},"end":{"line":504,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":516,"character":2},"end":{"line":516,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":21},"end":{"line":58,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":27},"end":{"line":59,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":23},"end":{"line":73,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":22},"end":{"line":78,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":26},"end":{"line":79,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":4},"end":{"line":144,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":18},"end":{"line":218,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":25},"end":{"line":266,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":479,"character":18},"end":{"line":479,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":45},"end":{"line":28,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":29},"end":{"line":51,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":22},"end":{"line":92,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":115,"character":29},"end":{"line":115,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":29},"end":{"line":129,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":18},"end":{"line":141,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":142,"character":17},"end":{"line":142,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":9},"end":{"line":148,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":9},"end":{"line":150,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":9},"end":{"line":156,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":167,"character":29},"end":{"line":167,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":9},"end":{"line":179,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":182,"character":29},"end":{"line":182,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":196,"character":29},"end":{"line":196,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":8},"end":{"line":237,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":15},"end":{"line":249,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":21},"end":{"line":265,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":22},"end":{"line":281,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":282,"character":18},"end":{"line":282,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":22},"end":{"line":283,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":15},"end":{"line":287,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":21},"end":{"line":291,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":293,"character":19},"end":{"line":293,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":24},"end":{"line":298,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":312,"character":19},"end":{"line":312,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":479,"character":51},"end":{"line":479,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":483,"character":11},"end":{"line":483,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":492,"character":11},"end":{"line":492,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":503,"character":18},"end":{"line":503,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":11},"end":{"line":255,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":256,"character":16},"end":{"line":256,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":334,"character":11},"end":{"line":334,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":347,"character":11},"end":{"line":347,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":357,"character":11},"end":{"line":357,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":423,"character":27},"end":{"line":423,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":60},"end":{"line":30,"character":63}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":34},"end":{"line":83,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":34},"end":{"line":86,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":34},"end":{"line":89,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":31},"end":{"line":250,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":42},"end":{"line":354,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":9},"end":{"line":276,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":34},"end":{"line":266,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":509,"character":49},"end":{"line":509,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":521,"character":49},"end":{"line":521,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":38},"end":{"line":141,"character":42}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":64},"end":{"line":298,"character":68}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":70},"end":{"line":298,"character":75}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":77},"end":{"line":298,"character":81}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":250,"character":51},"end":{"line":250,"character":55}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/sort.lua":[{"severity":2,"range":{"start":{"line":31,"character":40},"end":{"line":31,"character":43}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":40},"end":{"line":32,"character":43}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/context_bar.lua":[{"severity":2,"range":{"start":{"line":172,"character":2},"end":{"line":172,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":2},"end":{"line":162,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":16},"end":{"line":149,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":10},"end":{"line":151,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":18},"end":{"line":148,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":9},"end":{"line":155,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":4},"end":{"line":180,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":7},"end":{"line":98,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":7},"end":{"line":99,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":7},"end":{"line":100,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":20},"end":{"line":175,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/contextual_actions.lua":[{"severity":2,"range":{"start":{"line":22,"character":2},"end":{"line":22,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":2},"end":{"line":42,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":4},"end":{"line":82,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":16},"end":{"line":19,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":18},"end":{"line":20,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":6},"end":{"line":88,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":6},"end":{"line":26,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":6},"end":{"line":46,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":6},"end":{"line":63,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":8},"end":{"line":31,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":8},"end":{"line":54,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":10},"end":{"line":90,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":25},"end":{"line":27,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":25},"end":{"line":50,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":93,"character":27},"end":{"line":93,"character":33}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/debug_helper.lua":[{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":2},"end":{"line":77,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":2},"end":{"line":16,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":2},"end":{"line":76,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":19},"end":{"line":16,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":4},"end":{"line":20,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":4},"end":{"line":32,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":4},"end":{"line":64,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":4},"end":{"line":70,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":16},"end":{"line":75,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":18},"end":{"line":11,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":19},"end":{"line":12,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":23},"end":{"line":35,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":51},"end":{"line":46,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":19},"end":{"line":74,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":72},"end":{"line":77,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":5},"end":{"line":18,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":46},"end":{"line":32,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":48},"end":{"line":64,"character":51}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":45},"end":{"line":70,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/diff_tab.lua":[{"severity":2,"range":{"start":{"line":37,"character":2},"end":{"line":37,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":2},"end":{"line":56,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":24},"end":{"line":35,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":4},"end":{"line":43,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":4},"end":{"line":44,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":10},"end":{"line":14,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":27},"end":{"line":36,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":17},"end":{"line":38,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":18},"end":{"line":54,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":22},"end":{"line":55,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":22},"end":{"line":5,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":10},"end":{"line":6,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":6},"end":{"line":47,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":6},"end":{"line":48,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":20},"end":{"line":7,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":18},"end":{"line":10,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":9},"end":{"line":16,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":50},"end":{"line":35,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":23},"end":{"line":40,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":25},"end":{"line":44,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":23},"end":{"line":51,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":16},"end":{"line":25,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":29},"end":{"line":18,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":13},"end":{"line":19,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/file_picker.lua":[{"severity":2,"range":{"start":{"line":157,"character":2},"end":{"line":157,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":21},"end":{"line":103,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":22},"end":{"line":104,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":21},"end":{"line":105,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":11},"end":{"line":11,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":6},"end":{"line":130,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":6},"end":{"line":134,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":8},"end":{"line":132,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":26},"end":{"line":126,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua":[{"severity":2,"range":{"start":{"line":400,"character":43},"end":{"line":400,"character":57}},"message":"Undefined type or alias `vim.Diagnostic`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":160,"character":73},"end":{"line":160,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":37},"end":{"line":224,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":310,"character":16},"end":{"line":310,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":326,"character":19},"end":{"line":326,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":367,"character":19},"end":{"line":367,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":384,"character":19},"end":{"line":384,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":438,"character":5},"end":{"line":438,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":448,"character":19},"end":{"line":448,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":16},"end":{"line":563,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":698,"character":16},"end":{"line":698,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":437,"character":14},"end":{"line":437,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":6},"end":{"line":21,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":64},"end":{"line":283,"character":67}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":475,"character":27},"end":{"line":475,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":484,"character":30},"end":{"line":484,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":497,"character":27},"end":{"line":497,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":26},"end":{"line":563,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":700,"character":12},"end":{"line":700,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":798,"character":64},"end":{"line":798,"character":67}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":300,"character":10},"end":{"line":300,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":571,"character":19},"end":{"line":571,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":304,"character":34},"end":{"line":304,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":413,"character":17},"end":{"line":413,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":655,"character":23},"end":{"line":655,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":781,"character":42},"end":{"line":781,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":68},"end":{"line":299,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":769,"character":38},"end":{"line":769,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":49,"character":71},"end":{"line":49,"character":77}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/highlight.lua":[{"severity":2,"range":{"start":{"line":3,"character":19},"end":{"line":3,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":4},"end":{"line":6,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":4},"end":{"line":7,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":4},"end":{"line":8,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":4},"end":{"line":9,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":4},"end":{"line":10,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":4},"end":{"line":12,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":4},"end":{"line":15,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":4},"end":{"line":16,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":4},"end":{"line":17,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":4},"end":{"line":20,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":4},"end":{"line":21,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":4},"end":{"line":22,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":4},"end":{"line":23,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":4},"end":{"line":25,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":4},"end":{"line":26,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":4},"end":{"line":27,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":4},"end":{"line":29,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":4},"end":{"line":30,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":4},"end":{"line":32,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":4},"end":{"line":36,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":4},"end":{"line":37,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":4},"end":{"line":38,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":4},"end":{"line":43,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":4},"end":{"line":44,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":4},"end":{"line":46,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":4},"end":{"line":47,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":4},"end":{"line":48,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":4},"end":{"line":49,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":4},"end":{"line":50,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":4},"end":{"line":53,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":4},"end":{"line":54,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":4},"end":{"line":55,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":4},"end":{"line":58,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":4},"end":{"line":59,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":4},"end":{"line":60,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":4},"end":{"line":61,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/icons.lua":[{"severity":2,"range":{"start":{"line":89,"character":6},"end":{"line":89,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":8},"end":{"line":90,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":10},"end":{"line":92,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/loading_animation.lua":[{"severity":2,"range":{"start":{"line":28,"character":11},"end":{"line":28,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":10},"end":{"line":13,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":4},"end":{"line":100,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":28},"end":{"line":45,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":9},"end":{"line":34,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":62},"end":{"line":34,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/mention.lua":[{"severity":2,"range":{"start":{"line":103,"character":2},"end":{"line":103,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":27},"end":{"line":4,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":2},"end":{"line":104,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":2},"end":{"line":105,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":8},"end":{"line":11,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":6},"end":{"line":33,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":23},"end":{"line":94,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":4},"end":{"line":112,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":32},"end":{"line":14,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":26},"end":{"line":56,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":7},"end":{"line":132,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":7},"end":{"line":137,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":116,"character":25},"end":{"line":116,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":27},"end":{"line":137,"character":31}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/navigation.lua":[{"severity":2,"range":{"start":{"line":53,"character":2},"end":{"line":53,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":2},"end":{"line":86,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":23},"end":{"line":32,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":19},"end":{"line":34,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":21},"end":{"line":52,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":23},"end":{"line":66,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":19},"end":{"line":68,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":6},"end":{"line":47,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":6},"end":{"line":82,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/output.lua":[{"severity":2,"range":{"start":{"line":94,"character":9},"end":{"line":94,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":9},"end":{"line":110,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":30},"end":{"line":141,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":30},"end":{"line":145,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/output_window.lua":[{"severity":2,"range":{"start":{"line":4,"character":14},"end":{"line":4,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":2},"end":{"line":39,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":2},"end":{"line":40,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":2},"end":{"line":42,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":2},"end":{"line":43,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":2},"end":{"line":44,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":2},"end":{"line":45,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":2},"end":{"line":47,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":2},"end":{"line":48,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":2},"end":{"line":49,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":2},"end":{"line":50,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":2},"end":{"line":51,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":2},"end":{"line":61,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":2},"end":{"line":89,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":2},"end":{"line":90,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":2},"end":{"line":91,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":2},"end":{"line":106,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":2},"end":{"line":141,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":158,"character":2},"end":{"line":158,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":2},"end":{"line":168,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":9},"end":{"line":69,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":4},"end":{"line":139,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":8},"end":{"line":148,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":8},"end":{"line":149,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":21},"end":{"line":7,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":22},"end":{"line":58,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":12},"end":{"line":132,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":11},"end":{"line":30,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":6},"end":{"line":162,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":172,"character":6},"end":{"line":172,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua":[{"severity":2,"range":{"start":{"line":656,"character":2},"end":{"line":656,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":733,"character":2},"end":{"line":733,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":4},"end":{"line":507,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":685,"character":4},"end":{"line":685,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":699,"character":4},"end":{"line":699,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":194,"character":18},"end":{"line":194,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":17},"end":{"line":195,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":21},"end":{"line":197,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":4},"end":{"line":213,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":669,"character":9},"end":{"line":669,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":31},"end":{"line":189,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":453,"character":30},"end":{"line":453,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":54},"end":{"line":507,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":73},"end":{"line":507,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":685,"character":36},"end":{"line":685,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":316,"character":23},"end":{"line":316,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":9},"end":{"line":30,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":9},"end":{"line":32,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/session_picker.lua":[{"severity":2,"range":{"start":{"line":423,"character":2},"end":{"line":423,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":16},"end":{"line":233,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":25},"end":{"line":53,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":365,"character":6},"end":{"line":365,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":396,"character":6},"end":{"line":396,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":401,"character":6},"end":{"line":401,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":8},"end":{"line":342,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":10},"end":{"line":324,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":8},"end":{"line":402,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":22},"end":{"line":249,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":51},"end":{"line":402,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":69},"end":{"line":402,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":22},"end":{"line":54,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":253,"character":20},"end":{"line":253,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":20},"end":{"line":276,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":343,"character":22},"end":{"line":343,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":24},"end":{"line":107,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/timer.lua":[{"severity":2,"range":{"start":{"line":31,"character":18},"end":{"line":31,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":16},"end":{"line":25,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":53,"character":15},"end":{"line":53,"character":21}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":32,"character":45},"end":{"line":32,"character":51}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/helpers.lua":[{"severity":2,"range":{"start":{"line":112,"character":2},"end":{"line":112,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":2},"end":{"line":64,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":2},"end":{"line":78,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":2},"end":{"line":98,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":109,"character":26},"end":{"line":109,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":25},"end":{"line":96,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":9},"end":{"line":65,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":8},"end":{"line":91,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":4},"end":{"line":102,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":157,"character":9},"end":{"line":157,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":10},"end":{"line":237,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":21},"end":{"line":249,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":19},"end":{"line":45,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":6},"end":{"line":122,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":264,"character":14},"end":{"line":264,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":20},"end":{"line":39,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":15},"end":{"line":70,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":71,"character":10},"end":{"line":71,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":7},"end":{"line":86,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":25},"end":{"line":84,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":87,"character":12},"end":{"line":87,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":12},"end":{"line":262,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":263,"character":15},"end":{"line":263,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":177,"character":28},"end":{"line":177,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":17},"end":{"line":180,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":39},"end":{"line":197,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":36},"end":{"line":199,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/manual/init_replay.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":0},"end":{"line":21,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":0},"end":{"line":22,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":0},"end":{"line":23,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":0},"end":{"line":27,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":0},"end":{"line":29,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":0},"end":{"line":19,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":0},"end":{"line":24,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":0,"character":20},"end":{"line":0,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":2},"end":{"line":16,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":3},"end":{"line":8,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":5},"end":{"line":10,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/manual/renderer_replay.lua":[{"severity":2,"range":{"start":{"line":35,"character":2},"end":{"line":35,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":2},"end":{"line":134,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":2},"end":{"line":200,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":2},"end":{"line":205,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":2},"end":{"line":265,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":2},"end":{"line":266,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":284,"character":2},"end":{"line":284,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":289,"character":2},"end":{"line":289,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":293,"character":2},"end":{"line":293,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":2},"end":{"line":298,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":303,"character":2},"end":{"line":303,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":2},"end":{"line":307,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":311,"character":2},"end":{"line":311,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":315,"character":2},"end":{"line":315,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":2},"end":{"line":319,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":331,"character":2},"end":{"line":331,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":336,"character":2},"end":{"line":336,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":337,"character":2},"end":{"line":337,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":338,"character":2},"end":{"line":338,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":339,"character":2},"end":{"line":339,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":340,"character":2},"end":{"line":340,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":341,"character":2},"end":{"line":341,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":4},"end":{"line":112,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":152,"character":4},"end":{"line":152,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":4},"end":{"line":181,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":4},"end":{"line":189,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":4},"end":{"line":262,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":4},"end":{"line":356,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":20},"end":{"line":16,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":69},"end":{"line":35,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":6},"end":{"line":70,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":21},"end":{"line":134,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":16},"end":{"line":162,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":163,"character":19},"end":{"line":163,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":14},"end":{"line":168,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":57},"end":{"line":200,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":207,"character":4},"end":{"line":207,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":246,"character":4},"end":{"line":246,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":14},"end":{"line":255,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":256,"character":15},"end":{"line":256,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":257,"character":21},"end":{"line":257,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":4},"end":{"line":333,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":27},"end":{"line":26,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":176,"character":6},"end":{"line":176,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":47},"end":{"line":19,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":61},"end":{"line":28,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":152,"character":45},"end":{"line":152,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":173,"character":17},"end":{"line":173,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":49},"end":{"line":181,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":59},"end":{"line":189,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":6},"end":{"line":213,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":54},"end":{"line":258,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":325,"character":6},"end":{"line":325,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":79},"end":{"line":356,"character":82}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":6},"end":{"line":48,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":45},"end":{"line":70,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":18},"end":{"line":222,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":223,"character":21},"end":{"line":223,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":81},"end":{"line":333,"character":84}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":12},"end":{"line":54,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":12},"end":{"line":55,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":176,"character":66},"end":{"line":176,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":208,"character":13},"end":{"line":208,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":8},"end":{"line":51,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":8},"end":{"line":52,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":325,"character":61},"end":{"line":325,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/init.lua":[{"severity":2,"range":{"start":{"line":32,"character":0},"end":{"line":32,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":0},"end":{"line":9,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":0},"end":{"line":26,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":27},"end":{"line":4,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":24},"end":{"line":5,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":20},"end":{"line":8,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":3},"end":{"line":15,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":5},"end":{"line":17,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":2},"end":{"line":12,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":2},"end":{"line":62,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":2},"end":{"line":74,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":2},"end":{"line":80,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":4},"end":{"line":63,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":4},"end":{"line":64,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":24},"end":{"line":13,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":22},"end":{"line":17,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":4},"end":{"line":65,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":26},"end":{"line":27,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_client_spec.lua":[{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":2},"end":{"line":4,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":2},"end":{"line":15,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":2},"end":{"line":60,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_spec.lua":[{"severity":2,"range":{"start":{"line":7,"character":0},"end":{"line":7,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":2},"end":{"line":26,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":2},"end":{"line":114,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":2},"end":{"line":144,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":4},"end":{"line":66,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":4},"end":{"line":86,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":115,"character":4},"end":{"line":115,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":4},"end":{"line":155,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":165,"character":4},"end":{"line":165,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":4},"end":{"line":175,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":4},"end":{"line":187,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":198,"character":4},"end":{"line":198,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":4},"end":{"line":205,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":9},"end":{"line":12,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":6},"end":{"line":90,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":22},"end":{"line":94,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":31},"end":{"line":199,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":66},"end":{"line":201,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_file_spec.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":2},"end":{"line":18,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":2},"end":{"line":51,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":2},"end":{"line":66,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":2},"end":{"line":81,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":4},"end":{"line":10,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":24},"end":{"line":9,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":16},"end":{"line":61,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":16},"end":{"line":62,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":16},"end":{"line":63,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":16},"end":{"line":76,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":17},"end":{"line":77,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":16},"end":{"line":78,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":23},"end":{"line":35,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":52,"character":23},"end":{"line":59,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":67,"character":23},"end":{"line":74,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":83,"character":23},"end":{"line":90,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":2},"end":{"line":26,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":22},"end":{"line":11,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":20},"end":{"line":13,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_bar_spec.lua":[{"severity":2,"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":2},"end":{"line":32,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":109,"character":2},"end":{"line":109,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":2},"end":{"line":232,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":4},"end":{"line":21,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":4},"end":{"line":65,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":4},"end":{"line":81,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":4},"end":{"line":90,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":4},"end":{"line":106,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":4},"end":{"line":110,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":4},"end":{"line":121,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":4},"end":{"line":137,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":157,"character":4},"end":{"line":157,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":177,"character":4},"end":{"line":177,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":198,"character":4},"end":{"line":198,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":211,"character":4},"end":{"line":211,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":223,"character":4},"end":{"line":223,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":4},"end":{"line":233,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":24},"end":{"line":37,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":32},"end":{"line":41,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":18},"end":{"line":42,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":4},"end":{"line":69,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":4},"end":{"line":73,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":4},"end":{"line":77,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":4},"end":{"line":102,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":4},"end":{"line":103,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":4},"end":{"line":104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":32},"end":{"line":38,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":36},"end":{"line":39,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":36},"end":{"line":40,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":6},"end":{"line":212,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/util.lua":[{"severity":2,"range":{"start":{"line":61,"character":9},"end":{"line":61,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":18},"end":{"line":15,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":16},"end":{"line":27,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":16},"end":{"line":281,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":414,"character":9},"end":{"line":414,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":419,"character":9},"end":{"line":419,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":450,"character":24},"end":{"line":450,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":19},"end":{"line":14,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":19},"end":{"line":16,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":253,"character":25},"end":{"line":253,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":404,"character":20},"end":{"line":404,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":12},"end":{"line":237,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":28},"end":{"line":322,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":16},"end":{"line":247,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":21},"end":{"line":319,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":343,"character":20},"end":{"line":343,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":203,"character":27},"end":{"line":203,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":37},"end":{"line":255,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":31},"end":{"line":258,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":41},"end":{"line":319,"character":49}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":282,"character":7},"end":{"line":282,"character":13}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":238,"character":11},"end":{"line":238,"character":17}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/state.lua":[{"severity":2,"range":{"start":{"line":133,"character":2},"end":{"line":133,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":161,"character":14},"end":{"line":161,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":174,"character":14},"end":{"line":174,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":11},"end":{"line":195,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":10},"end":{"line":138,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":10},"end":{"line":187,"character":12}},"message":"Missing required fields in type `OpencodeState`: `input_content`, `is_opencode_focused`, `current_mode`, `last_output`, `restore_points`, `cost`, `tokens_count`, `job_count`, `api_client`, `required_version`, `append`, `remove`, `subscribe`, `subscribe`, `unsubscribe`, `is_running`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/opencode_server_spec.lua":[{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":2},"end":{"line":13,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":2},"end":{"line":114,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":4},"end":{"line":9,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":4},"end":{"line":68,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":117,"character":4},"end":{"line":117,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":22},"end":{"line":6,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":4},"end":{"line":108,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":4},"end":{"line":156,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":6},"end":{"line":26,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/session.lua":[{"severity":2,"range":{"start":{"line":54,"character":9},"end":{"line":54,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":4},"end":{"line":50,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":24},"end":{"line":114,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":15},"end":{"line":20,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":15},"end":{"line":28,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":15},"end":{"line":36,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":15},"end":{"line":94,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":135,"character":24},"end":{"line":135,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":33},"end":{"line":145,"character":36}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":69},"end":{"line":11,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":51},"end":{"line":50,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":72},"end":{"line":50,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":72,"character":17},"end":{"line":72,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":31},"end":{"line":144,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":178,"character":50},"end":{"line":178,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":31},"end":{"line":95,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":46},"end":{"line":95,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/context.lua":[{"severity":2,"range":{"start":{"line":206,"character":2},"end":{"line":206,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":2},"end":{"line":224,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":246,"character":4},"end":{"line":246,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":4},"end":{"line":247,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":4},"end":{"line":248,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":288,"character":4},"end":{"line":288,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":24},"end":{"line":74,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":18},"end":{"line":206,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":209,"character":15},"end":{"line":209,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":4},"end":{"line":218,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":18},"end":{"line":224,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":12},"end":{"line":50,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":12},"end":{"line":53,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":12},"end":{"line":56,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":24},"end":{"line":265,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":270,"character":7},"end":{"line":270,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":208,"character":24},"end":{"line":208,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":23},"end":{"line":106,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":251,"character":14},"end":{"line":251,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":26},"end":{"line":267,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":59},"end":{"line":96,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":37},"end":{"line":218,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":18},"end":{"line":206,"character":76}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":78},"end":{"line":206,"character":81}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":18},"end":{"line":224,"character":72}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":74},"end":{"line":224,"character":77}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":58},"end":{"line":206,"character":62}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":64},"end":{"line":206,"character":69}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":71},"end":{"line":206,"character":75}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":54},"end":{"line":224,"character":58}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":60},"end":{"line":224,"character":65}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":67},"end":{"line":224,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":208,"character":17},"end":{"line":208,"character":23}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/input_window.lua":[{"severity":2,"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":2},"end":{"line":54,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":2},"end":{"line":55,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":2},"end":{"line":95,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":97,"character":2},"end":{"line":97,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":2},"end":{"line":98,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":2},"end":{"line":100,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":2},"end":{"line":101,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":2},"end":{"line":104,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":2},"end":{"line":105,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":2},"end":{"line":106,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":2},"end":{"line":126,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":2},"end":{"line":170,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":2},"end":{"line":179,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":2},"end":{"line":197,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":2},"end":{"line":206,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":225,"character":2},"end":{"line":225,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":2},"end":{"line":245,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":2},"end":{"line":255,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":8},"end":{"line":44,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":8},"end":{"line":45,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":16},"end":{"line":81,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":22},"end":{"line":83,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":4},"end":{"line":90,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":50},"end":{"line":195,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":20},"end":{"line":5,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":22},"end":{"line":22,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":22},"end":{"line":121,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":23},"end":{"line":122,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":146,"character":4},"end":{"line":146,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":4},"end":{"line":162,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":54},"end":{"line":170,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":16},"end":{"line":181,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":215,"character":16},"end":{"line":215,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":20},"end":{"line":218,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":235,"character":16},"end":{"line":235,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":19},"end":{"line":88,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":11},"end":{"line":31,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":37},"end":{"line":53,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":43},"end":{"line":90,"character":46}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":135,"character":18},"end":{"line":135,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":18},"end":{"line":138,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":22},"end":{"line":139,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":56},"end":{"line":162,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":26},"end":{"line":258,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/ui.lua":[{"severity":2,"range":{"start":{"line":234,"character":2},"end":{"line":234,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":2},"end":{"line":68,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":2},"end":{"line":73,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":2},"end":{"line":74,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":117,"character":2},"end":{"line":117,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":2},"end":{"line":136,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":8},"end":{"line":22,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":8},"end":{"line":23,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":8},"end":{"line":25,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":8},"end":{"line":26,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":8},"end":{"line":27,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":8},"end":{"line":28,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":4},"end":{"line":54,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":9},"end":{"line":58,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":2},"end":{"line":80,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":22},"end":{"line":147,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":16},"end":{"line":164,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":4},"end":{"line":191,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":22},"end":{"line":218,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":18},"end":{"line":38,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":120,"character":10},"end":{"line":120,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":10},"end":{"line":139,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":42},"end":{"line":85,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":29},"end":{"line":86,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":5},"end":{"line":122,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":124,"character":6},"end":{"line":124,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":123,"character":7},"end":{"line":123,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/git_review.lua":[{"severity":2,"range":{"start":{"line":10,"character":16},"end":{"line":10,"character":30}},"message":"Undefined type or alias `vim.SystemOpts`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":19,"character":2},"end":{"line":19,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":2},"end":{"line":107,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":2},"end":{"line":356,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":4},"end":{"line":15,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":11},"end":{"line":22,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":20},"end":{"line":106,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":2},"end":{"line":292,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":17},"end":{"line":20,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":2},"end":{"line":260,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":4},"end":{"line":128,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":4},"end":{"line":141,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":6},"end":{"line":224,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":6},"end":{"line":233,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":234,"character":6},"end":{"line":234,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":4},"end":{"line":249,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":261,"character":4},"end":{"line":261,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":4},"end":{"line":283,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":4},"end":{"line":299,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":318,"character":4},"end":{"line":318,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":373,"character":6},"end":{"line":373,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":375,"character":6},"end":{"line":375,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":8},"end":{"line":68,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":8},"end":{"line":74,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":8},"end":{"line":80,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":4},"end":{"line":149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":25},"end":{"line":212,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":21},"end":{"line":213,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":310,"character":4},"end":{"line":310,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":49},"end":{"line":78,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":6},"end":{"line":150,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":172,"character":6},"end":{"line":172,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":190,"character":6},"end":{"line":190,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":6},"end":{"line":255,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":329,"character":4},"end":{"line":329,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":271,"character":8},"end":{"line":271,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":305,"character":6},"end":{"line":305,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":6},"end":{"line":324,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":330,"character":6},"end":{"line":330,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":373,"character":72},"end":{"line":373,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":375,"character":76},"end":{"line":375,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":29},"end":{"line":40,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":228,"character":7},"end":{"line":228,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":5},"end":{"line":287,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":13},"end":{"line":262,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":340,"character":10},"end":{"line":340,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":15},"end":{"line":151,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":331,"character":15},"end":{"line":331,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/server_job.lua":[{"severity":2,"range":{"start":{"line":100,"character":12},"end":{"line":100,"character":15}},"message":"Undefined type or alias `Job`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":11,"character":35},"end":{"line":11,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":6},"end":{"line":114,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":8},"end":{"line":56,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":25},"end":{"line":64,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":8},"end":{"line":118,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":124,"character":25},"end":{"line":124,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":51},"end":{"line":114,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":69},"end":{"line":114,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":10},"end":{"line":57,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":76},"end":{"line":118,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":12},"end":{"line":39,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":12},"end":{"line":46,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":62},"end":{"line":57,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":14},"end":{"line":40,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":14},"end":{"line":47,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":72},"end":{"line":40,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":66},"end":{"line":47,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_completion_spec.lua":[{"severity":2,"range":{"start":{"line":21,"character":0},"end":{"line":21,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":2},"end":{"line":92,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":2},"end":{"line":100,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":111,"character":2},"end":{"line":111,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":2},"end":{"line":242,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":421,"character":2},"end":{"line":421,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":486,"character":2},"end":{"line":486,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":4},"end":{"line":114,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":4},"end":{"line":119,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":4},"end":{"line":129,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":4},"end":{"line":162,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":4},"end":{"line":180,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":4},"end":{"line":199,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":4},"end":{"line":212,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":4},"end":{"line":245,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":274,"character":4},"end":{"line":274,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":280,"character":4},"end":{"line":280,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":4},"end":{"line":287,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":306,"character":4},"end":{"line":306,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":338,"character":4},"end":{"line":338,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":370,"character":4},"end":{"line":370,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":396,"character":4},"end":{"line":396,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":422,"character":4},"end":{"line":422,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":446,"character":4},"end":{"line":446,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":470,"character":4},"end":{"line":470,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":487,"character":4},"end":{"line":487,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":509,"character":4},"end":{"line":509,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":6},"end":{"line":249,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":6},"end":{"line":258,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":269,"character":6},"end":{"line":269,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":6},"end":{"line":250,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":251,"character":6},"end":{"line":251,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":259,"character":6},"end":{"line":259,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":6},"end":{"line":262,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":6},"end":{"line":265,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":15},"end":{"line":249,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":16},"end":{"line":258,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":173,"character":30},"end":{"line":173,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":188,"character":29},"end":{"line":188,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":526,"character":11},"end":{"line":526,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_spec.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":0},"end":{"line":29,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":0},"end":{"line":40,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":0},"end":{"line":50,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":0},"end":{"line":94,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":111,"character":0},"end":{"line":111,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":2},"end":{"line":45,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":2},"end":{"line":52,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":2},"end":{"line":69,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":2},"end":{"line":75,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":2},"end":{"line":95,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":2},"end":{"line":112,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":2},"end":{"line":118,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":125,"character":2},"end":{"line":125,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":2},"end":{"line":132,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":2},"end":{"line":136,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":4},"end":{"line":119,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":4},"end":{"line":126,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":97,"character":35},"end":{"line":97,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":42},"end":{"line":104,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":54},"end":{"line":105,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":17},"end":{"line":12,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/core_spec.lua":[{"severity":3,"range":{"start":{"line":246,"character":8},"end":{"line":246,"character":21}},"message":"Global variable in lowercase initial, Did you miss `local` or misspell it?","source":"Lua Diagnostics.","code":"lowercase-global"},{"severity":2,"range":{"start":{"line":30,"character":0},"end":{"line":30,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":2},"end":{"line":36,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":2},"end":{"line":130,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":174,"character":2},"end":{"line":174,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":2},"end":{"line":199,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":263,"character":2},"end":{"line":263,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":4},"end":{"line":103,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":131,"character":4},"end":{"line":131,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":4},"end":{"line":144,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":4},"end":{"line":151,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":4},"end":{"line":175,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":4},"end":{"line":200,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":221,"character":4},"end":{"line":221,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":240,"character":4},"end":{"line":240,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":278,"character":4},"end":{"line":278,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":284,"character":4},"end":{"line":284,"character":14}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":290,"character":4},"end":{"line":290,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":297,"character":4},"end":{"line":297,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":4},"end":{"line":307,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":317,"character":4},"end":{"line":317,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":22},"end":{"line":38,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":24},"end":{"line":40,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":4},"end":{"line":104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":26},"end":{"line":39,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":21},"end":{"line":37,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":285,"character":6},"end":{"line":285,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":301,"character":6},"end":{"line":301,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":311,"character":6},"end":{"line":311,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":321,"character":6},"end":{"line":321,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":214,"character":6},"end":{"line":214,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":279,"character":24},"end":{"line":279,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":286,"character":6},"end":{"line":286,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":6},"end":{"line":291,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":6},"end":{"line":298,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":308,"character":6},"end":{"line":308,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":318,"character":6},"end":{"line":318,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":280,"character":28},"end":{"line":280,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":21},"end":{"line":27,"character":3}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":88,"character":28},"end":{"line":94,"character":5}},"message":"Missing required fields in type `OpencodeServer`: `spawn_promise`, `shutdown_promise`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":146,"character":29},"end":{"line":146,"character":51}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":202,"character":29},"end":{"line":202,"character":45}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":243,"character":29},"end":{"line":243,"character":45}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":254,"character":20},"end":{"line":254,"character":58}},"message":"Missing required fields in type `OpencodeContextConfig`: `enabled`, `cursor_data`, `diagnostics`, `selection`, `agents`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/curl.lua":[{"severity":2,"range":{"start":{"line":39,"character":16},"end":{"line":39,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":4},"end":{"line":134,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":16},"end":{"line":81,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":15},"end":{"line":126,"character":16}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":126,"character":21},"end":{"line":126,"character":30}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/api_client.lua":[{"severity":2,"range":{"start":{"line":382,"character":12},"end":{"line":382,"character":15}},"message":"Undefined type or alias `Job`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":223,"character":164},"end":{"line":223,"character":168}},"message":"Undefined type or alias `Part`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":393,"character":28},"end":{"line":393,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":393,"character":45},"end":{"line":393,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/event_manager.lua":[{"severity":2,"data":"syntax","range":{"start":{"line":148,"character":118},"end":{"line":148,"character":118}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":149,"character":121},"end":{"line":149,"character":121}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":150,"character":108},"end":{"line":150,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":151,"character":108},"end":{"line":151,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":152,"character":117},"end":{"line":152,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":153,"character":117},"end":{"line":153,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":154,"character":112},"end":{"line":154,"character":112}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":155,"character":102},"end":{"line":155,"character":102}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":156,"character":108},"end":{"line":156,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":157,"character":108},"end":{"line":157,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":158,"character":104},"end":{"line":158,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":159,"character":114},"end":{"line":159,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":160,"character":114},"end":{"line":160,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":161,"character":100},"end":{"line":161,"character":100}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":162,"character":117},"end":{"line":162,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":163,"character":110},"end":{"line":163,"character":110}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":164,"character":104},"end":{"line":164,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":165,"character":115},"end":{"line":165,"character":115}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":166,"character":109},"end":{"line":166,"character":109}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":167,"character":113},"end":{"line":167,"character":113}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":168,"character":126},"end":{"line":168,"character":126}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":181,"character":118},"end":{"line":181,"character":118}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":182,"character":121},"end":{"line":182,"character":121}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":183,"character":108},"end":{"line":183,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":184,"character":108},"end":{"line":184,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":185,"character":117},"end":{"line":185,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":186,"character":117},"end":{"line":186,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":187,"character":112},"end":{"line":187,"character":112}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":188,"character":102},"end":{"line":188,"character":102}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":189,"character":108},"end":{"line":189,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":190,"character":108},"end":{"line":190,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":191,"character":104},"end":{"line":191,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":192,"character":114},"end":{"line":192,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":193,"character":114},"end":{"line":193,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":194,"character":100},"end":{"line":194,"character":100}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":195,"character":117},"end":{"line":195,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":196,"character":110},"end":{"line":196,"character":110}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":197,"character":104},"end":{"line":197,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":198,"character":115},"end":{"line":198,"character":115}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":199,"character":109},"end":{"line":199,"character":109}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":200,"character":113},"end":{"line":200,"character":113}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":201,"character":126},"end":{"line":201,"character":126}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"range":{"start":{"line":281,"character":39},"end":{"line":281,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":308,"character":10},"end":{"line":308,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":361,"character":8},"end":{"line":361,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/event_manager_spec.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":2},"end":{"line":9,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":2},"end":{"line":15,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":2},"end":{"line":64,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":2},"end":{"line":77,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":2},"end":{"line":93,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":113,"character":2},"end":{"line":113,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/id_spec.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":3,"character":2},"end":{"line":3,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":2},"end":{"line":14,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":2},"end":{"line":36,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":2},"end":{"line":49,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":2},"end":{"line":60,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":19},"end":{"line":9,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":19},"end":{"line":10,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":19},"end":{"line":20,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":19},"end":{"line":21,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/init_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":2},"end":{"line":12,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua":[{"severity":2,"range":{"start":{"line":339,"character":2},"end":{"line":339,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":28},"end":{"line":16,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":17},"end":{"line":107,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":4},"end":{"line":130,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":28},"end":{"line":169,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":4},"end":{"line":250,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":4},"end":{"line":267,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":272,"character":4},"end":{"line":272,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":4},"end":{"line":291,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":4},"end":{"line":299,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":6},"end":{"line":145,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":9},"end":{"line":298,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":6},"end":{"line":61,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":5},"end":{"line":249,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":6},"end":{"line":319,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":59},"end":{"line":101,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":55},"end":{"line":130,"character":58}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":6},"end":{"line":202,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":6},"end":{"line":252,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":97},"end":{"line":267,"character":100}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":274,"character":6},"end":{"line":274,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":39},"end":{"line":291,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":301,"character":6},"end":{"line":301,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":326,"character":24},"end":{"line":326,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":57},"end":{"line":145,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":75},"end":{"line":145,"character":78}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":8},"end":{"line":222,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":8},"end":{"line":226,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":19},"end":{"line":258,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":70},"end":{"line":61,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":6},"end":{"line":156,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":46},"end":{"line":319,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":62},"end":{"line":202,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":38},"end":{"line":222,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":51},"end":{"line":156,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":69},"end":{"line":156,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":59},"end":{"line":136,"character":64}},"message":"Undefined field `parts`.","source":"Lua Diagnostics.","code":"undefined-field"},{"severity":2,"range":{"start":{"line":136,"character":38},"end":{"line":136,"character":42}},"message":"Undefined field `info`.","source":"Lua Diagnostics.","code":"undefined-field"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/health.lua":[{"severity":2,"range":{"start":{"line":2,"character":15},"end":{"line":2,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":9},"end":{"line":6,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":9},"end":{"line":114,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":14},"end":{"line":154,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":17},"end":{"line":14,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":5},"end":{"line":148,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":18},"end":{"line":147,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/history.lua":[{"severity":2,"range":{"start":{"line":9,"character":29},"end":{"line":9,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/id.lua":[{"severity":2,"range":{"start":{"line":139,"character":9},"end":{"line":139,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":9},"end":{"line":101,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":11},"end":{"line":119,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":39},"end":{"line":66,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/keymap.lua":[{"severity":2,"range":{"start":{"line":38,"character":9},"end":{"line":38,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":9},"end":{"line":49,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":19},"end":{"line":15,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":8},"end":{"line":21,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":12},"end":{"line":74,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":12},"end":{"line":75,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":8},"end":{"line":19,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":8},"end":{"line":65,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":98},"end":{"line":21,"character":101}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/opencode_server.lua":[{"severity":2,"range":{"start":{"line":58,"character":34},"end":{"line":58,"character":53}},"message":"Undefined type or alias `vim.SystemCompleted`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":13},"end":{"line":66,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":12},"end":{"line":18,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/provider.lua":[{"severity":2,"range":{"start":{"line":22,"character":2},"end":{"line":22,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/promise.lua":[{"severity":2,"range":{"start":{"line":53,"character":10},"end":{"line":53,"character":15}},"message":"Undefined param `error`.","source":"Lua Diagnostics.","code":"undefined-doc-param"},{"severity":2,"range":{"start":{"line":5,"character":77},"end":{"line":5,"character":78}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":2,"character":37},"end":{"line":2,"character":38}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":5,"character":34},"end":{"line":5,"character":35}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":2,"character":62},"end":{"line":2,"character":63}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":42,"character":24},"end":{"line":42,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":25},"end":{"line":62,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":178,"character":18},"end":{"line":178,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":26},"end":{"line":103,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":27},"end":{"line":150,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/keymap_spec.lua":[{"severity":2,"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":2},"end":{"line":38,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":2},"end":{"line":44,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":2},"end":{"line":242,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":359,"character":2},"end":{"line":359,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":425,"character":2},"end":{"line":425,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":4},"end":{"line":79,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":4},"end":{"line":121,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":243,"character":4},"end":{"line":243,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":4},"end":{"line":276,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":309,"character":4},"end":{"line":309,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":4},"end":{"line":342,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":360,"character":4},"end":{"line":360,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":393,"character":4},"end":{"line":393,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":426,"character":4},"end":{"line":426,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":465,"character":4},"end":{"line":465,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":496,"character":4},"end":{"line":496,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":23},"end":{"line":21,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":26},"end":{"line":20,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":6},"end":{"line":281,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":306,"character":6},"end":{"line":306,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":365,"character":6},"end":{"line":365,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":389,"character":6},"end":{"line":389,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":278,"character":30},"end":{"line":278,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":362,"character":30},"end":{"line":362,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":390,"character":6},"end":{"line":390,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":421,"character":6},"end":{"line":421,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":461,"character":6},"end":{"line":461,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":493,"character":6},"end":{"line":493,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":521,"character":6},"end":{"line":521,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":456,"character":21},"end":{"line":456,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":457,"character":21},"end":{"line":457,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":458,"character":21},"end":{"line":458,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":295,"character":19},"end":{"line":295,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":369,"character":20},"end":{"line":369,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":378,"character":19},"end":{"line":378,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":394,"character":20},"end":{"line":394,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":430,"character":20},"end":{"line":430,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":469,"character":20},"end":{"line":469,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":500,"character":20},"end":{"line":500,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":428,"character":33},"end":{"line":428,"character":48}},"message":"Missing required fields in type `OpencodePermission`: `type`, `pattern`, `sessionID`, `messageID`, `title`, `metadata`, `time`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":467,"character":33},"end":{"line":467,"character":48}},"message":"Missing required fields in type `OpencodePermission`: `type`, `pattern`, `sessionID`, `messageID`, `title`, `metadata`, `time`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/plugin/opencode.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1,"character":3},"end":{"line":1,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/topbar.lua":[{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":2},"end":{"line":79,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":16},"end":{"line":65,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":10},"end":{"line":68,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":18},"end":{"line":64,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":72,"character":9},"end":{"line":72,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":4},"end":{"line":107,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":86},"end":{"line":108,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/review.lua":[{"severity":2,"range":{"start":{"line":71,"character":2},"end":{"line":71,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":2},"end":{"line":140,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":192,"character":2},"end":{"line":192,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":182,"character":2},"end":{"line":182,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":146,"character":4},"end":{"line":146,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":4},"end":{"line":147,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":4},"end":{"line":149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":4},"end":{"line":150,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":14},"end":{"line":48,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":19},"end":{"line":49,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":87,"character":4},"end":{"line":87,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":10},"end":{"line":88,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":17},"end":{"line":110,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":17},"end":{"line":141,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":18},"end":{"line":180,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":22},"end":{"line":181,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":20},"end":{"line":191,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":2},"end":{"line":307,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":22},"end":{"line":76,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":10},"end":{"line":77,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":6},"end":{"line":175,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":19},"end":{"line":19,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":26},"end":{"line":63,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":18},"end":{"line":64,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":6},"end":{"line":66,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":20},"end":{"line":79,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":4},"end":{"line":202,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":4},"end":{"line":292,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":4},"end":{"line":324,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":4},"end":{"line":333,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":8},"end":{"line":38,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":18},"end":{"line":50,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":18},"end":{"line":83,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":9},"end":{"line":91,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":158,"character":8},"end":{"line":158,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":8},"end":{"line":162,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":163,"character":8},"end":{"line":163,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":8},"end":{"line":164,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":167,"character":8},"end":{"line":167,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":8},"end":{"line":168,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":171,"character":8},"end":{"line":171,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":4},"end":{"line":210,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":312,"character":23},"end":{"line":312,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":313,"character":19},"end":{"line":313,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":31},"end":{"line":57,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":24},"end":{"line":155,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":159,"character":26},"end":{"line":159,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":18},"end":{"line":210,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":6},"end":{"line":224,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":239,"character":6},"end":{"line":239,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":29},"end":{"line":13,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":16},"end":{"line":101,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":296,"character":5},"end":{"line":296,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":328,"character":5},"end":{"line":328,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":29},"end":{"line":93,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":13},"end":{"line":94,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/snapshot.lua":[{"severity":2,"range":{"start":{"line":8,"character":16},"end":{"line":8,"character":30}},"message":"Undefined type or alias `vim.SystemOpts`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":217,"character":2},"end":{"line":217,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":236,"character":2},"end":{"line":236,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":2},"end":{"line":252,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":9},"end":{"line":61,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":9},"end":{"line":164,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":194,"character":4},"end":{"line":194,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":4},"end":{"line":30,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":4},"end":{"line":46,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":4},"end":{"line":70,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":4},"end":{"line":91,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":4},"end":{"line":122,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":4},"end":{"line":128,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":133,"character":4},"end":{"line":133,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":4},"end":{"line":154,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":160,"character":4},"end":{"line":160,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":4},"end":{"line":210,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":4},"end":{"line":226,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":4},"end":{"line":232,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":4},"end":{"line":242,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":4},"end":{"line":248,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":259,"character":19},"end":{"line":259,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":11},"end":{"line":20,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":20},"end":{"line":27,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":4},"end":{"line":85,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":14},"end":{"line":138,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":20},"end":{"line":140,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":24},"end":{"line":168,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":171,"character":20},"end":{"line":171,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":6},"end":{"line":187,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":24},"end":{"line":205,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":214,"character":4},"end":{"line":214,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":236,"character":51},"end":{"line":236,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":82},"end":{"line":252,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":17},"end":{"line":18,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":5},"end":{"line":84,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":24},"end":{"line":89,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":6},"end":{"line":191,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":36},"end":{"line":40,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":51},"end":{"line":52,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":80},"end":{"line":57,"character":83}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":36},"end":{"line":70,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":57},"end":{"line":91,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":36},"end":{"line":122,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":56},"end":{"line":128,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":133,"character":72},"end":{"line":133,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":36},"end":{"line":154,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":160,"character":67},"end":{"line":160,"character":70}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":61},"end":{"line":179,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":6},"end":{"line":212,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":78},"end":{"line":226,"character":81}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":82},"end":{"line":232,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":78},"end":{"line":242,"character":81}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":82},"end":{"line":248,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":8},"end":{"line":189,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":44},"end":{"line":89,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":184,"character":44},"end":{"line":184,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/files.lua":[{"severity":2,"range":{"start":{"line":75,"character":2},"end":{"line":75,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":5},"end":{"line":32,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":83},"end":{"line":75,"character":86}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":19},"end":{"line":82,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":14},"end":{"line":83,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":20},"end":{"line":86,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":15},"end":{"line":94,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":11},"end":{"line":136,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":7},"end":{"line":169,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":27},"end":{"line":18,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":18},"end":{"line":62,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":18},"end":{"line":129,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":24},"end":{"line":168,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":16},"end":{"line":19,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":13},"end":{"line":28,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":14},"end":{"line":33,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":13},"end":{"line":36,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":184,"character":31},"end":{"line":184,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":22},"end":{"line":169,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":54},"end":{"line":169,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":27},"end":{"line":170,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":131,"character":13},"end":{"line":131,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/api.lua":[{"severity":3,"range":{"start":{"line":650,"character":9},"end":{"line":650,"character":35}},"message":"Global variable in lowercase initial, Did you miss `local` or misspell it?","source":"Lua Diagnostics.","code":"lowercase-global"},{"severity":2,"range":{"start":{"line":207,"character":2},"end":{"line":207,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":2},"end":{"line":245,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":2},"end":{"line":260,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":385,"character":2},"end":{"line":385,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1175,"character":2},"end":{"line":1175,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":71,"character":9},"end":{"line":71,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":9},"end":{"line":78,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":4},"end":{"line":201,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":4},"end":{"line":322,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":332,"character":4},"end":{"line":332,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":4},"end":{"line":342,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":4},"end":{"line":354,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":358,"character":4},"end":{"line":358,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":363,"character":4},"end":{"line":363,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":461,"character":26},"end":{"line":461,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":522,"character":4},"end":{"line":522,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":542,"character":4},"end":{"line":542,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":548,"character":4},"end":{"line":548,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":553,"character":4},"end":{"line":553,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":575,"character":4},"end":{"line":575,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":600,"character":4},"end":{"line":600,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":621,"character":4},"end":{"line":621,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":627,"character":4},"end":{"line":627,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":690,"character":4},"end":{"line":690,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":695,"character":4},"end":{"line":695,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":740,"character":4},"end":{"line":740,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1091,"character":15},"end":{"line":1091,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1104,"character":4},"end":{"line":1104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1109,"character":16},"end":{"line":1109,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1149,"character":4},"end":{"line":1149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":207,"character":65},"end":{"line":207,"character":68}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":239,"character":23},"end":{"line":239,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":24},"end":{"line":245,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":254,"character":23},"end":{"line":254,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":38},"end":{"line":255,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":24},"end":{"line":260,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":531,"character":6},"end":{"line":531,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":567,"character":6},"end":{"line":567,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":592,"character":6},"end":{"line":592,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":612,"character":6},"end":{"line":612,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":641,"character":6},"end":{"line":641,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":747,"character":6},"end":{"line":747,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1115,"character":11},"end":{"line":1115,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1128,"character":11},"end":{"line":1128,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1134,"character":11},"end":{"line":1134,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1102,"character":18},"end":{"line":1102,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1113,"character":24},"end":{"line":1113,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1150,"character":6},"end":{"line":1150,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1154,"character":6},"end":{"line":1154,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":61},"end":{"line":179,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":61},"end":{"line":201,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":57},"end":{"line":322,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":332,"character":57},"end":{"line":332,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":57},"end":{"line":342,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":47},"end":{"line":354,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":358,"character":36},"end":{"line":358,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":363,"character":74},"end":{"line":363,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":522,"character":36},"end":{"line":522,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":542,"character":47},"end":{"line":542,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":548,"character":36},"end":{"line":548,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":553,"character":68},"end":{"line":553,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":562,"character":6},"end":{"line":562,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":575,"character":45},"end":{"line":575,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":582,"character":6},"end":{"line":582,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":600,"character":47},"end":{"line":600,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":607,"character":6},"end":{"line":607,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":621,"character":44},"end":{"line":621,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":627,"character":42},"end":{"line":627,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":636,"character":6},"end":{"line":636,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":690,"character":44},"end":{"line":690,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":695,"character":34},"end":{"line":695,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":713,"character":8},"end":{"line":713,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":729,"character":8},"end":{"line":729,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":740,"character":50},"end":{"line":740,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1104,"character":53},"end":{"line":1104,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":8},"end":{"line":568,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":8},"end":{"line":593,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":8},"end":{"line":613,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":8},"end":{"line":642,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":8},"end":{"line":748,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":776,"character":8},"end":{"line":776,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":845,"character":8},"end":{"line":845,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":875,"character":8},"end":{"line":875,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":909,"character":8},"end":{"line":909,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":922,"character":8},"end":{"line":922,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":931,"character":8},"end":{"line":931,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":954,"character":8},"end":{"line":954,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":969,"character":8},"end":{"line":969,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":981,"character":8},"end":{"line":981,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":993,"character":8},"end":{"line":993,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":996,"character":31},"end":{"line":996,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1023,"character":8},"end":{"line":1023,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":708,"character":8},"end":{"line":708,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":724,"character":8},"end":{"line":724,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1116,"character":13},"end":{"line":1116,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1129,"character":13},"end":{"line":1129,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1135,"character":13},"end":{"line":1135,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1152,"character":8},"end":{"line":1152,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":459,"character":38},"end":{"line":459,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":8},"end":{"line":563,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":608,"character":8},"end":{"line":608,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":637,"character":8},"end":{"line":637,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":10},"end":{"line":714,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":10},"end":{"line":730,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":896,"character":10},"end":{"line":896,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":906,"character":10},"end":{"line":906,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":52},"end":{"line":568,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":70},"end":{"line":568,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":50},"end":{"line":593,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":68},"end":{"line":593,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":52},"end":{"line":613,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":70},"end":{"line":613,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":54},"end":{"line":642,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":72},"end":{"line":642,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":56},"end":{"line":748,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":74},"end":{"line":748,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":776,"character":59},"end":{"line":776,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":845,"character":73},"end":{"line":845,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":875,"character":70},"end":{"line":875,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":909,"character":61},"end":{"line":909,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":922,"character":43},"end":{"line":922,"character":46}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":931,"character":62},"end":{"line":931,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":954,"character":71},"end":{"line":954,"character":74}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":969,"character":38},"end":{"line":969,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":981,"character":38},"end":{"line":981,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":993,"character":44},"end":{"line":993,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1023,"character":76},"end":{"line":1023,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":585,"character":10},"end":{"line":585,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":587,"character":10},"end":{"line":587,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":709,"character":10},"end":{"line":709,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":725,"character":10},"end":{"line":725,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":819,"character":35},"end":{"line":819,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":823,"character":12},"end":{"line":823,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":53},"end":{"line":563,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":584,"character":10},"end":{"line":584,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":608,"character":52},"end":{"line":608,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":51},"end":{"line":714,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":69},"end":{"line":714,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":51},"end":{"line":730,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":69},"end":{"line":730,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":896,"character":86},"end":{"line":896,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":906,"character":86},"end":{"line":906,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":585,"character":94},"end":{"line":585,"character":97}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":587,"character":60},"end":{"line":587,"character":63}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":823,"character":55},"end":{"line":823,"character":58}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":60},"end":{"line":245,"character":64}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":245,"character":66},"end":{"line":245,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":245,"character":73},"end":{"line":245,"character":77}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":60},"end":{"line":260,"character":64}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":66},"end":{"line":260,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":73},"end":{"line":260,"character":77}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/throttling_emitter.lua":[{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":4},"end":{"line":53,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/types.lua":[{"severity":2,"range":{"start":{"line":246,"character":28},"end":{"line":246,"character":54}},"message":"Undefined type or alias `vim.api.keyset.set_extmark`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":320,"character":24},"end":{"line":320,"character":38}},"message":"Undefined type or alias `vim.Diagnostic`.","source":"Lua Diagnostics.","code":"undefined-doc-name"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/config.lua":[{"severity":2,"range":{"start":{"line":178,"character":11},"end":{"line":178,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":4},"end":{"line":226,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":13},"end":{"line":247,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":9},"end":{"line":200,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":289,"character":31},"end":{"line":289,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":98},"end":{"line":226,"character":101}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":305,"character":11},"end":{"line":305,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/footer.lua":[{"severity":2,"range":{"start":{"line":85,"character":2},"end":{"line":85,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":2},"end":{"line":122,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":2},"end":{"line":129,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":2},"end":{"line":140,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":2},"end":{"line":154,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":2},"end":{"line":155,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":2},"end":{"line":156,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":20},"end":{"line":49,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":23},"end":{"line":84,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":8},"end":{"line":114,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":21},"end":{"line":128,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":21},"end":{"line":139,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":12},"end":{"line":62,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":10},"end":{"line":98,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":10},"end":{"line":99,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":113,"character":8},"end":{"line":113,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":10},"end":{"line":64,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}]}},"status":"completed","time":{"start":1762176906475,"end":1762176906837},"title":"lua/opencode/core.lua","input":{"newString":" if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)","filePath":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","oldString":" state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)"},"output":"\nThis file has errors, please fix\n\n\n\n"},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"reason":"tool-calls","cost":0,"id":"prt_a49edb65e001xdiFvgkXFJjIiw","messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","snapshot":"f33f38a70b284207e092c2c578a24e96fdd1bd4d","type":"step-finish","tokens":{"reasoning":0,"cache":{"read":10752,"write":0},"input":14938,"output":576},"sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176899112},"id":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":10752,"write":0},"input":14938,"output":576},"providerID":"github-copilot"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"files":["/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua"],"messageID":"msg_a49ed9828001mN6CDcWPnGnpHS","id":"prt_a49edb681001xxBeFUSvyhS2Eo","type":"patch","hash":"8e7903714919009004aad8754db0035fb47ecb24","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176899112,"completed":1762176906882},"id":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":10752,"write":0},"input":14938,"output":576},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176899112,"completed":1762176906890},"id":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":10752,"write":0},"input":14938,"output":576},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176899112,"completed":1762176906891},"id":"msg_a49ed9828001mN6CDcWPnGnpHS","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":10752,"write":0},"input":14938,"output":576},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176906900},"id":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":0,"write":0},"input":0,"output":0},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"id":"msg_a49ed91d6001coTsjFq9x6FF5W","time":{"created":1762176897494},"summary":{"diffs":[{"file":"lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":0,"additions":4,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"}]},"role":"user","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176906932},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Fixing param-type-not-match and need-check-nil in core.lua line 130","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_a49edb95a001BXEIud4AFAjA3v","snapshot":"f33f38a70b284207e092c2c578a24e96fdd1bd4d","type":"step-start","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"id"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" step"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" the"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" string"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"\n"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":")/"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, model","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" model"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"end"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" string"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `model","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"model"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `modelID` first, then `providerID`. Let's update the assignment to","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" to"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `modelID` first, then `providerID`. Let's update the assignment to match the expected order.\n\nI'll fix this now","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" now"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `modelID` first, then `providerID`. Let's update the assignment to match the expected order.\n\nI'll fix this now.","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176907612},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"."}},{"type":"message.part.updated","properties":{"part":{"callID":"call_Kwbm6aS5sRCah2asJyUHTyZu","id":"prt_a49edc06d001Em2jkf8QmWbwv3","tool":"edit","messageID":"msg_a49edb694001syExFxMUW1ik3n","state":{"status":"pending"},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"callID":"call_Kwbm6aS5sRCah2asJyUHTyZu","id":"prt_a49edc06d001Em2jkf8QmWbwv3","tool":"edit","messageID":"msg_a49edb694001syExFxMUW1ik3n","state":{"status":"running","input":{"newString":" params.model = { modelID = model, providerID = provider }","filePath":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","oldString":" params.model = { providerID = provider, modelID = model }"},"time":{"start":1762176909474}},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"file.edited","properties":{"file":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua"}},{"type":"message.part.updated","properties":{"part":{"text":"Step 1 is complete: nil check for `state.active_session` before accessing `.id` is added.\n\nNow, let's address step 2: Ensure the `model` field in `params` matches the expected type `{ modelID: string, providerID: string }`.\n\nCurrently, the code is:\n```lua\nif opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\nend\n```\nThe expected type is `{ modelID: string, providerID: string }`, but EmmyLua expects the order to be `modelID` first, then `providerID`. Let's update the assignment to match the expected order.\n\nI'll fix this now.","id":"prt_a49edb95c0019lorS0C7cytxrl","time":{"start":1762176909485,"end":1762176909485},"type":"text","messageID":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"callID":"call_Kwbm6aS5sRCah2asJyUHTyZu","id":"prt_a49edc06d001Em2jkf8QmWbwv3","tool":"edit","messageID":"msg_a49edb694001syExFxMUW1ik3n","state":{"metadata":{"filediff":{"file":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":1,"additions":1,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { modelID = model, providerID = provider }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"},"diff":"Index: /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n===================================================================\n--- /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n+++ /home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua\n@@ -114,9 +114,9 @@\n local params = {}\n \n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n- params.model = { providerID = provider, modelID = model }\n+ params.model = { modelID = model, providerID = provider }\n state.current_model = opts.model\n end\n \n if opts.agent then\n","diagnostics":{"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/autocmds.lua":[{"severity":2,"range":{"start":{"line":11,"character":2},"end":{"line":11,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":2},"end":{"line":37,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":2},"end":{"line":48,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":2},"end":{"line":58,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":16},"end":{"line":5,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":23},"end":{"line":47,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":9},"end":{"line":16,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":8},"end":{"line":17,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":44},"end":{"line":32,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":31},"end":{"line":33,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":23},"end":{"line":66,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":24},"end":{"line":62,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion.lua":[{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":59},"end":{"line":35,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":6},"end":{"line":90,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":6},"end":{"line":93,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/commands.lua":[{"severity":2,"range":{"start":{"line":81,"character":8},"end":{"line":81,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":37},"end":{"line":27,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":10},"end":{"line":75,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":56},"end":{"line":81,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/config_file.lua":[{"severity":2,"range":{"start":{"line":17,"character":4},"end":{"line":17,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":4},"end":{"line":34,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":14},"end":{"line":61,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":11},"end":{"line":90,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":53},"end":{"line":17,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":74},"end":{"line":17,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":54},"end":{"line":34,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":75},"end":{"line":34,"character":78}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":56},"end":{"line":51,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":77},"end":{"line":51,"character":80}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/blink_cmp.lua":[{"severity":2,"range":{"start":{"line":24,"character":9},"end":{"line":24,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":37},"end":{"line":35,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":49},"end":{"line":35,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/nvim_cmp.lua":[{"severity":2,"range":{"start":{"line":83,"character":18},"end":{"line":83,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":11},"end":{"line":26,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":14},"end":{"line":86,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":39},"end":{"line":34,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":51},"end":{"line":34,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/engines/vim_complete.lua":[{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":116,"character":25},"end":{"line":116,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":21},"end":{"line":20,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":15},"end":{"line":46,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":14},"end":{"line":47,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":15},"end":{"line":64,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":14},"end":{"line":65,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":37},"end":{"line":38,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":9},"end":{"line":85,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":49},"end":{"line":38,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":6},"end":{"line":108,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":6},"end":{"line":9,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":6},"end":{"line":10,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":41},"end":{"line":106,"character":44}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/context.lua":[{"severity":2,"range":{"start":{"line":286,"character":2},"end":{"line":286,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":290,"character":2},"end":{"line":290,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":2},"end":{"line":292,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":297,"character":2},"end":{"line":297,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":296,"character":2},"end":{"line":296,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":2},"end":{"line":298,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":2},"end":{"line":299,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":504,"character":2},"end":{"line":504,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":516,"character":2},"end":{"line":516,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":21},"end":{"line":58,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":27},"end":{"line":59,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":23},"end":{"line":73,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":22},"end":{"line":78,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":26},"end":{"line":79,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":4},"end":{"line":144,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":18},"end":{"line":218,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":25},"end":{"line":266,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":479,"character":18},"end":{"line":479,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":45},"end":{"line":28,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":29},"end":{"line":51,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":22},"end":{"line":92,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":115,"character":29},"end":{"line":115,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":29},"end":{"line":129,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":18},"end":{"line":141,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":142,"character":17},"end":{"line":142,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":9},"end":{"line":148,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":9},"end":{"line":150,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":9},"end":{"line":156,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":167,"character":29},"end":{"line":167,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":9},"end":{"line":179,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":182,"character":29},"end":{"line":182,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":196,"character":29},"end":{"line":196,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":8},"end":{"line":237,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":15},"end":{"line":249,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":21},"end":{"line":265,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":22},"end":{"line":281,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":282,"character":18},"end":{"line":282,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":22},"end":{"line":283,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":15},"end":{"line":287,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":21},"end":{"line":291,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":293,"character":19},"end":{"line":293,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":24},"end":{"line":298,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":312,"character":19},"end":{"line":312,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":479,"character":51},"end":{"line":479,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":483,"character":11},"end":{"line":483,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":492,"character":11},"end":{"line":492,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":503,"character":18},"end":{"line":503,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":11},"end":{"line":255,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":256,"character":16},"end":{"line":256,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":334,"character":11},"end":{"line":334,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":347,"character":11},"end":{"line":347,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":357,"character":11},"end":{"line":357,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":423,"character":27},"end":{"line":423,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":60},"end":{"line":30,"character":63}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":34},"end":{"line":83,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":34},"end":{"line":86,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":34},"end":{"line":89,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":31},"end":{"line":250,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":42},"end":{"line":354,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":9},"end":{"line":276,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":34},"end":{"line":266,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":509,"character":49},"end":{"line":509,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":521,"character":49},"end":{"line":521,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":38},"end":{"line":141,"character":42}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":64},"end":{"line":298,"character":68}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":70},"end":{"line":298,"character":75}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":298,"character":77},"end":{"line":298,"character":81}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":250,"character":51},"end":{"line":250,"character":55}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/sort.lua":[{"severity":2,"range":{"start":{"line":31,"character":40},"end":{"line":31,"character":43}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":40},"end":{"line":32,"character":43}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/context_bar.lua":[{"severity":2,"range":{"start":{"line":172,"character":2},"end":{"line":172,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":2},"end":{"line":162,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":16},"end":{"line":149,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":10},"end":{"line":151,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":18},"end":{"line":148,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":9},"end":{"line":155,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":4},"end":{"line":180,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":7},"end":{"line":98,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":7},"end":{"line":99,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":7},"end":{"line":100,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":20},"end":{"line":175,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/contextual_actions.lua":[{"severity":2,"range":{"start":{"line":22,"character":2},"end":{"line":22,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":2},"end":{"line":42,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":4},"end":{"line":82,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":16},"end":{"line":19,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":18},"end":{"line":20,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":6},"end":{"line":88,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":6},"end":{"line":26,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":6},"end":{"line":46,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":6},"end":{"line":63,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":8},"end":{"line":31,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":8},"end":{"line":54,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":10},"end":{"line":90,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":25},"end":{"line":27,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":25},"end":{"line":50,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":93,"character":27},"end":{"line":93,"character":33}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/debug_helper.lua":[{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":2},"end":{"line":77,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":2},"end":{"line":16,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":2},"end":{"line":76,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":19},"end":{"line":16,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":4},"end":{"line":20,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":4},"end":{"line":32,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":4},"end":{"line":64,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":4},"end":{"line":70,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":16},"end":{"line":75,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":18},"end":{"line":11,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":19},"end":{"line":12,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":23},"end":{"line":35,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":51},"end":{"line":46,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":19},"end":{"line":74,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":72},"end":{"line":77,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":5},"end":{"line":18,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":46},"end":{"line":32,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":48},"end":{"line":64,"character":51}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":45},"end":{"line":70,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/diff_tab.lua":[{"severity":2,"range":{"start":{"line":37,"character":2},"end":{"line":37,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":2},"end":{"line":56,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":24},"end":{"line":35,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":4},"end":{"line":43,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":4},"end":{"line":44,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":10},"end":{"line":14,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":27},"end":{"line":36,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":17},"end":{"line":38,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":18},"end":{"line":54,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":22},"end":{"line":55,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":22},"end":{"line":5,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":10},"end":{"line":6,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":6},"end":{"line":47,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":6},"end":{"line":48,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":20},"end":{"line":7,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":18},"end":{"line":10,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":9},"end":{"line":16,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":50},"end":{"line":35,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":23},"end":{"line":40,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":25},"end":{"line":44,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":23},"end":{"line":51,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":16},"end":{"line":25,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":29},"end":{"line":18,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":13},"end":{"line":19,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/file_picker.lua":[{"severity":2,"range":{"start":{"line":157,"character":2},"end":{"line":157,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":21},"end":{"line":103,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":22},"end":{"line":104,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":21},"end":{"line":105,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":11},"end":{"line":11,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":6},"end":{"line":130,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":6},"end":{"line":134,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":8},"end":{"line":132,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":26},"end":{"line":126,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/formatter.lua":[{"severity":2,"range":{"start":{"line":400,"character":43},"end":{"line":400,"character":57}},"message":"Undefined type or alias `vim.Diagnostic`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":160,"character":73},"end":{"line":160,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":37},"end":{"line":224,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":310,"character":16},"end":{"line":310,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":326,"character":19},"end":{"line":326,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":367,"character":19},"end":{"line":367,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":384,"character":19},"end":{"line":384,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":438,"character":5},"end":{"line":438,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":448,"character":19},"end":{"line":448,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":16},"end":{"line":563,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":698,"character":16},"end":{"line":698,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":437,"character":14},"end":{"line":437,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":6},"end":{"line":21,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":64},"end":{"line":283,"character":67}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":475,"character":27},"end":{"line":475,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":484,"character":30},"end":{"line":484,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":497,"character":27},"end":{"line":497,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":26},"end":{"line":563,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":700,"character":12},"end":{"line":700,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":798,"character":64},"end":{"line":798,"character":67}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":300,"character":10},"end":{"line":300,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":571,"character":19},"end":{"line":571,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":304,"character":34},"end":{"line":304,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":413,"character":17},"end":{"line":413,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":655,"character":23},"end":{"line":655,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":781,"character":42},"end":{"line":781,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":68},"end":{"line":299,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":769,"character":38},"end":{"line":769,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":49,"character":71},"end":{"line":49,"character":77}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/highlight.lua":[{"severity":2,"range":{"start":{"line":3,"character":19},"end":{"line":3,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":4},"end":{"line":6,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":4},"end":{"line":7,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":4},"end":{"line":8,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":4},"end":{"line":9,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":4},"end":{"line":10,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":4},"end":{"line":12,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":4},"end":{"line":15,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":4},"end":{"line":16,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":4},"end":{"line":17,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":4},"end":{"line":20,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":4},"end":{"line":21,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":4},"end":{"line":22,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":4},"end":{"line":23,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":4},"end":{"line":25,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":4},"end":{"line":26,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":4},"end":{"line":27,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":4},"end":{"line":29,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":4},"end":{"line":30,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":4},"end":{"line":32,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":4},"end":{"line":36,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":4},"end":{"line":37,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":4},"end":{"line":38,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":4},"end":{"line":43,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":4},"end":{"line":44,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":4},"end":{"line":46,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":4},"end":{"line":47,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":4},"end":{"line":48,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":4},"end":{"line":49,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":4},"end":{"line":50,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":4},"end":{"line":51,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":4},"end":{"line":53,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":4},"end":{"line":54,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":4},"end":{"line":55,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":4},"end":{"line":58,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":4},"end":{"line":59,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":4},"end":{"line":60,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":4},"end":{"line":61,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/icons.lua":[{"severity":2,"range":{"start":{"line":89,"character":6},"end":{"line":89,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":8},"end":{"line":90,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":10},"end":{"line":92,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/loading_animation.lua":[{"severity":2,"range":{"start":{"line":28,"character":11},"end":{"line":28,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":10},"end":{"line":13,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":4},"end":{"line":100,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":28},"end":{"line":45,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":9},"end":{"line":34,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":62},"end":{"line":34,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/mention.lua":[{"severity":2,"range":{"start":{"line":103,"character":2},"end":{"line":103,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":27},"end":{"line":4,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":2},"end":{"line":104,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":2},"end":{"line":105,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":8},"end":{"line":11,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":6},"end":{"line":33,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":23},"end":{"line":94,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":4},"end":{"line":112,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":32},"end":{"line":14,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":26},"end":{"line":56,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":7},"end":{"line":132,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":7},"end":{"line":137,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":116,"character":25},"end":{"line":116,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":27},"end":{"line":137,"character":31}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/navigation.lua":[{"severity":2,"range":{"start":{"line":53,"character":2},"end":{"line":53,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":2},"end":{"line":86,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":23},"end":{"line":32,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":34,"character":19},"end":{"line":34,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":21},"end":{"line":52,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":23},"end":{"line":66,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":19},"end":{"line":68,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":6},"end":{"line":47,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":6},"end":{"line":82,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/output.lua":[{"severity":2,"range":{"start":{"line":94,"character":9},"end":{"line":94,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":9},"end":{"line":110,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":30},"end":{"line":141,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":30},"end":{"line":145,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/output_window.lua":[{"severity":2,"range":{"start":{"line":4,"character":14},"end":{"line":4,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":2},"end":{"line":39,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":2},"end":{"line":40,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":2},"end":{"line":42,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":43,"character":2},"end":{"line":43,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":2},"end":{"line":44,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":2},"end":{"line":45,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":2},"end":{"line":47,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":2},"end":{"line":48,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":2},"end":{"line":49,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":2},"end":{"line":50,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":2},"end":{"line":51,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":2},"end":{"line":61,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":2},"end":{"line":89,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":2},"end":{"line":90,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":2},"end":{"line":91,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":2},"end":{"line":106,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":2},"end":{"line":141,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":158,"character":2},"end":{"line":158,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":2},"end":{"line":168,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":9},"end":{"line":69,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":4},"end":{"line":139,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":8},"end":{"line":148,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":8},"end":{"line":149,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":7,"character":21},"end":{"line":7,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":22},"end":{"line":58,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":12},"end":{"line":132,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":11},"end":{"line":30,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":6},"end":{"line":162,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":172,"character":6},"end":{"line":172,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/renderer.lua":[{"severity":2,"range":{"start":{"line":656,"character":2},"end":{"line":656,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":733,"character":2},"end":{"line":733,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":4},"end":{"line":507,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":685,"character":4},"end":{"line":685,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":699,"character":4},"end":{"line":699,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":194,"character":18},"end":{"line":194,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":17},"end":{"line":195,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":21},"end":{"line":197,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":4},"end":{"line":213,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":669,"character":9},"end":{"line":669,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":31},"end":{"line":189,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":453,"character":30},"end":{"line":453,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":54},"end":{"line":507,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":507,"character":73},"end":{"line":507,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":685,"character":36},"end":{"line":685,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":316,"character":23},"end":{"line":316,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":9},"end":{"line":30,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":9},"end":{"line":32,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/session_picker.lua":[{"severity":2,"range":{"start":{"line":423,"character":2},"end":{"line":423,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":16},"end":{"line":233,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":25},"end":{"line":53,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":365,"character":6},"end":{"line":365,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":396,"character":6},"end":{"line":396,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":401,"character":6},"end":{"line":401,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":8},"end":{"line":342,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":10},"end":{"line":324,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":8},"end":{"line":402,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":22},"end":{"line":249,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":51},"end":{"line":402,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":402,"character":69},"end":{"line":402,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":22},"end":{"line":54,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":253,"character":20},"end":{"line":253,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":20},"end":{"line":276,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":343,"character":22},"end":{"line":343,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":24},"end":{"line":107,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/timer.lua":[{"severity":2,"range":{"start":{"line":31,"character":18},"end":{"line":31,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":16},"end":{"line":25,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":53,"character":15},"end":{"line":53,"character":21}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":32,"character":45},"end":{"line":32,"character":51}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/helpers.lua":[{"severity":2,"range":{"start":{"line":112,"character":2},"end":{"line":112,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":2},"end":{"line":64,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":2},"end":{"line":78,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":2},"end":{"line":98,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":109,"character":26},"end":{"line":109,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":59,"character":2},"end":{"line":59,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":25},"end":{"line":96,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":9},"end":{"line":65,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":8},"end":{"line":91,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":4},"end":{"line":102,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":157,"character":9},"end":{"line":157,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":10},"end":{"line":237,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":21},"end":{"line":249,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":19},"end":{"line":45,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":6},"end":{"line":122,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":264,"character":14},"end":{"line":264,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":20},"end":{"line":39,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":15},"end":{"line":70,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":71,"character":10},"end":{"line":71,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":7},"end":{"line":86,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":25},"end":{"line":84,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":87,"character":12},"end":{"line":87,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":12},"end":{"line":262,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":263,"character":15},"end":{"line":263,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":177,"character":28},"end":{"line":177,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":17},"end":{"line":180,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":39},"end":{"line":197,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":36},"end":{"line":199,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/manual/init_replay.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":0},"end":{"line":21,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":0},"end":{"line":22,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":0},"end":{"line":23,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":0},"end":{"line":27,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":0},"end":{"line":29,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":0},"end":{"line":19,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":0},"end":{"line":24,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":0,"character":20},"end":{"line":0,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":2},"end":{"line":16,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":3},"end":{"line":8,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":5},"end":{"line":10,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/manual/renderer_replay.lua":[{"severity":2,"range":{"start":{"line":35,"character":2},"end":{"line":35,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":2},"end":{"line":134,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":2},"end":{"line":200,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":2},"end":{"line":205,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":2},"end":{"line":265,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":266,"character":2},"end":{"line":266,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":284,"character":2},"end":{"line":284,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":289,"character":2},"end":{"line":289,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":293,"character":2},"end":{"line":293,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":2},"end":{"line":298,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":303,"character":2},"end":{"line":303,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":2},"end":{"line":307,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":311,"character":2},"end":{"line":311,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":315,"character":2},"end":{"line":315,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":2},"end":{"line":319,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":331,"character":2},"end":{"line":331,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":336,"character":2},"end":{"line":336,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":337,"character":2},"end":{"line":337,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":338,"character":2},"end":{"line":338,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":339,"character":2},"end":{"line":339,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":340,"character":2},"end":{"line":340,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":341,"character":2},"end":{"line":341,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":4},"end":{"line":112,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":152,"character":4},"end":{"line":152,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":4},"end":{"line":181,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":4},"end":{"line":189,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":4},"end":{"line":262,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":4},"end":{"line":356,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":20},"end":{"line":16,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":35,"character":69},"end":{"line":35,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":6},"end":{"line":70,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":21},"end":{"line":134,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":16},"end":{"line":162,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":163,"character":19},"end":{"line":163,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":14},"end":{"line":168,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":57},"end":{"line":200,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":207,"character":4},"end":{"line":207,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":246,"character":4},"end":{"line":246,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":14},"end":{"line":255,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":256,"character":15},"end":{"line":256,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":257,"character":21},"end":{"line":257,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":4},"end":{"line":333,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":27},"end":{"line":26,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":176,"character":6},"end":{"line":176,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":47},"end":{"line":19,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":61},"end":{"line":28,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":152,"character":45},"end":{"line":152,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":173,"character":17},"end":{"line":173,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":49},"end":{"line":181,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":59},"end":{"line":189,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":6},"end":{"line":213,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":54},"end":{"line":258,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":325,"character":6},"end":{"line":325,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":79},"end":{"line":356,"character":82}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":6},"end":{"line":48,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":45},"end":{"line":70,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":18},"end":{"line":222,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":223,"character":21},"end":{"line":223,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":81},"end":{"line":333,"character":84}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":12},"end":{"line":54,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":12},"end":{"line":55,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":176,"character":66},"end":{"line":176,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":208,"character":13},"end":{"line":208,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":8},"end":{"line":51,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":8},"end":{"line":52,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":325,"character":61},"end":{"line":325,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/init.lua":[{"severity":2,"range":{"start":{"line":32,"character":0},"end":{"line":32,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":0},"end":{"line":9,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":0},"end":{"line":26,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":27},"end":{"line":4,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":24},"end":{"line":5,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":20},"end":{"line":8,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":3},"end":{"line":15,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":5},"end":{"line":17,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":2},"end":{"line":12,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":2},"end":{"line":62,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":2},"end":{"line":74,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":2},"end":{"line":80,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":4},"end":{"line":14,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":4},"end":{"line":18,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":4},"end":{"line":63,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":4},"end":{"line":64,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":24},"end":{"line":13,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":22},"end":{"line":17,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":4},"end":{"line":28,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":4},"end":{"line":65,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":26},"end":{"line":27,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_client_spec.lua":[{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":4,"character":2},"end":{"line":4,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":2},"end":{"line":15,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":2},"end":{"line":60,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_spec.lua":[{"severity":2,"range":{"start":{"line":7,"character":0},"end":{"line":7,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":2},"end":{"line":26,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":2},"end":{"line":114,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":2},"end":{"line":144,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":4},"end":{"line":31,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":4},"end":{"line":66,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":4},"end":{"line":86,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":115,"character":4},"end":{"line":115,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":4},"end":{"line":155,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":165,"character":4},"end":{"line":165,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":4},"end":{"line":175,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":4},"end":{"line":187,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":198,"character":4},"end":{"line":198,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":4},"end":{"line":205,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":9},"end":{"line":12,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":6},"end":{"line":90,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":22},"end":{"line":94,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":31},"end":{"line":199,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":66},"end":{"line":201,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_file_spec.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":2},"end":{"line":18,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":51,"character":2},"end":{"line":51,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":2},"end":{"line":66,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":2},"end":{"line":81,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":4},"end":{"line":10,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":4},"end":{"line":19,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":24},"end":{"line":9,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":16},"end":{"line":61,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":16},"end":{"line":62,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":16},"end":{"line":63,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":16},"end":{"line":76,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":17},"end":{"line":77,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":16},"end":{"line":78,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":23},"end":{"line":35,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":52,"character":23},"end":{"line":59,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":67,"character":23},"end":{"line":74,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":83,"character":23},"end":{"line":90,"character":5}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":2},"end":{"line":10,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":2},"end":{"line":26,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":22},"end":{"line":11,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":20},"end":{"line":13,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_bar_spec.lua":[{"severity":2,"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":2},"end":{"line":32,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":109,"character":2},"end":{"line":109,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":2},"end":{"line":232,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":4},"end":{"line":21,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":4},"end":{"line":65,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":4},"end":{"line":81,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":4},"end":{"line":90,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":4},"end":{"line":106,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":4},"end":{"line":110,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":4},"end":{"line":121,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":137,"character":4},"end":{"line":137,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":157,"character":4},"end":{"line":157,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":177,"character":4},"end":{"line":177,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":198,"character":4},"end":{"line":198,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":211,"character":4},"end":{"line":211,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":223,"character":4},"end":{"line":223,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":4},"end":{"line":233,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":24},"end":{"line":37,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":32},"end":{"line":41,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":18},"end":{"line":42,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":4},"end":{"line":69,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":4},"end":{"line":73,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":4},"end":{"line":77,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":4},"end":{"line":102,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":4},"end":{"line":103,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":4},"end":{"line":104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":32},"end":{"line":38,"character":35}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":36},"end":{"line":39,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":36},"end":{"line":40,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":6},"end":{"line":212,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/util.lua":[{"severity":2,"range":{"start":{"line":61,"character":9},"end":{"line":61,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":18},"end":{"line":15,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":16},"end":{"line":27,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":16},"end":{"line":281,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":414,"character":9},"end":{"line":414,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":419,"character":9},"end":{"line":419,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":450,"character":24},"end":{"line":450,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":19},"end":{"line":14,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":19},"end":{"line":16,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":253,"character":25},"end":{"line":253,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":404,"character":20},"end":{"line":404,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":237,"character":12},"end":{"line":237,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":28},"end":{"line":322,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":16},"end":{"line":247,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":21},"end":{"line":319,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":343,"character":20},"end":{"line":343,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":203,"character":27},"end":{"line":203,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":37},"end":{"line":255,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":31},"end":{"line":258,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":41},"end":{"line":319,"character":49}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 1.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":282,"character":7},"end":{"line":282,"character":13}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":238,"character":11},"end":{"line":238,"character":17}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/state.lua":[{"severity":2,"range":{"start":{"line":133,"character":2},"end":{"line":133,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":161,"character":14},"end":{"line":161,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":174,"character":14},"end":{"line":174,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":11},"end":{"line":195,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":10},"end":{"line":138,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":10},"end":{"line":187,"character":12}},"message":"Missing required fields in type `OpencodeState`: `input_content`, `is_opencode_focused`, `current_mode`, `last_output`, `restore_points`, `cost`, `tokens_count`, `job_count`, `api_client`, `required_version`, `append`, `remove`, `subscribe`, `subscribe`, `unsubscribe`, `is_running`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/opencode_server_spec.lua":[{"severity":2,"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":8,"character":2},"end":{"line":8,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":2},"end":{"line":13,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":2},"end":{"line":46,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":2},"end":{"line":114,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":4},"end":{"line":9,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":4},"end":{"line":68,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":117,"character":4},"end":{"line":117,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":22},"end":{"line":6,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":4},"end":{"line":108,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":4},"end":{"line":156,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":6},"end":{"line":26,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/session.lua":[{"severity":2,"range":{"start":{"line":54,"character":9},"end":{"line":54,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":4},"end":{"line":11,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":4},"end":{"line":50,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":24},"end":{"line":114,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":15},"end":{"line":20,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":15},"end":{"line":28,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":15},"end":{"line":36,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":15},"end":{"line":94,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":135,"character":24},"end":{"line":135,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":33},"end":{"line":145,"character":36}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":69},"end":{"line":11,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":51},"end":{"line":50,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":72},"end":{"line":50,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":72,"character":17},"end":{"line":72,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":31},"end":{"line":144,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":178,"character":50},"end":{"line":178,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":31},"end":{"line":95,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":46},"end":{"line":95,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/context.lua":[{"severity":2,"range":{"start":{"line":206,"character":2},"end":{"line":206,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":2},"end":{"line":224,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":246,"character":4},"end":{"line":246,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":4},"end":{"line":247,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":4},"end":{"line":248,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":288,"character":4},"end":{"line":288,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":24},"end":{"line":74,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":18},"end":{"line":206,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":209,"character":15},"end":{"line":209,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":4},"end":{"line":218,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":18},"end":{"line":224,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":12},"end":{"line":50,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":12},"end":{"line":53,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":12},"end":{"line":56,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":24},"end":{"line":265,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":270,"character":7},"end":{"line":270,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":208,"character":24},"end":{"line":208,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":23},"end":{"line":106,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":251,"character":14},"end":{"line":251,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":26},"end":{"line":267,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":59},"end":{"line":96,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":37},"end":{"line":218,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":18},"end":{"line":206,"character":76}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":78},"end":{"line":206,"character":81}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":18},"end":{"line":224,"character":72}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":74},"end":{"line":224,"character":77}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":58},"end":{"line":206,"character":62}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":64},"end":{"line":206,"character":69}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":206,"character":71},"end":{"line":206,"character":75}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":54},"end":{"line":224,"character":58}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":60},"end":{"line":224,"character":65}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":224,"character":67},"end":{"line":224,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"data":{"versions":["Lua 5.1","LuaJIT"]},"tags":[2],"range":{"start":{"line":208,"character":17},"end":{"line":208,"character":23}},"message":"Deprecated.(Defined in Lua 5.1/LuaJIT, current is Lua 5.4.)","source":"Lua Diagnostics.","code":"deprecated"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/input_window.lua":[{"severity":2,"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":2},"end":{"line":54,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":55,"character":2},"end":{"line":55,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":2},"end":{"line":95,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":97,"character":2},"end":{"line":97,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":2},"end":{"line":98,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":2},"end":{"line":100,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":2},"end":{"line":101,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":2},"end":{"line":104,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":2},"end":{"line":105,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":2},"end":{"line":106,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":2},"end":{"line":126,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":2},"end":{"line":170,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":2},"end":{"line":179,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":197,"character":2},"end":{"line":197,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":206,"character":2},"end":{"line":206,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":225,"character":2},"end":{"line":225,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":2},"end":{"line":245,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":2},"end":{"line":255,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":8},"end":{"line":44,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":8},"end":{"line":45,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":16},"end":{"line":81,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":22},"end":{"line":83,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":4},"end":{"line":90,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":195,"character":50},"end":{"line":195,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":20},"end":{"line":5,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":22},"end":{"line":22,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":22},"end":{"line":121,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":23},"end":{"line":122,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":146,"character":4},"end":{"line":146,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":4},"end":{"line":162,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":54},"end":{"line":170,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":16},"end":{"line":181,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":215,"character":16},"end":{"line":215,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":20},"end":{"line":218,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":235,"character":16},"end":{"line":235,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":19},"end":{"line":88,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":31,"character":11},"end":{"line":31,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":37},"end":{"line":53,"character":40}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":90,"character":43},"end":{"line":90,"character":46}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":135,"character":18},"end":{"line":135,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":18},"end":{"line":138,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":22},"end":{"line":139,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":56},"end":{"line":162,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":26},"end":{"line":258,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/ui.lua":[{"severity":2,"range":{"start":{"line":234,"character":2},"end":{"line":234,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":2},"end":{"line":68,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":73,"character":2},"end":{"line":73,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":2},"end":{"line":74,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":117,"character":2},"end":{"line":117,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":2},"end":{"line":136,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":8},"end":{"line":22,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":8},"end":{"line":23,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":8},"end":{"line":25,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":26,"character":8},"end":{"line":26,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":8},"end":{"line":27,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":8},"end":{"line":28,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":54,"character":4},"end":{"line":54,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":58,"character":9},"end":{"line":58,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":2},"end":{"line":80,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":4},"end":{"line":39,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":22},"end":{"line":147,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":16},"end":{"line":164,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":4},"end":{"line":191,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":218,"character":22},"end":{"line":218,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":18},"end":{"line":38,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":120,"character":10},"end":{"line":120,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":10},"end":{"line":139,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":42},"end":{"line":85,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":29},"end":{"line":86,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":5},"end":{"line":122,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":124,"character":6},"end":{"line":124,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":123,"character":7},"end":{"line":123,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/git_review.lua":[{"severity":2,"range":{"start":{"line":10,"character":16},"end":{"line":10,"character":30}},"message":"Undefined type or alias `vim.SystemOpts`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":19,"character":2},"end":{"line":19,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":2},"end":{"line":107,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":356,"character":2},"end":{"line":356,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":4},"end":{"line":15,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":22,"character":11},"end":{"line":22,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":106,"character":20},"end":{"line":106,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":2},"end":{"line":292,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":17},"end":{"line":20,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":2},"end":{"line":260,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":4},"end":{"line":128,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":4},"end":{"line":141,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":6},"end":{"line":224,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":233,"character":6},"end":{"line":233,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":234,"character":6},"end":{"line":234,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":4},"end":{"line":249,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":261,"character":4},"end":{"line":261,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":283,"character":4},"end":{"line":283,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":4},"end":{"line":299,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":318,"character":4},"end":{"line":318,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":373,"character":6},"end":{"line":373,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":375,"character":6},"end":{"line":375,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":8},"end":{"line":68,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":8},"end":{"line":74,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":80,"character":8},"end":{"line":80,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":4},"end":{"line":149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":25},"end":{"line":212,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":213,"character":21},"end":{"line":213,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":310,"character":4},"end":{"line":310,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":49},"end":{"line":78,"character":52}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":6},"end":{"line":150,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":172,"character":6},"end":{"line":172,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":190,"character":6},"end":{"line":190,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":6},"end":{"line":255,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":329,"character":4},"end":{"line":329,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":271,"character":8},"end":{"line":271,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":305,"character":6},"end":{"line":305,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":6},"end":{"line":324,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":330,"character":6},"end":{"line":330,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":373,"character":72},"end":{"line":373,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":375,"character":76},"end":{"line":375,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":29},"end":{"line":40,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":228,"character":7},"end":{"line":228,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":5},"end":{"line":287,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":13},"end":{"line":262,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":340,"character":10},"end":{"line":340,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":15},"end":{"line":151,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":331,"character":15},"end":{"line":331,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/server_job.lua":[{"severity":2,"range":{"start":{"line":100,"character":12},"end":{"line":100,"character":15}},"message":"Undefined type or alias `Job`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":11,"character":35},"end":{"line":11,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":6},"end":{"line":114,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":8},"end":{"line":56,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":25},"end":{"line":64,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":8},"end":{"line":118,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":124,"character":25},"end":{"line":124,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":51},"end":{"line":114,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":69},"end":{"line":114,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":10},"end":{"line":57,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":76},"end":{"line":118,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":12},"end":{"line":39,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":12},"end":{"line":46,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":62},"end":{"line":57,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":14},"end":{"line":40,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":14},"end":{"line":47,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":72},"end":{"line":40,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":47,"character":66},"end":{"line":47,"character":69}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_completion_spec.lua":[{"severity":2,"range":{"start":{"line":21,"character":0},"end":{"line":21,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":2},"end":{"line":24,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":92,"character":2},"end":{"line":92,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":100,"character":2},"end":{"line":100,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":111,"character":2},"end":{"line":111,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":2},"end":{"line":242,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":421,"character":2},"end":{"line":421,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":486,"character":2},"end":{"line":486,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":4},"end":{"line":114,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":4},"end":{"line":119,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":4},"end":{"line":129,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":4},"end":{"line":162,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":4},"end":{"line":180,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":4},"end":{"line":199,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":4},"end":{"line":212,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":4},"end":{"line":245,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":274,"character":4},"end":{"line":274,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":280,"character":4},"end":{"line":280,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":287,"character":4},"end":{"line":287,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":306,"character":4},"end":{"line":306,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":338,"character":4},"end":{"line":338,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":370,"character":4},"end":{"line":370,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":396,"character":4},"end":{"line":396,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":422,"character":4},"end":{"line":422,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":446,"character":4},"end":{"line":446,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":470,"character":4},"end":{"line":470,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":487,"character":4},"end":{"line":487,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":509,"character":4},"end":{"line":509,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":6},"end":{"line":249,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":6},"end":{"line":258,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":269,"character":6},"end":{"line":269,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":6},"end":{"line":250,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":251,"character":6},"end":{"line":251,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":259,"character":6},"end":{"line":259,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":262,"character":6},"end":{"line":262,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":265,"character":6},"end":{"line":265,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":15},"end":{"line":249,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":16},"end":{"line":258,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":173,"character":30},"end":{"line":173,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":188,"character":29},"end":{"line":188,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":526,"character":11},"end":{"line":526,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_spec.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":29,"character":0},"end":{"line":29,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":0},"end":{"line":40,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":0},"end":{"line":50,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":0},"end":{"line":94,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":111,"character":0},"end":{"line":111,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":23,"character":2},"end":{"line":23,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":2},"end":{"line":45,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":2},"end":{"line":52,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":2},"end":{"line":65,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":69,"character":2},"end":{"line":69,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":2},"end":{"line":75,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":95,"character":2},"end":{"line":95,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":112,"character":2},"end":{"line":112,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":118,"character":2},"end":{"line":118,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":125,"character":2},"end":{"line":125,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":132,"character":2},"end":{"line":132,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":2},"end":{"line":136,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":4},"end":{"line":119,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":4},"end":{"line":126,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":97,"character":35},"end":{"line":97,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":42},"end":{"line":104,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":54},"end":{"line":105,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":17},"end":{"line":12,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/core_spec.lua":[{"severity":3,"range":{"start":{"line":246,"character":8},"end":{"line":246,"character":21}},"message":"Global variable in lowercase initial, Did you miss `local` or misspell it?","source":"Lua Diagnostics.","code":"lowercase-global"},{"severity":2,"range":{"start":{"line":30,"character":0},"end":{"line":30,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":2},"end":{"line":36,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":2},"end":{"line":99,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":2},"end":{"line":130,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":174,"character":2},"end":{"line":174,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":199,"character":2},"end":{"line":199,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":263,"character":2},"end":{"line":263,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":4},"end":{"line":103,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":131,"character":4},"end":{"line":131,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":144,"character":4},"end":{"line":144,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":151,"character":4},"end":{"line":151,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":4},"end":{"line":175,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":4},"end":{"line":200,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":221,"character":4},"end":{"line":221,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":240,"character":4},"end":{"line":240,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":278,"character":4},"end":{"line":278,"character":15}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":284,"character":4},"end":{"line":284,"character":14}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":290,"character":4},"end":{"line":290,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":297,"character":4},"end":{"line":297,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":4},"end":{"line":307,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":317,"character":4},"end":{"line":317,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":22},"end":{"line":38,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":24},"end":{"line":40,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":42,"character":4},"end":{"line":42,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":104,"character":4},"end":{"line":104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":39,"character":26},"end":{"line":39,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":37,"character":21},"end":{"line":37,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":285,"character":6},"end":{"line":285,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":301,"character":6},"end":{"line":301,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":311,"character":6},"end":{"line":311,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":321,"character":6},"end":{"line":321,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":214,"character":6},"end":{"line":214,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":279,"character":24},"end":{"line":279,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":286,"character":6},"end":{"line":286,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":6},"end":{"line":291,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":6},"end":{"line":298,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":308,"character":6},"end":{"line":308,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":318,"character":6},"end":{"line":318,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":280,"character":28},"end":{"line":280,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":11,"character":21},"end":{"line":27,"character":3}},"message":"Missing required fields in type `OpencodeApiClient`: `base_url`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":88,"character":28},"end":{"line":94,"character":5}},"message":"Missing required fields in type `OpencodeServer`: `spawn_promise`, `shutdown_promise`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":146,"character":29},"end":{"line":146,"character":51}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":202,"character":29},"end":{"line":202,"character":45}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":243,"character":29},"end":{"line":243,"character":45}},"message":"Missing required fields in type `Session`: `workspace`, `description`, `modified`, `path`, `messages_path`, `parts_path`, `snapshot_path`, `cache_path`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":254,"character":20},"end":{"line":254,"character":58}},"message":"Missing required fields in type `OpencodeContextConfig`: `enabled`, `cursor_data`, `diagnostics`, `selection`, `agents`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/curl.lua":[{"severity":2,"range":{"start":{"line":39,"character":16},"end":{"line":39,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":134,"character":4},"end":{"line":134,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":81,"character":16},"end":{"line":81,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":126,"character":15},"end":{"line":126,"character":16}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":126,"character":21},"end":{"line":126,"character":30}},"message":"This function expects a maximum of 0 argument(s) but instead it is receiving 2.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/api_client.lua":[{"severity":2,"range":{"start":{"line":382,"character":12},"end":{"line":382,"character":15}},"message":"Undefined type or alias `Job`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":223,"character":164},"end":{"line":223,"character":168}},"message":"Undefined type or alias `Part`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":393,"character":28},"end":{"line":393,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":393,"character":45},"end":{"line":393,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/event_manager.lua":[{"severity":2,"data":"syntax","range":{"start":{"line":148,"character":118},"end":{"line":148,"character":118}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":149,"character":121},"end":{"line":149,"character":121}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":150,"character":108},"end":{"line":150,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":151,"character":108},"end":{"line":151,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":152,"character":117},"end":{"line":152,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":153,"character":117},"end":{"line":153,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":154,"character":112},"end":{"line":154,"character":112}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":155,"character":102},"end":{"line":155,"character":102}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":156,"character":108},"end":{"line":156,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":157,"character":108},"end":{"line":157,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":158,"character":104},"end":{"line":158,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":159,"character":114},"end":{"line":159,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":160,"character":114},"end":{"line":160,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":161,"character":100},"end":{"line":161,"character":100}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":162,"character":117},"end":{"line":162,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":163,"character":110},"end":{"line":163,"character":110}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":164,"character":104},"end":{"line":164,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":165,"character":115},"end":{"line":165,"character":115}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":166,"character":109},"end":{"line":166,"character":109}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":167,"character":113},"end":{"line":167,"character":113}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":168,"character":126},"end":{"line":168,"character":126}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":181,"character":118},"end":{"line":181,"character":118}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":182,"character":121},"end":{"line":182,"character":121}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":183,"character":108},"end":{"line":183,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":184,"character":108},"end":{"line":184,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":185,"character":117},"end":{"line":185,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":186,"character":117},"end":{"line":186,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":187,"character":112},"end":{"line":187,"character":112}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":188,"character":102},"end":{"line":188,"character":102}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":189,"character":108},"end":{"line":189,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":190,"character":108},"end":{"line":190,"character":108}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":191,"character":104},"end":{"line":191,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":192,"character":114},"end":{"line":192,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":193,"character":114},"end":{"line":193,"character":114}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":194,"character":100},"end":{"line":194,"character":100}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":195,"character":117},"end":{"line":195,"character":117}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":196,"character":110},"end":{"line":196,"character":110}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":197,"character":104},"end":{"line":197,"character":104}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":198,"character":115},"end":{"line":198,"character":115}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":199,"character":109},"end":{"line":199,"character":109}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":200,"character":113},"end":{"line":200,"character":113}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"data":"syntax","range":{"start":{"line":201,"character":126},"end":{"line":201,"character":126}},"message":"`)` expected.","source":"Lua Syntax Check.","code":"luadoc-miss-symbol"},{"severity":2,"range":{"start":{"line":281,"character":39},"end":{"line":281,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":308,"character":10},"end":{"line":308,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":361,"character":8},"end":{"line":361,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/event_manager_spec.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":5,"character":2},"end":{"line":5,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":2},"end":{"line":9,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":2},"end":{"line":15,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":2},"end":{"line":21,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":2},"end":{"line":41,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":2},"end":{"line":64,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":2},"end":{"line":77,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":2},"end":{"line":93,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":102,"character":2},"end":{"line":102,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":113,"character":2},"end":{"line":113,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":56,"character":4},"end":{"line":56,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/id_spec.lua":[{"severity":2,"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":3,"character":2},"end":{"line":3,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":2},"end":{"line":14,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":25,"character":2},"end":{"line":25,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":2},"end":{"line":30,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":2},"end":{"line":36,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":2},"end":{"line":49,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":60,"character":2},"end":{"line":60,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":9,"character":19},"end":{"line":9,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":10,"character":19},"end":{"line":10,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":19},"end":{"line":20,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":19},"end":{"line":21,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/init_spec.lua":[{"severity":2,"range":{"start":{"line":5,"character":0},"end":{"line":5,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":2},"end":{"line":6,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":12,"character":2},"end":{"line":12,"character":4}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua":[{"severity":2,"range":{"start":{"line":339,"character":2},"end":{"line":339,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":16,"character":28},"end":{"line":16,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":4},"end":{"line":101,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":17},"end":{"line":107,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":4},"end":{"line":130,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":28},"end":{"line":169,"character":31}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":250,"character":4},"end":{"line":250,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":4},"end":{"line":267,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":272,"character":4},"end":{"line":272,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":4},"end":{"line":291,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":299,"character":4},"end":{"line":299,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":6},"end":{"line":145,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":298,"character":9},"end":{"line":298,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":6},"end":{"line":61,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":249,"character":5},"end":{"line":249,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":6},"end":{"line":319,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":59},"end":{"line":101,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":130,"character":55},"end":{"line":130,"character":58}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":6},"end":{"line":202,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":6},"end":{"line":252,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":267,"character":97},"end":{"line":267,"character":100}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":274,"character":6},"end":{"line":274,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":291,"character":39},"end":{"line":291,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":301,"character":6},"end":{"line":301,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":326,"character":24},"end":{"line":326,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":57},"end":{"line":145,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":75},"end":{"line":145,"character":78}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":8},"end":{"line":222,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":8},"end":{"line":226,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":258,"character":19},"end":{"line":258,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":70},"end":{"line":61,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":6},"end":{"line":156,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":319,"character":46},"end":{"line":319,"character":49}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":62},"end":{"line":202,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":222,"character":38},"end":{"line":222,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":51},"end":{"line":156,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":69},"end":{"line":156,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":59},"end":{"line":136,"character":64}},"message":"Undefined field `parts`.","source":"Lua Diagnostics.","code":"undefined-field"},{"severity":2,"range":{"start":{"line":136,"character":38},"end":{"line":136,"character":42}},"message":"Undefined field `info`.","source":"Lua Diagnostics.","code":"undefined-field"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/health.lua":[{"severity":2,"range":{"start":{"line":2,"character":15},"end":{"line":2,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":6,"character":9},"end":{"line":6,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":9},"end":{"line":114,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":14},"end":{"line":154,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":14,"character":17},"end":{"line":14,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":148,"character":5},"end":{"line":148,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":18},"end":{"line":147,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/history.lua":[{"severity":2,"range":{"start":{"line":9,"character":29},"end":{"line":9,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/id.lua":[{"severity":2,"range":{"start":{"line":139,"character":9},"end":{"line":139,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":9},"end":{"line":101,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":119,"character":11},"end":{"line":119,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":39},"end":{"line":66,"character":42}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/keymap.lua":[{"severity":2,"range":{"start":{"line":38,"character":9},"end":{"line":38,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":9},"end":{"line":49,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":15,"character":19},"end":{"line":15,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":8},"end":{"line":21,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":74,"character":12},"end":{"line":74,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":12},"end":{"line":75,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":8},"end":{"line":19,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":8},"end":{"line":65,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":98},"end":{"line":21,"character":101}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/opencode_server.lua":[{"severity":2,"range":{"start":{"line":58,"character":34},"end":{"line":58,"character":53}},"message":"Undefined type or alias `vim.SystemCompleted`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":13},"end":{"line":66,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":12},"end":{"line":18,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/provider.lua":[{"severity":2,"range":{"start":{"line":22,"character":2},"end":{"line":22,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/promise.lua":[{"severity":2,"range":{"start":{"line":53,"character":10},"end":{"line":53,"character":15}},"message":"Undefined param `error`.","source":"Lua Diagnostics.","code":"undefined-doc-param"},{"severity":2,"range":{"start":{"line":5,"character":77},"end":{"line":5,"character":78}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":2,"character":37},"end":{"line":2,"character":38}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":5,"character":34},"end":{"line":5,"character":35}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":2,"character":62},"end":{"line":2,"character":63}},"message":"Undefined type or alias `T`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":42,"character":24},"end":{"line":42,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":25},"end":{"line":62,"character":28}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":178,"character":18},"end":{"line":178,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":103,"character":26},"end":{"line":103,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":27},"end":{"line":150,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/tests/unit/keymap_spec.lua":[{"severity":2,"range":{"start":{"line":6,"character":0},"end":{"line":6,"character":8}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":13}},"message":"Undefined global `before_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":2},"end":{"line":38,"character":12}},"message":"Undefined global `after_each`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":44,"character":2},"end":{"line":44,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":2},"end":{"line":242,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":359,"character":2},"end":{"line":359,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":425,"character":2},"end":{"line":425,"character":10}},"message":"Undefined global `describe`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":4},"end":{"line":33,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":41,"character":4},"end":{"line":41,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":45,"character":4},"end":{"line":45,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":4},"end":{"line":79,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":121,"character":4},"end":{"line":121,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":243,"character":4},"end":{"line":243,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":276,"character":4},"end":{"line":276,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":309,"character":4},"end":{"line":309,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":4},"end":{"line":342,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":360,"character":4},"end":{"line":360,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":393,"character":4},"end":{"line":393,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":426,"character":4},"end":{"line":426,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":465,"character":4},"end":{"line":465,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":496,"character":4},"end":{"line":496,"character":6}},"message":"Undefined global `it`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":21,"character":23},"end":{"line":21,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":24,"character":4},"end":{"line":24,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":26},"end":{"line":20,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":281,"character":6},"end":{"line":281,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":306,"character":6},"end":{"line":306,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":365,"character":6},"end":{"line":365,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":389,"character":6},"end":{"line":389,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":278,"character":30},"end":{"line":278,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":362,"character":30},"end":{"line":362,"character":33}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":390,"character":6},"end":{"line":390,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":421,"character":6},"end":{"line":421,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":461,"character":6},"end":{"line":461,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":493,"character":6},"end":{"line":493,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":521,"character":6},"end":{"line":521,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":456,"character":21},"end":{"line":456,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":457,"character":21},"end":{"line":457,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":458,"character":21},"end":{"line":458,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":295,"character":19},"end":{"line":295,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":369,"character":20},"end":{"line":369,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":378,"character":19},"end":{"line":378,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":394,"character":20},"end":{"line":394,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":430,"character":20},"end":{"line":430,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":469,"character":20},"end":{"line":469,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":500,"character":20},"end":{"line":500,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":428,"character":33},"end":{"line":428,"character":48}},"message":"Missing required fields in type `OpencodePermission`: `type`, `pattern`, `sessionID`, `messageID`, `title`, `metadata`, `time`","source":"Lua Diagnostics.","code":"missing-fields"},{"severity":2,"range":{"start":{"line":467,"character":33},"end":{"line":467,"character":48}},"message":"Missing required fields in type `OpencodePermission`: `type`, `pattern`, `sessionID`, `messageID`, `title`, `metadata`, `time`","source":"Lua Diagnostics.","code":"missing-fields"}],"/home/francis/Projects/_nvim/opencode.nvim/plugin/opencode.lua":[{"severity":2,"range":{"start":{"line":4,"character":0},"end":{"line":4,"character":3}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1,"character":3},"end":{"line":1,"character":6}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/topbar.lua":[{"severity":2,"range":{"start":{"line":96,"character":2},"end":{"line":96,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":2},"end":{"line":79,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":65,"character":16},"end":{"line":65,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":68,"character":10},"end":{"line":68,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":18},"end":{"line":64,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":72,"character":9},"end":{"line":72,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":105,"character":4},"end":{"line":105,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":107,"character":4},"end":{"line":107,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":108,"character":86},"end":{"line":108,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/review.lua":[{"severity":2,"range":{"start":{"line":71,"character":2},"end":{"line":71,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":2},"end":{"line":140,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":192,"character":2},"end":{"line":192,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":182,"character":2},"end":{"line":182,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":145,"character":4},"end":{"line":145,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":146,"character":4},"end":{"line":146,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":147,"character":4},"end":{"line":147,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":149,"character":4},"end":{"line":149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":150,"character":4},"end":{"line":150,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":48,"character":14},"end":{"line":48,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":19},"end":{"line":49,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":87,"character":4},"end":{"line":87,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":88,"character":10},"end":{"line":88,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":110,"character":17},"end":{"line":110,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":141,"character":17},"end":{"line":141,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":180,"character":18},"end":{"line":180,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":181,"character":22},"end":{"line":181,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":20},"end":{"line":191,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":307,"character":2},"end":{"line":307,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":76,"character":22},"end":{"line":76,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":77,"character":10},"end":{"line":77,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":175,"character":6},"end":{"line":175,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":19},"end":{"line":19,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":63,"character":26},"end":{"line":63,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":18},"end":{"line":64,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":66,"character":6},"end":{"line":66,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":79,"character":20},"end":{"line":79,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":202,"character":4},"end":{"line":202,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":292,"character":4},"end":{"line":292,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":324,"character":4},"end":{"line":324,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":333,"character":4},"end":{"line":333,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":38,"character":8},"end":{"line":38,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":50,"character":18},"end":{"line":50,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":18},"end":{"line":83,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":9},"end":{"line":91,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":158,"character":8},"end":{"line":158,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":162,"character":8},"end":{"line":162,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":163,"character":8},"end":{"line":163,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":8},"end":{"line":164,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":167,"character":8},"end":{"line":167,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":8},"end":{"line":168,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":171,"character":8},"end":{"line":171,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":4},"end":{"line":210,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":312,"character":23},"end":{"line":312,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":313,"character":19},"end":{"line":313,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":31},"end":{"line":57,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":24},"end":{"line":155,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":159,"character":26},"end":{"line":159,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":18},"end":{"line":210,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":224,"character":6},"end":{"line":224,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":239,"character":6},"end":{"line":239,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":29},"end":{"line":13,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":101,"character":16},"end":{"line":101,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":296,"character":5},"end":{"line":296,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":328,"character":5},"end":{"line":328,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":93,"character":29},"end":{"line":93,"character":32}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":13},"end":{"line":94,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/snapshot.lua":[{"severity":2,"range":{"start":{"line":8,"character":16},"end":{"line":8,"character":30}},"message":"Undefined type or alias `vim.SystemOpts`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":17,"character":2},"end":{"line":17,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":217,"character":2},"end":{"line":217,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":236,"character":2},"end":{"line":236,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":2},"end":{"line":252,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":61,"character":9},"end":{"line":61,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":164,"character":9},"end":{"line":164,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":194,"character":4},"end":{"line":194,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":13,"character":4},"end":{"line":13,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":30,"character":4},"end":{"line":30,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":4},"end":{"line":40,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":46,"character":4},"end":{"line":46,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":4},"end":{"line":52,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":4},"end":{"line":57,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":4},"end":{"line":70,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":4},"end":{"line":91,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":4},"end":{"line":122,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":4},"end":{"line":128,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":133,"character":4},"end":{"line":133,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":4},"end":{"line":154,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":160,"character":4},"end":{"line":160,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":210,"character":4},"end":{"line":210,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":4},"end":{"line":226,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":4},"end":{"line":232,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":4},"end":{"line":242,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":4},"end":{"line":248,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":259,"character":19},"end":{"line":259,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":20,"character":11},"end":{"line":20,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":27,"character":20},"end":{"line":27,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":85,"character":4},"end":{"line":85,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":138,"character":14},"end":{"line":138,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":20},"end":{"line":140,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":24},"end":{"line":168,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":171,"character":20},"end":{"line":171,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":187,"character":6},"end":{"line":187,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":205,"character":24},"end":{"line":205,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":214,"character":4},"end":{"line":214,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":236,"character":51},"end":{"line":236,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":252,"character":82},"end":{"line":252,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":17},"end":{"line":18,"character":20}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":5},"end":{"line":84,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":24},"end":{"line":89,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":191,"character":6},"end":{"line":191,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":40,"character":36},"end":{"line":40,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":52,"character":51},"end":{"line":52,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":57,"character":80},"end":{"line":57,"character":83}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":70,"character":36},"end":{"line":70,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":91,"character":57},"end":{"line":91,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":36},"end":{"line":122,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":56},"end":{"line":128,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":133,"character":72},"end":{"line":133,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":36},"end":{"line":154,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":160,"character":67},"end":{"line":160,"character":70}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":61},"end":{"line":179,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":212,"character":6},"end":{"line":212,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":78},"end":{"line":226,"character":81}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":232,"character":82},"end":{"line":232,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":242,"character":78},"end":{"line":242,"character":81}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":248,"character":82},"end":{"line":248,"character":85}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":189,"character":8},"end":{"line":189,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":89,"character":44},"end":{"line":89,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":184,"character":44},"end":{"line":184,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/completion/files.lua":[{"severity":2,"range":{"start":{"line":75,"character":2},"end":{"line":75,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":32,"character":5},"end":{"line":32,"character":8}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":75,"character":83},"end":{"line":75,"character":86}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":82,"character":19},"end":{"line":82,"character":22}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":83,"character":14},"end":{"line":83,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":86,"character":20},"end":{"line":86,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":94,"character":15},"end":{"line":94,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":136,"character":11},"end":{"line":136,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":7},"end":{"line":169,"character":10}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":18,"character":27},"end":{"line":18,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":18},"end":{"line":62,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":18},"end":{"line":129,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":168,"character":24},"end":{"line":168,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":19,"character":16},"end":{"line":19,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":28,"character":13},"end":{"line":28,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":33,"character":14},"end":{"line":33,"character":17}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":36,"character":13},"end":{"line":36,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":184,"character":31},"end":{"line":184,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":22},"end":{"line":169,"character":25}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":169,"character":54},"end":{"line":169,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":170,"character":27},"end":{"line":170,"character":30}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":131,"character":13},"end":{"line":131,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/api.lua":[{"severity":3,"range":{"start":{"line":650,"character":9},"end":{"line":650,"character":35}},"message":"Global variable in lowercase initial, Did you miss `local` or misspell it?","source":"Lua Diagnostics.","code":"lowercase-global"},{"severity":2,"range":{"start":{"line":207,"character":2},"end":{"line":207,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":2},"end":{"line":245,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":2},"end":{"line":260,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":385,"character":2},"end":{"line":385,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1175,"character":2},"end":{"line":1175,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":71,"character":9},"end":{"line":71,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":78,"character":9},"end":{"line":78,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":4},"end":{"line":179,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":4},"end":{"line":201,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":4},"end":{"line":322,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":332,"character":4},"end":{"line":332,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":4},"end":{"line":342,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":4},"end":{"line":354,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":358,"character":4},"end":{"line":358,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":363,"character":4},"end":{"line":363,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":461,"character":26},"end":{"line":461,"character":29}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":522,"character":4},"end":{"line":522,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":542,"character":4},"end":{"line":542,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":548,"character":4},"end":{"line":548,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":553,"character":4},"end":{"line":553,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":575,"character":4},"end":{"line":575,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":600,"character":4},"end":{"line":600,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":621,"character":4},"end":{"line":621,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":627,"character":4},"end":{"line":627,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":690,"character":4},"end":{"line":690,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":695,"character":4},"end":{"line":695,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":740,"character":4},"end":{"line":740,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1091,"character":15},"end":{"line":1091,"character":18}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1104,"character":4},"end":{"line":1104,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1109,"character":16},"end":{"line":1109,"character":19}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1149,"character":4},"end":{"line":1149,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":207,"character":65},"end":{"line":207,"character":68}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":239,"character":23},"end":{"line":239,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":24},"end":{"line":245,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":254,"character":23},"end":{"line":254,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":255,"character":38},"end":{"line":255,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":260,"character":24},"end":{"line":260,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":531,"character":6},"end":{"line":531,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":567,"character":6},"end":{"line":567,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":592,"character":6},"end":{"line":592,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":612,"character":6},"end":{"line":612,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":641,"character":6},"end":{"line":641,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":747,"character":6},"end":{"line":747,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1115,"character":11},"end":{"line":1115,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1128,"character":11},"end":{"line":1128,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1134,"character":11},"end":{"line":1134,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1102,"character":18},"end":{"line":1102,"character":21}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1113,"character":24},"end":{"line":1113,"character":27}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1150,"character":6},"end":{"line":1150,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1154,"character":6},"end":{"line":1154,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":179,"character":61},"end":{"line":179,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":201,"character":61},"end":{"line":201,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":322,"character":57},"end":{"line":322,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":332,"character":57},"end":{"line":332,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":342,"character":57},"end":{"line":342,"character":60}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":354,"character":47},"end":{"line":354,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":358,"character":36},"end":{"line":358,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":363,"character":74},"end":{"line":363,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":522,"character":36},"end":{"line":522,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":542,"character":47},"end":{"line":542,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":548,"character":36},"end":{"line":548,"character":39}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":553,"character":68},"end":{"line":553,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":562,"character":6},"end":{"line":562,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":575,"character":45},"end":{"line":575,"character":48}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":582,"character":6},"end":{"line":582,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":600,"character":47},"end":{"line":600,"character":50}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":607,"character":6},"end":{"line":607,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":621,"character":44},"end":{"line":621,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":627,"character":42},"end":{"line":627,"character":45}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":636,"character":6},"end":{"line":636,"character":9}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":690,"character":44},"end":{"line":690,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":695,"character":34},"end":{"line":695,"character":37}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":713,"character":8},"end":{"line":713,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":729,"character":8},"end":{"line":729,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":740,"character":50},"end":{"line":740,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1104,"character":53},"end":{"line":1104,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":8},"end":{"line":568,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":8},"end":{"line":593,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":8},"end":{"line":613,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":8},"end":{"line":642,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":8},"end":{"line":748,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":776,"character":8},"end":{"line":776,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":845,"character":8},"end":{"line":845,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":875,"character":8},"end":{"line":875,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":909,"character":8},"end":{"line":909,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":922,"character":8},"end":{"line":922,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":931,"character":8},"end":{"line":931,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":954,"character":8},"end":{"line":954,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":969,"character":8},"end":{"line":969,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":981,"character":8},"end":{"line":981,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":993,"character":8},"end":{"line":993,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":996,"character":31},"end":{"line":996,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1023,"character":8},"end":{"line":1023,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":708,"character":8},"end":{"line":708,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":724,"character":8},"end":{"line":724,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1116,"character":13},"end":{"line":1116,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1129,"character":13},"end":{"line":1129,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1135,"character":13},"end":{"line":1135,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1152,"character":8},"end":{"line":1152,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":459,"character":38},"end":{"line":459,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":8},"end":{"line":563,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":608,"character":8},"end":{"line":608,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":637,"character":8},"end":{"line":637,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":10},"end":{"line":714,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":10},"end":{"line":730,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":896,"character":10},"end":{"line":896,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":906,"character":10},"end":{"line":906,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":52},"end":{"line":568,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":568,"character":70},"end":{"line":568,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":50},"end":{"line":593,"character":53}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":593,"character":68},"end":{"line":593,"character":71}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":52},"end":{"line":613,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":613,"character":70},"end":{"line":613,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":54},"end":{"line":642,"character":57}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":642,"character":72},"end":{"line":642,"character":75}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":56},"end":{"line":748,"character":59}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":748,"character":74},"end":{"line":748,"character":77}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":776,"character":59},"end":{"line":776,"character":62}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":845,"character":73},"end":{"line":845,"character":76}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":875,"character":70},"end":{"line":875,"character":73}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":909,"character":61},"end":{"line":909,"character":64}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":922,"character":43},"end":{"line":922,"character":46}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":931,"character":62},"end":{"line":931,"character":65}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":954,"character":71},"end":{"line":954,"character":74}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":969,"character":38},"end":{"line":969,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":981,"character":38},"end":{"line":981,"character":41}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":993,"character":44},"end":{"line":993,"character":47}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":1023,"character":76},"end":{"line":1023,"character":79}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":585,"character":10},"end":{"line":585,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":587,"character":10},"end":{"line":587,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":709,"character":10},"end":{"line":709,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":725,"character":10},"end":{"line":725,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":819,"character":35},"end":{"line":819,"character":38}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":823,"character":12},"end":{"line":823,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":563,"character":53},"end":{"line":563,"character":56}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":584,"character":10},"end":{"line":584,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":608,"character":52},"end":{"line":608,"character":55}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":51},"end":{"line":714,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":714,"character":69},"end":{"line":714,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":51},"end":{"line":730,"character":54}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":730,"character":69},"end":{"line":730,"character":72}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":896,"character":86},"end":{"line":896,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":906,"character":86},"end":{"line":906,"character":89}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":585,"character":94},"end":{"line":585,"character":97}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":587,"character":60},"end":{"line":587,"character":63}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":823,"character":55},"end":{"line":823,"character":58}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":245,"character":60},"end":{"line":245,"character":64}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":245,"character":66},"end":{"line":245,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":245,"character":73},"end":{"line":245,"character":77}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":60},"end":{"line":260,"character":64}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":66},"end":{"line":260,"character":71}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"},{"severity":2,"range":{"start":{"line":260,"character":73},"end":{"line":260,"character":77}},"message":"This function expects a maximum of 1 argument(s) but instead it is receiving 4.","source":"Lua Diagnostics.","code":"redundant-parameter"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/throttling_emitter.lua":[{"severity":2,"range":{"start":{"line":35,"character":4},"end":{"line":35,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":53,"character":4},"end":{"line":53,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/types.lua":[{"severity":2,"range":{"start":{"line":246,"character":28},"end":{"line":246,"character":54}},"message":"Undefined type or alias `vim.api.keyset.set_extmark`.","source":"Lua Diagnostics.","code":"undefined-doc-name"},{"severity":2,"range":{"start":{"line":320,"character":24},"end":{"line":320,"character":38}},"message":"Undefined type or alias `vim.Diagnostic`.","source":"Lua Diagnostics.","code":"undefined-doc-name"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/config.lua":[{"severity":2,"range":{"start":{"line":178,"character":11},"end":{"line":178,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":4},"end":{"line":226,"character":7}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":247,"character":13},"end":{"line":247,"character":16}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":200,"character":9},"end":{"line":200,"character":12}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":289,"character":31},"end":{"line":289,"character":34}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":226,"character":98},"end":{"line":226,"character":101}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":305,"character":11},"end":{"line":305,"character":14}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}],"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/ui/footer.lua":[{"severity":2,"range":{"start":{"line":85,"character":2},"end":{"line":85,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":122,"character":2},"end":{"line":122,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":129,"character":2},"end":{"line":129,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":140,"character":2},"end":{"line":140,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":154,"character":2},"end":{"line":154,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":155,"character":2},"end":{"line":155,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":156,"character":2},"end":{"line":156,"character":5}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":49,"character":20},"end":{"line":49,"character":23}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":84,"character":23},"end":{"line":84,"character":26}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":114,"character":8},"end":{"line":114,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":128,"character":21},"end":{"line":128,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":139,"character":21},"end":{"line":139,"character":24}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":62,"character":12},"end":{"line":62,"character":15}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":98,"character":10},"end":{"line":98,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":99,"character":10},"end":{"line":99,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":113,"character":8},"end":{"line":113,"character":11}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"},{"severity":2,"range":{"start":{"line":64,"character":10},"end":{"line":64,"character":13}},"message":"Undefined global `vim`.","source":"Lua Diagnostics.","code":"undefined-global"}]}},"status":"completed","time":{"start":1762176909474,"end":1762176910374},"title":"lua/opencode/core.lua","input":{"newString":" params.model = { modelID = model, providerID = provider }","filePath":"/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua","oldString":" params.model = { providerID = provider, modelID = model }"},"output":"\nThis file has errors, please fix\n\n\n\n"},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"reason":"tool-calls","cost":0,"id":"prt_a49edc42b001zynaxIfLCTqFF6","messageID":"msg_a49edb694001syExFxMUW1ik3n","snapshot":"4d76a8382f4cd173216ee6d5949f80aeec2ed395","type":"step-finish","tokens":{"reasoning":0,"cache":{"read":15488,"write":0},"input":15541,"output":237},"sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176906900},"id":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15488,"write":0},"input":15541,"output":237},"providerID":"github-copilot"}}},{"type":"message.part.updated","properties":{"part":{"files":["/home/francis/Projects/_nvim/opencode.nvim/lua/opencode/core.lua"],"messageID":"msg_a49edb694001syExFxMUW1ik3n","id":"prt_a49edc44d001r66NSVANs6OHqr","type":"patch","hash":"f33f38a70b284207e092c2c578a24e96fdd1bd4d","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176906900,"completed":1762176910414},"id":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15488,"write":0},"input":15541,"output":237},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176906900,"completed":1762176910418},"id":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15488,"write":0},"input":15541,"output":237},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176906900,"completed":1762176910418},"id":"msg_a49edb694001syExFxMUW1ik3n","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15488,"write":0},"input":15541,"output":237},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176910436},"id":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":0,"write":0},"input":0,"output":0},"providerID":"github-copilot"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176910449},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Fixing param-type-not-match and need-check-nil in core.lua line 130","version":"0.15.30"}}},{"type":"message.updated","properties":{"info":{"id":"msg_a49ed91d6001coTsjFq9x6FF5W","time":{"created":1762176897494},"summary":{"diffs":[{"file":"lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":1,"additions":5,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { modelID = model, providerID = provider }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"}]},"role":"user","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_a49edc83d001bg2hfdA1yYp8Q1","snapshot":"4d76a8382f4cd173216ee6d5949f80aeec2ed395","type":"step-start","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176911423},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" type"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID =","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176911423},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" ="}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID = provider }`.\n\nNow, let's move to step 3: Test the changes to","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176911423},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" to"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID = provider }`.\n\nNow, let's move to step 3: Test the changes to ensure the diagnostics are resolved and the function works as expected.\n\nI'll run the test","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176911423},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" test"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID = provider }`.\n\nNow, let's move to step 3: Test the changes to ensure the diagnostics are resolved and the function works as expected.\n\nI'll run the test suite using the provided script to verify everything is","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176911423},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" is"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"Step 2 is complete: the `model` field in `params` now matches the expected type `{ modelID = model, providerID = provider }`.\n\nNow, let's move to step 3: Test the changes to ensure the diagnostics are resolved and the function works as expected.\n\nI'll run the test suite using the provided script to verify everything is working.","id":"prt_a49edc83f001YsFxwe2yt9W3Jz","time":{"start":1762176912551,"end":1762176912551},"type":"text","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"callID":"call_4NyLmBcZTmbwsJwuN6gfFqP9","id":"prt_a49edcc8e001xT4R3ZUgjYzQng","tool":"bash","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","state":{"metadata":{"output":"\u001b[0;33mRunning tests for opencode.nvim\u001b[0m\n------------------------------------------------\n","description":"Run all tests to verify code changes"},"status":"running","input":{"command":"./run_tests.sh","description":"Run all tests to verify code changes"},"time":{"start":1762176912550}},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"callID":"call_4NyLmBcZTmbwsJwuN6gfFqP9","id":"prt_a49edcc8e001xT4R3ZUgjYzQng","tool":"bash","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","state":{"metadata":{"output":"\u001b[0;33mRunning tests for opencode.nvim\u001b[0m\n------------------------------------------------\nStarting...Scheduling: ./tests/minimal/plugin_spec.lua\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin loads the plugin without errors\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin can be set up with custom config\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\u001b[0;32mโœ“ Minimal tests passed\u001b[0m\n------------------------------------------------\n","description":"Run all tests to verify code changes"},"status":"running","input":{"command":"./run_tests.sh","description":"Run all tests to verify code changes"},"time":{"start":1762176912721}},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"callID":"call_4NyLmBcZTmbwsJwuN6gfFqP9","id":"prt_a49edcc8e001xT4R3ZUgjYzQng","tool":"bash","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","state":{"metadata":{"exit":0,"description":"Run all tests to verify code changes","output":"\u001b[0;33mRunning tests for opencode.nvim\u001b[0m\n------------------------------------------------\nStarting...Scheduling: ./tests/minimal/plugin_spec.lua\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin loads the plugin without errors\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin can be set up with custom config\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\u001b[0;32mโœ“ Minimal tests passed\u001b[0m\n------------------------------------------------\nStarting...Scheduling: ./tests/unit/keymap_spec.lua\nScheduling: ./tests/unit/opencode_server_spec.lua\nScheduling: ./tests/unit/context_completion_spec.lua\nScheduling: ./tests/unit/config_file_spec.lua\nScheduling: ./tests/unit/init_spec.lua\nScheduling: ./tests/unit/state_spec.lua\nScheduling: ./tests/unit/render_state_spec.lua\nScheduling: ./tests/unit/server_job_spec.lua\nScheduling: ./tests/unit/config_spec.lua\nScheduling: ./tests/unit/context_bar_spec.lua\nScheduling: ./tests/unit/renderer_spec.lua\nScheduling: ./tests/unit/api_client_spec.lua\nScheduling: ./tests/unit/core_spec.lua\nScheduling: ./tests/unit/session_spec.lua\nScheduling: ./tests/unit/event_manager_spec.lua\nScheduling: ./tests/unit/api_spec.lua\nScheduling: ./tests/unit/context_spec.lua\nScheduling: ./tests/unit/timer_spec.lua\nScheduling: ./tests/unit/util_spec.lua\nScheduling: ./tests/unit/snapshot_spec.lua\nScheduling: ./tests/unit/id_spec.lua\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_completion_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion get_source should return a completion source\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should return empty table when trigger char does not match\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should return context items when trigger char matches\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include selection items when selections exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include mentioned files when they exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include subagent items when they exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should filter items based on input\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should sort items with available items first\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should handle nil item gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should handle item without data gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should toggle context enabled state for toggleable items\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove mentioned file when selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove subagent when selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove selection when selection item selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should clean up trigger character from current line\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format diagnostics correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format cursor data correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format selection correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion edge cases should handle empty context gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion edge cases should handle disabled contexts correctly\t\n\t\n\u001b[32mSuccess: \u001b[0m\t20\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/keymap_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up keymap with new format configured keys\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up keymap with old format configured keys (normalized)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up callbacks that execute the correct commands (new format)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up callbacks that execute the correct commands (old format normalized)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap normalizes old format keymap to new format correctly\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap shows error message for unknown API functions\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap uses custom description from config_entry\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap falls back to API description when no custom desc provided\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_window_keymaps handles unknown API functions with error message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_window_keymaps uses custom description for window keymaps\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap sets up permission keymaps when there is a current permission\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap should delete existing permission keymaps if no current permission exists after being set\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap does not set permission keymaps when there is no current permission\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/opencode_server_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server creates a new server object\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server spawn promise resolves when stdout emits server URL\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server shutdown resolves shutdown_promise and clears fields\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server calls on_error when stderr is triggered\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server calls on_exit and clears fields when process exits\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_file_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup lazily loads config when accessed\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_agents returns primary + defaults\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_agents respects disabled defaults\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_project returns project\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/init_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode has setup function in the public API\t\n\u001b[32mSuccess\u001b[0m\t||\topencode main module can be required without errors\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/render_state_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState new and reset creates a new instance\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState new and reset resets to empty state\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message sets a new message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message updates line index for message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message updates existing message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part sets a new part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part updates line index for part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part initializes actions array\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_at_line returns part at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_at_line returns nil for line without part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_message_at_line returns message at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_message_at_line returns nil for line without message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_by_call_id finds part by call ID\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_by_call_id returns nil when call ID not found\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions adds actions to part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions adds actions with offset\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions clears actions for part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions gets actions at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions gets all actions from all parts\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines updates part line positions\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines shifts subsequent content when expanding\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines shifts subsequent content when shrinking\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines returns false for non-existent part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part removes part and shifts subsequent content\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part clears line index for removed part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part returns false for non-existent part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message removes message and shifts subsequent content\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message clears line index for removed message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message returns false for non-existent message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all does nothing when delta is 0\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all shifts content at or after from_line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all shifts actions with parts\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all does not rebuild index when nothing shifted\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all invalidates index when content shifted\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all exits early when content found before from_line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_data updates part reference\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_data does nothing for non-existent part\t\n\t\n\u001b[32mSuccess: \u001b[0m\t37\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/server_job_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job exposes expected public functions\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job call_api resolves with decoded json and toggles is_job_running\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job call_api rejects on non 2xx\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job stream_api forwards chunks\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job ensure_server spawns a new opencode server only once\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.config uses default values when no options are provided\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.config merges user options with defaults\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_bar_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders minimal winbar with right aligh token only\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with current file when present\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with multiple context elements\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with diagnostics\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar respects context enabled settings\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar handles empty winbar gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar does nothing when window is invalid\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar uses provided windows parameter\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar setup subscribes to state changes\t\n\t\n\u001b[32mSuccess: \u001b[0m\t9\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_client_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should create a new client instance\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should remove trailing slash from base_url\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should create client using create factory function\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should have all expected API methods\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should construct URLs correctly with query parameters\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nError detected while processing command line:\nopencode command not found - please install and configure opencode before using this plugin\nUnsupported opencode CLI version: opencode 0.4.1. Requires >= 0.4.2\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/core_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open creates windows if they don't exist\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open handles new session properly\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open focuses the appropriate window\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core select_session filters sessions by description and parentID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message sends a message via api_client\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message creates new session when none active\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message persist options in state when sending message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns false when opencode executable is missing\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns false when version is below required\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns true when version equals required\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns true when version is above required\t\n\t\n\u001b[32mSuccess: \u001b[0m\t11\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/session_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session returns the most recent session for current workspace\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session returns nil when no sessions match the workspace\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session handles JSON parsing errors\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session handles empty session list\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_by_name returns the session with matching ID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_by_name returns nil when no session matches the ID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns nil for non-existent directory\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns nil when directory exists but has no JSON files\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns decoded JSON content from directory\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir skips invalid JSON files\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns nil when session is nil\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns nil when messages directory does not exist\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns messages with their parts\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/state_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) notifies listeners on key change\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) notifies wildcard listeners on any key change\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) can unregister listeners\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) does not notify if value is unchanged\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/event_manager_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should create a new instance\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should subscribe and emit events\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should handle multiple subscribers\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should unsubscribe correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should track subscriber count\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should list event names\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should handle starting and stopping\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should not start multiple times\t\n\t\n\u001b[32mSuccess: \u001b[0m\t8\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nFile not added to context. Could not read.\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_opencode_message extracts prompt, selected_text, and current_file from tags in parts\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_opencode_message returns nils if message or parts missing\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_message_legacy extracts legacy tags from text\t\n\u001b[32mSuccess\u001b[0m\t||\textract_legacy_tag extracts content between tags\t\n\u001b[32mSuccess\u001b[0m\t||\textract_legacy_tag returns nil if tag not found\t\n\u001b[32mSuccess\u001b[0m\t||\tformat_message returns a parts array with prompt as first part\t\n\u001b[32mSuccess\u001b[0m\t||\tformat_message includes mentioned_files and subagents\t\n\u001b[32mSuccess\u001b[0m\t||\tdelta_context removes current_file if unchanged\t\n\u001b[32mSuccess\u001b[0m\t||\tdelta_context removes mentioned_subagents if unchanged\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a file if filereadable\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent does not add file if not filereadable\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a selection\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a subagent\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n:OpencodeOpenInput is deprecated. Use `:Opencode open input` instead\n:OpencodeStop is deprecated. Use `:Opencode cancel` instead\n:OpencodeClose is deprecated. Use `:Opencode close` instead\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api commands table contains the expected commands with proper structure\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api setup registers the main Opencode command and legacy commands\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api setup sets up legacy command functions that route to main command\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api Lua API provides callable functions that match commands\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses agent prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses model prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses context prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses multiple prefixes and passes all to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing works with run_new command\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing requires a prompt after prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing Lua API accepts opts directly without parsing\t\n\t\n\u001b[32mSuccess: \u001b[0m\t11\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/util_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses flat booleans\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses nested dot notation\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses mixed nesting and booleans\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses numbers\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args handles empty string\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses no prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single agent prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single model prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single context prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses multiple prefixes in order\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses context with multiple comma-delimited values\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args handles empty prompt after prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args handles empty string\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args stops parsing at first non-prefix token\t\n\t\n\u001b[32mSuccess: \u001b[0m\t14\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/snapshot_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore runs read-tree and checkout-index and notifies on success\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if no active session\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if read-tree fails\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if checkout-index fails\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/id_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate ascending session IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate descending message IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should validate given IDs correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should throw error for invalid given IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should validate schemas correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should return available prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate IDs with correct length structure\t\n\t\n\u001b[32mSuccess: \u001b[0m\t7\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/timer_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new creates a new timer with required options\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new sets repeat_timer to false when explicitly disabled\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new stores optional parameters\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start starts a repeating timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start starts a one-shot timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start passes arguments to on_tick function\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops timer when on_tick returns false\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops timer when on_tick throws an error\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops previous timer before starting new one\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start throws error when timer creation fails\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop stops a running timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop calls on_stop callback when provided\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop does nothing when timer is not running\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop handles errors in on_stop callback gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false when timer is not started\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns true when timer is running\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false after timer is stopped\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false after one-shot timer completes\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Integration tests can restart a stopped timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Integration tests handles rapid start/stop cycles\t\n\t\n\u001b[32mSuccess: \u001b[0m\t20\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nTwo pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc\nTwo pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO\nTwo pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc\nTwo pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/renderer_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays message-removal correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays message-removal correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-prompt correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-prompt correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (session)\t\n\t\n\u001b[32mSuccess: \u001b[0m\t60\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\u001b[0;32mโœ“ Unit tests passed\u001b[0m\n------------------------------------------------\n\u001b[0;32mAll tests passed successfully!\u001b[0m\n"},"status":"completed","time":{"start":1762176912541,"end":1762176915509},"title":"./run_tests.sh","input":{"command":"./run_tests.sh","description":"Run all tests to verify code changes"},"output":"\u001b[0;33mRunning tests for opencode.nvim\u001b[0m\n------------------------------------------------\nStarting...Scheduling: ./tests/minimal/plugin_spec.lua\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/minimal/plugin_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin loads the plugin without errors\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.nvim plugin can be set up with custom config\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\u001b[0;32mโœ“ Minimal tests passed\u001b[0m\n------------------------------------------------\nStarting...Scheduling: ./tests/unit/keymap_spec.lua\nScheduling: ./tests/unit/opencode_server_spec.lua\nScheduling: ./tests/unit/context_completion_spec.lua\nScheduling: ./tests/unit/config_file_spec.lua\nScheduling: ./tests/unit/init_spec.lua\nScheduling: ./tests/unit/state_spec.lua\nScheduling: ./tests/unit/render_state_spec.lua\nScheduling: ./tests/unit/server_job_spec.lua\nScheduling: ./tests/unit/config_spec.lua\nScheduling: ./tests/unit/context_bar_spec.lua\nScheduling: ./tests/unit/renderer_spec.lua\nScheduling: ./tests/unit/api_client_spec.lua\nScheduling: ./tests/unit/core_spec.lua\nScheduling: ./tests/unit/session_spec.lua\nScheduling: ./tests/unit/event_manager_spec.lua\nScheduling: ./tests/unit/api_spec.lua\nScheduling: ./tests/unit/context_spec.lua\nScheduling: ./tests/unit/timer_spec.lua\nScheduling: ./tests/unit/util_spec.lua\nScheduling: ./tests/unit/snapshot_spec.lua\nScheduling: ./tests/unit/id_spec.lua\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_completion_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion get_source should return a completion source\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should return empty table when trigger char does not match\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should return context items when trigger char matches\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include selection items when selections exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include mentioned files when they exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should include subagent items when they exist\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should filter items based on input\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion complete function should sort items with available items first\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should handle nil item gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should handle item without data gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should toggle context enabled state for toggleable items\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove mentioned file when selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove subagent when selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should remove selection when selection item selected\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion on_complete function should clean up trigger character from current line\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format diagnostics correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format cursor data correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion formatting functions should format selection correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion edge cases should handle empty context gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tcontext completion edge cases should handle disabled contexts correctly\t\n\t\n\u001b[32mSuccess: \u001b[0m\t20\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/keymap_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up keymap with new format configured keys\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up keymap with old format configured keys (normalized)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up callbacks that execute the correct commands (new format)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup sets up callbacks that execute the correct commands (old format normalized)\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap normalizes old format keymap to new format correctly\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap shows error message for unknown API functions\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap uses custom description from config_entry\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap normalize_keymap falls back to API description when no custom desc provided\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_window_keymaps handles unknown API functions with error message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_window_keymaps uses custom description for window keymaps\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap sets up permission keymaps when there is a current permission\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap should delete existing permission keymaps if no current permission exists after being set\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.keymap setup_permission_keymap does not set permission keymaps when there is no current permission\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/opencode_server_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server creates a new server object\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server spawn promise resolves when stdout emits server URL\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server shutdown resolves shutdown_promise and clears fields\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server calls on_error when stderr is triggered\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.opencode_server calls on_exit and clears fields when process exits\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_file_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup lazily loads config when accessed\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_agents returns primary + defaults\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_agents respects disabled defaults\t\n\u001b[32mSuccess\u001b[0m\t||\tconfig_file.setup get_opencode_project returns project\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/init_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode has setup function in the public API\t\n\u001b[32mSuccess\u001b[0m\t||\topencode main module can be required without errors\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/render_state_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState new and reset creates a new instance\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState new and reset resets to empty state\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message sets a new message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message updates line index for message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_message updates existing message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part sets a new part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part updates line index for part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState set_part initializes actions array\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_at_line returns part at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_at_line returns nil for line without part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_message_at_line returns message at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_message_at_line returns nil for line without message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_by_call_id finds part by call ID\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState get_part_by_call_id returns nil when call ID not found\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions adds actions to part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions adds actions with offset\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions clears actions for part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions gets actions at line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState actions gets all actions from all parts\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines updates part line positions\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines shifts subsequent content when expanding\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines shifts subsequent content when shrinking\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_lines returns false for non-existent part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part removes part and shifts subsequent content\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part clears line index for removed part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_part returns false for non-existent part\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message removes message and shifts subsequent content\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message clears line index for removed message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState remove_message returns false for non-existent message\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all does nothing when delta is 0\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all shifts content at or after from_line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all shifts actions with parts\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all does not rebuild index when nothing shifted\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all invalidates index when content shifted\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState shift_all exits early when content found before from_line\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_data updates part reference\t\n\u001b[32mSuccess\u001b[0m\t||\tRenderState update_part_data does nothing for non-existent part\t\n\t\n\u001b[32mSuccess: \u001b[0m\t37\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/server_job_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job exposes expected public functions\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job call_api resolves with decoded json and toggles is_job_running\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job call_api rejects on non 2xx\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job stream_api forwards chunks\t\n\u001b[32mSuccess\u001b[0m\t||\tserver_job ensure_server spawns a new opencode server only once\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/config_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.config uses default values when no options are provided\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.config merges user options with defaults\t\n\t\n\u001b[32mSuccess: \u001b[0m\t2\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_bar_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders minimal winbar with right aligh token only\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with current file when present\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with multiple context elements\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar renders winbar with diagnostics\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar respects context enabled settings\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar handles empty winbar gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar does nothing when window is invalid\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar opencode.ui.context_bar uses provided windows parameter\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.ui.context_bar setup subscribes to state changes\t\n\t\n\u001b[32mSuccess: \u001b[0m\t9\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_client_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should create a new client instance\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should remove trailing slash from base_url\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should create client using create factory function\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should have all expected API methods\t\n\u001b[32mSuccess\u001b[0m\t||\tapi_client should construct URLs correctly with query parameters\t\n\t\n\u001b[32mSuccess: \u001b[0m\t5\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nError detected while processing command line:\nopencode command not found - please install and configure opencode before using this plugin\nUnsupported opencode CLI version: opencode 0.4.1. Requires >= 0.4.2\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/core_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open creates windows if they don't exist\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open handles new session properly\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core open focuses the appropriate window\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core select_session filters sessions by description and parentID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message sends a message via api_client\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message creates new session when none active\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core send_message persist options in state when sending message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns false when opencode executable is missing\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns false when version is below required\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns true when version equals required\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.core opencode_ok (version checks) returns true when version is above required\t\n\t\n\u001b[32mSuccess: \u001b[0m\t11\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/session_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session returns the most recent session for current workspace\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session returns nil when no sessions match the workspace\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session handles JSON parsing errors\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_last_workspace_session handles empty session list\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_by_name returns the session with matching ID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_by_name returns nil when no session matches the ID\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns nil for non-existent directory\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns nil when directory exists but has no JSON files\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir returns decoded JSON content from directory\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session read_json_dir skips invalid JSON files\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns nil when session is nil\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns nil when messages directory does not exist\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.session get_messages returns messages with their parts\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/state_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) notifies listeners on key change\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) notifies wildcard listeners on any key change\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) can unregister listeners\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.state (observable) does not notify if value is unchanged\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/event_manager_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should create a new instance\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should subscribe and emit events\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should handle multiple subscribers\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should unsubscribe correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should track subscriber count\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should list event names\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should handle starting and stopping\t\n\u001b[32mSuccess\u001b[0m\t||\tEventManager should not start multiple times\t\n\t\n\u001b[32mSuccess: \u001b[0m\t8\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nFile not added to context. Could not read.\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/context_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_opencode_message extracts prompt, selected_text, and current_file from tags in parts\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_opencode_message returns nils if message or parts missing\t\n\u001b[32mSuccess\u001b[0m\t||\textract_from_message_legacy extracts legacy tags from text\t\n\u001b[32mSuccess\u001b[0m\t||\textract_legacy_tag extracts content between tags\t\n\u001b[32mSuccess\u001b[0m\t||\textract_legacy_tag returns nil if tag not found\t\n\u001b[32mSuccess\u001b[0m\t||\tformat_message returns a parts array with prompt as first part\t\n\u001b[32mSuccess\u001b[0m\t||\tformat_message includes mentioned_files and subagents\t\n\u001b[32mSuccess\u001b[0m\t||\tdelta_context removes current_file if unchanged\t\n\u001b[32mSuccess\u001b[0m\t||\tdelta_context removes mentioned_subagents if unchanged\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a file if filereadable\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent does not add file if not filereadable\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a selection\t\n\u001b[32mSuccess\u001b[0m\t||\tadd_file/add_selection/add_subagent adds a subagent\t\n\t\n\u001b[32mSuccess: \u001b[0m\t13\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n:OpencodeOpenInput is deprecated. Use `:Opencode open input` instead\n:OpencodeStop is deprecated. Use `:Opencode cancel` instead\n:OpencodeClose is deprecated. Use `:Opencode close` instead\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/api_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api commands table contains the expected commands with proper structure\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api setup registers the main Opencode command and legacy commands\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api setup sets up legacy command functions that route to main command\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api Lua API provides callable functions that match commands\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses agent prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses model prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses context prefix and passes to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing parses multiple prefixes and passes all to send_message\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing works with run_new command\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing requires a prompt after prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\topencode.api run command argument parsing Lua API accepts opts directly without parsing\t\n\t\n\u001b[32mSuccess: \u001b[0m\t11\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/util_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses flat booleans\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses nested dot notation\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses mixed nesting and booleans\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args parses numbers\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_dot_args handles empty string\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses no prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single agent prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single model prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses single context prefix\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses multiple prefixes in order\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args parses context with multiple comma-delimited values\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args handles empty prompt after prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args handles empty string\t\n\u001b[32mSuccess\u001b[0m\t||\tutil.parse_run_args stops parsing at first non-prefix token\t\n\t\n\u001b[32mSuccess: \u001b[0m\t14\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/snapshot_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore runs read-tree and checkout-index and notifies on success\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if no active session\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if read-tree fails\t\n\u001b[32mSuccess\u001b[0m\t||\tsnapshot.restore notifies error if checkout-index fails\t\n\t\n\u001b[32mSuccess: \u001b[0m\t4\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/id_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate ascending session IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate descending message IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should validate given IDs correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should throw error for invalid given IDs\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should validate schemas correctly\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should return available prefixes\t\n\u001b[32mSuccess\u001b[0m\t||\tID module should generate IDs with correct length structure\t\n\t\n\u001b[32mSuccess: \u001b[0m\t7\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/timer_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new creates a new timer with required options\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new sets repeat_timer to false when explicitly disabled\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer.new stores optional parameters\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start starts a repeating timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start starts a one-shot timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start passes arguments to on_tick function\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops timer when on_tick returns false\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops timer when on_tick throws an error\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start stops previous timer before starting new one\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:start throws error when timer creation fails\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop stops a running timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop calls on_stop callback when provided\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop does nothing when timer is not running\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:stop handles errors in on_stop callback gracefully\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false when timer is not started\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns true when timer is running\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false after timer is stopped\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Timer:is_running returns false after one-shot timer completes\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Integration tests can restart a stopped timer\t\n\u001b[32mSuccess\u001b[0m\t||\tTimer Integration tests handles rapid start/stop cycles\t\n\t\n\u001b[32mSuccess: \u001b[0m\t20\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\nTwo pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc\nTwo pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO\nTwo pending permissions? existing: per_9efb5b2f3001aqJAFBMiGjFjVZ new: per_9efb5bc2a001j9Bd6bFjLB7hrc\nTwo pending permissions? existing: per_9efb5bc2a001j9Bd6bFjLB7hrc new: per_9efb5d6d1001uwVXQ9dhlBlgfO\n\n========================================\t\nTesting: \t/home/francis/Projects/_nvim/opencode.nvim/tests/unit/renderer_spec.lua\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays ansi-codes correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-abort correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays api-error correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays cursor_data correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays diff correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays markdown-codefence correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays mentions-with-ranges correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays message-removal correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays message-removal correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays perf correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-denied correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-prompt correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission-prompt correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays permission correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays planning correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-all correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays redo-once correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays revert correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays selection correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays shifting-and-multiple-perms correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays simple-session correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays tool-invalid correctly (session)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (event-by-event, collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (event-by-event, no collapsing)\t\n\u001b[32mSuccess\u001b[0m\t||\trenderer replays updating-text correctly (session)\t\n\t\n\u001b[32mSuccess: \u001b[0m\t60\t\n\u001b[31mFailed : \u001b[0m\t0\t\n========================================\t\n\u001b[0;32mโœ“ Unit tests passed\u001b[0m\n------------------------------------------------\n\u001b[0;32mAll tests passed successfully!\u001b[0m\n"},"type":"tool","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"reason":"tool-calls","cost":0,"id":"prt_a49edd837001lGPaOMUY99F0JS","messageID":"msg_a49edc4640017DZPFVUPHCm7Ji","snapshot":"4d76a8382f4cd173216ee6d5949f80aeec2ed395","type":"step-finish","tokens":{"reasoning":0,"cache":{"read":7680,"write":0},"input":15805,"output":102},"sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176910436},"id":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":7680,"write":0},"input":15805,"output":102},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176910436,"completed":1762176915544},"id":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":7680,"write":0},"input":15805,"output":102},"providerID":"github-copilot"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176910436,"completed":1762176915546},"id":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":7680,"write":0},"input":15805,"output":102},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176910436,"completed":1762176915547},"id":"msg_a49edc4640017DZPFVUPHCm7Ji","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":7680,"write":0},"input":15805,"output":102},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176915583},"id":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":0,"write":0},"input":0,"output":0},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"id":"msg_a49ed91d6001coTsjFq9x6FF5W","time":{"created":1762176897494},"summary":{"diffs":[{"file":"lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":1,"additions":5,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { modelID = model, providerID = provider }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"}]},"role":"user","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176915602},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Fixing param-type-not-match and need-check-nil in core.lua line 130","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"id":"prt_a49eddd62001iPYFPbJ6Y4rnHk","snapshot":"4d76a8382f4cd173216ee6d5949f80aeec2ed395","type":"step-start","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" of"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" for"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":"M"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" `"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ...,","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" ...,"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.\n- โœ… Verified the fixes by running the","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" the"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.\n- โœ… Verified the fixes by running the full test suiteโ€”no errors or failures.\n\nYour file is now","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" now"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.\n- โœ… Verified the fixes by running the full test suiteโ€”no errors or failures.\n\nYour file is now robust and EmmyLua diagnostics at line","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" line"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.\n- โœ… Verified the fixes by running the full test suiteโ€”no errors or failures.\n\nYour file is now robust and EmmyLua diagnostics at line 130 are resolved. If you need further tweaks or want","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176916836},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"},"delta":" want"}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.part.updated","properties":{"part":{"text":"All steps are complete and all tests pass! Hereโ€™s a summary of what was fixed:\n\n- โœ… Added a nil check for `state.active_session` before accessing `.id` in `M.send_message`.\n- โœ… Ensured the `model` field in `params` matches the expected type `{ modelID = ..., providerID = ... }`.\n- โœ… Verified the fixes by running the full test suiteโ€”no errors or failures.\n\nYour file is now robust and EmmyLua diagnostics at line 130 are resolved. If you need further tweaks or want to address other diagnostics, let me know!","id":"prt_a49eddd640016qrxxmOdhzVlPS","time":{"start":1762176918065,"end":1762176918065},"type":"text","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.part.updated","properties":{"part":{"reason":"stop","cost":0,"id":"prt_a49ede231001JoNcJuwk65yXP6","messageID":"msg_a49edd87f001eOJDDoq5Vb5hra","snapshot":"4d76a8382f4cd173216ee6d5949f80aeec2ed395","type":"step-finish","tokens":{"reasoning":0,"cache":{"read":15744,"write":0},"input":24075,"output":120},"sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176915583},"id":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15744,"write":0},"input":24075,"output":120},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176915583,"completed":1762176918091},"id":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15744,"write":0},"input":24075,"output":120},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176915583,"completed":1762176918092},"id":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15744,"write":0},"input":24075,"output":120},"providerID":"github-copilot"}}},{"type":"message.updated","properties":{"info":{"mode":"build","role":"assistant","path":{"root":"/home/francis/Projects/_nvim/opencode.nvim","cwd":"/home/francis/Projects/_nvim/opencode.nvim"},"parentID":"msg_a49ed91d6001coTsjFq9x6FF5W","system":["You are opencode, an agent - please keep going until the userโ€™s query is completely resolved, before ending your turn and yielding back to the user.\n\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\n\nYou MUST iterate and keep going until the problem is solved.\n\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\n\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\n\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\n\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\n\nYour knowledge on everything is out of date because your training date is in the past. \n\nYou CANNOT successfully complete this task without using Google to verify your\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\n\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\n\nIf the user request is \"resume\" or \"continue\" or \"try again\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\n\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\n\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\n\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \"Next I will do X\" or \"Now I will do Y\" or \"I will do X\", you MUST actually do X or Y instead just saying that you will do it. \n\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\n\n# Workflow\n1. Fetch any URL's provided by the user using the `webfetch` tool.\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\n - What is the expected behavior?\n - What are the edge cases?\n - What are the potential pitfalls?\n - How does this fit into the larger context of the codebase?\n - What are the dependencies and interactions with other parts of the code?\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\n6. Implement the fix incrementally. Make small, testable code changes.\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\n8. Test frequently. Run tests after each change to verify correctness.\n9. Iterate until the root cause is fixed and all tests pass.\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\n\nRefer to the detailed sections below for more information on each step.\n\n## 1. Fetch Provided URLs\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\n- After fetching, review the content returned by the webfetch tool.\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\n\n## 2. Deeply Understand the Problem\nCarefully read the issue and think hard about a plan to solve it before coding.\n\n## 3. Codebase Investigation\n- Explore relevant files and directories.\n- Search for key functions, classes, or variables related to the issue.\n- Read and understand relevant code snippets.\n- Identify the root cause of the problem.\n- Validate and update your understanding continuously as you gather more context.\n\n## 4. Internet Research\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\n- After fetching, review the content returned by the fetch tool.\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find withhin the content that are relevant to the problem.\n- Recursively gather all relevant information by fetching links until you have all the information you need.\n\n## 5. Develop a Detailed Plan \n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\n- Create a todo list in markdown format to track your progress.\n- Each time you complete a step, check it off using `[x]` syntax.\n- Each time you check off a step, display the updated todo list to the user.\n- Make sure that you ACTUALLY continue on to the next step after checkin off a step instead of ending your turn and asking the user what they want to do next.\n\n## 6. Making Code Changes\n- Before editing, always read the relevant file contents or section to ensure complete context.\n- Always read 2000 lines of code at a time to ensure you have enough context.\n- If a patch is not applied correctly, attempt to reapply it.\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\n\n## 7. Debugging\n- Make code changes only if you have high confidence they can solve the problem\n- When debugging, try to determine the root cause rather than addressing symptoms\n- Debug for as long as needed to identify the root cause and identify a fix\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\n- To test hypotheses, you can also add test statements or functions\n- Revisit your assumptions if unexpected behavior occurs.\n\n\n# Communication Guidelines\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \n\n\"Let me fetch the URL you provided to gather more information.\"\n\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\"\n\"Now, I will search the codebase for the function that handles the LIFX API requests.\"\n\"I need to update several files here - stand by\"\n\"OK! Now let's run the tests to make sure everything is working correctly.\"\n\"Whelp - I see we have some problems. Let's fix those up.\"\n\n\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \n- Always write code directly to the correct files.\n- Do not display code to the user unless they specifically ask for it.\n- Only elaborate when clarification is essential for accuracy or user understanding.\n\n# Memory\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \n\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\n```yaml\n---\napplyTo: '**'\n---\n```\n\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\n\n# Reading Files and Folders\n\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\n\n- If you have already read the content and it has not changed, do NOT re-read it.\n- Only re-read files or folders if:\n - You suspect the content has changed since your last read.\n - You have made edits to the file or folder.\n - You encounter an error that suggests the context may be stale or incomplete.\n- Use your internal memory and previous context to avoid redundant reads.\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\n\n# Writing Prompts\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\n\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\n\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\n\n# Git \nIf the user tells you to stage and commit, you may do so. \n\nYou are NEVER allowed to stage and commit files automatically.\n","Here is some useful information about the environment you are running in:\n\n Working directory: /home/francis/Projects/_nvim/opencode.nvim\n Is directory a git repo: yes\n Platform: linux\n Today's date: Mon Nov 03 2025\n\n\n .github/\n\tworkflows/\n\t\ttests.yml\nlua/\n\topencode/\n\t\tui/\n\t\t\tcompletion/\n\t\t\t\tengines/\n\t\t\t\t\tblink_cmp.lua\n\t\t\t\t\tnvim_cmp.lua\n\t\t\t\t\tvim_complete.lua\n\t\t\t\tcommands.lua\n\t\t\t\tcontext.lua\n\t\t\t\tfiles.lua\n\t\t\t\tsort.lua\n\t\t\t\tsubagents.lua\n\t\t\tautocmds.lua\n\t\t\tcompletion.lua\n\t\t\tcontext_bar.lua\n\t\t\tcontextual_actions.lua\n\t\t\tdebug_helper.lua\n\t\t\tdiff_tab.lua\n\t\t\tfile_picker.lua\n\t\t\tfooter.lua\n\t\t\tformatter.lua\n\t\t\thighlight.lua\n\t\t\ticons.lua\n\t\t\tinput_window.lua\n\t\t\tloading_animation.lua\n\t\t\tmention.lua\n\t\t\tnavigation.lua\n\t\t\toutput_window.lua\n\t\t\toutput.lua\n\t\t\tpicker.lua\n\t\t\tprompt_guard_indicator.lua\n\t\t\trender_state.lua\n\t\t\trenderer.lua\n\t\t\tsession_picker.lua\n\t\t\ttimer.lua\n\t\t\ttopbar.lua\n\t\t\tui.lua\n\t\tapi_client.lua\n\t\tapi.lua\n\t\tconfig_file.lua\n\t\tconfig.lua\n\t\tcontext.lua\n\t\tcore.lua\n\t\tcurl.lua\n\t\tevent_manager.lua\n\t\tgit_review.lua\n\t\thealth.lua\n\t\thistory.lua\n\t\tid.lua\n\t\tinit.lua\n\t\tkeymap.lua\n\t\topencode_server.lua\n\t\tpromise.lua\n\t\tprovider.lua\n\t\treview.lua\n\t\tserver_job.lua\n\t\tsession.lua\n\t\tsnapshot.lua\n\t\tstate.lua\n\t\tthrottling_emitter.lua\n\t\ttypes.lua\n\t\tutil.lua\nplugin/\n\topencode.lua\ntests/\n\tdata/\n\t\tansi-codes.expected.json\n\t\tansi-codes.json\n\t\tapi-abort.expected.json\n\t\tapi-abort.json\n\t\tapi-error.expected.json\n\t\tapi-error.json\n\t\tcursor_data.expected.json\n\t\tcursor_data.json\n\t\tdiff.expected.json\n\t\tdiff.json\n\t\tmarkdown-codefence.expected.json\n\t\tmarkdown-codefence.json\n\t\tmentions-with-ranges.expected.json\n\t\tmentions-with-ranges.json\n\t\tmessage-removal.expected.json\n\t\tmessage-removal.json\n\t\tperf.expected.json\n\t\tperf.json\n\t\tpermission-denied.expected.json\n\t\tpermission-denied.json\n\t\tpermission-prompt.expected.json\n\t\tpermission-prompt.json\n\t\tpermission.expected.json\n\t\tpermission.json\n\t\tplanning.expected.json\n\t\tplanning.json\n\t\tredo-all.expected.json\n\t\tredo-all.json\n\t\tredo-once.expected.json\n\t\tredo-once.json\n\t\trevert.expected.json\n\t\trevert.json\n\t\tselection.expected.json\n\t\tselection.json\n\t\tshifting-and-multiple-perms.expected.json\n\t\tshifting-and-multiple-perms.json\n\t\tsimple-session.expected.json\n\t\tsimple-session.json\n\t\ttool-invalid.expected.json\n\t\ttool-invalid.json\n\t\tupdating-text.expected.json\n\t\tupdating-text.json\n\tmanual/\n\t\tinit_replay.lua\n\t\tQUICKSTART.md\n\t\tREADME.md\n\t\tregenerate_expected.sh\n\t\trenderer_replay.lua\n\t\treplay.ps1\n\t\trun_replay.sh\n\tminimal/\n\t\tinit.lua\n\t\tplugin_spec.lua\n\tmocks/\n\t\tsession_list.lua\n\tunit/\n\t\tapi_client_spec.lua\n\t\tapi_spec.lua\n\t\tconfig_file_spec.lua\n\t\tconfig_spec.lua\n\t\tcontext_bar_spec.lua\n\t\tcontext_completion_spec.lua\n\t\tcontext_spec.lua\n\t\tcore_spec.lua\n\t\tevent_manager_spec.lua\n\t\tid_spec.lua\n\t\tinit_spec.lua\n\t\tkeymap_spec.lua\n\t\topencode_server_spec.lua\n\t\trender_state_spec.lua\n\t\trenderer_spec.lua\n\t\tserver_job_spec.lua\n\t\tsession_spec.lua\n\t\tsnapshot_spec.lua\n\t\tstate_spec.lua\n\t\ttimer_spec.lua\n\t\tutil_spec.lua\n\thelpers.lua\n.emmyrc.json\n.gitignore\n.stylua.toml\nLICENSE\nREADME.md\nrun_tests.sh\ntest.txt\n\n# AGENTS.md\n\n## Build, Lint, and Test\n\n- **Run all tests:** `./run_tests.sh`\n- **Minimal tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/minimal', {minimal_init = './tests/minimal/init.lua', sequential = true})\"`\n- **Unit tests:**\n `nvim --headless -u tests/minimal/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Run a single test:** Replace the directory in the above command with the test file path, e.g.:\n `nvim --headless -u tests/manual/init.lua -c \"lua require('plenary.test_harness').test_directory('./tests/unit/job_spec.lua', {minimal_init = './tests/minimal/init.lua'})\"`\n- **Manual/Visual tests:** `./tests/manual/run_replay.sh` - Replay captured event data for visual testing\n- **Debug rendering in headless mode:**\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/FILE.json\" \"+ReplayAll 0\" \"+qa\"`\n This will replay events and dump the output buffer to stdout, useful for debugging rendering issues without a UI.\n You can also run to just a specific message # with (e.g. message # 12):\n `nvim --headless -u tests/manual/init_replay.lua \"+ReplayHeadless\" \"+ReplayLoad tests/data/message-removal.json\" \"+ReplayNext 12\" \"+qa\"`\n- **Lint:** No explicit lint command; follow Lua best practices.\n\n## Code Style Guidelines\n\n- **Imports:** `local mod = require('mod')` at the top. Group standard, then project imports.\n- **Formatting:** 2 spaces per indent. No trailing whitespace. Lines โ‰ค 100 chars.\n- **Types:** Use Lua annotations (`---@class`, `---@field`, etc.) for public APIs/config.\n- **Naming:** Modules: `snake_case.lua`; functions/vars: `snake_case`; classes: `CamelCase`.\n- **Error Handling:** Use `vim.notify` for user-facing errors. Return early on error.\n- **Comments:** Only when necessary for clarity. Prefer self-explanatory code.\n- **Functions:** Prefer local functions. Use `M.func` for module exports.\n- **Config:** Centralize in `config.lua`. Use deep merge for user overrides.\n- **Tests:** Place in `tests/minimal/` or `tests/unit/`. Manual/visual tests in `tests/manual/`.\n\n_Agentic coding agents must follow these conventions strictly for consistency and reliability._\n"],"cost":0,"modelID":"gpt-4.1","time":{"created":1762176915583,"completed":1762176918093},"id":"msg_a49edd87f001eOJDDoq5Vb5hra","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7","tokens":{"reasoning":0,"cache":{"read":15744,"write":0},"input":24075,"output":120},"providerID":"github-copilot"}}},{"type":"custom.emit_events.finished","properties":[]},{"type":"message.updated","properties":{"info":{"id":"msg_a49ed91d6001coTsjFq9x6FF5W","time":{"created":1762176897494},"summary":{"diffs":[{"file":"lua/opencode/core.lua","before":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { providerID = provider, modelID = model }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n","deletions":1,"additions":5,"after":"-- This file was written by an automated tool.\nlocal state = require('opencode.state')\nlocal context = require('opencode.context')\nlocal session = require('opencode.session')\nlocal ui = require('opencode.ui.ui')\nlocal server_job = require('opencode.server_job')\nlocal input_window = require('opencode.ui.input_window')\nlocal util = require('opencode.util')\nlocal config = require('opencode.config')\n\nlocal M = {}\nM._abort_count = 0\n\n---@param parent_id string?\nfunction M.select_session(parent_id)\n local all_sessions = session.get_all_workspace_sessions() or {}\n local filtered_sessions = vim.tbl_filter(function(s)\n return s.description ~= '' and s ~= nil and s.parentID == parent_id\n end, all_sessions)\n\n ui.select_session(filtered_sessions, function(selected_session)\n if not selected_session then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n state.active_session = selected_session\n if state.windows then\n state.restore_points = {}\n -- Don't need to update either renderer because they subscribe to\n -- session changes\n ui.focus_input()\n else\n M.open()\n end\n end)\nend\n\n---@param opts? OpenOpts\nfunction M.open(opts)\n opts = opts or { focus = 'input', new_session = false }\n\n if not state.opencode_server or not state.opencode_server:is_running() then\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n\n M.ensure_current_mode()\n\n local are_windows_closed = state.windows == nil\n\n if not require('opencode.ui.ui').is_opencode_focused() then\n require('opencode.context').load()\n end\n\n if are_windows_closed then\n -- Check if whether prompting will be allowed\n local context_module = require('opencode.context')\n local mentioned_files = context_module.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n if not allowed then\n vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)\n end\n\n state.windows = ui.create_windows()\n end\n\n if opts.new_session then\n state.active_session = nil\n state.last_sent_context = nil\n state.active_session = M.create_new_session()\n else\n if not state.active_session then\n state.active_session = session.get_last_workspace_session()\n else\n if not state.display_route and are_windows_closed then\n -- We're not displaying /help or something like that but we have an active session\n -- and the windows were closed so we need to do a full refresh. This mostly happens\n -- when opening the window after having closed it since we're not currently clearing\n -- the session on api.close()\n ui.render_output(false)\n end\n end\n end\n\n if opts.focus == 'input' then\n ui.focus_input({ restore_position = are_windows_closed, start_insert = opts.start_insert == true })\n elseif opts.focus == 'output' then\n ui.focus_output({ restore_position = are_windows_closed })\n end\n state.is_opencode_focused = true\nend\n\n--- Sends a message to the active session, creating one if necessary.\n--- @param prompt string The message prompt to send.\n--- @param opts? SendMessageOpts\nfunction M.send_message(prompt, opts)\n local mentioned_files = context.context.mentioned_files or {}\n local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)\n\n if not allowed then\n vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)\n return\n end\n\n opts = opts or {}\n\n opts.context = vim.tbl_deep_extend('force', state.current_context_config or {}, opts.context or {})\n state.current_context_config = opts.context\n context.load()\n opts.model = opts.model or state.current_model\n opts.agent = opts.agent or state.current_mode or config.default_mode\n\n local params = {}\n\n if opts.model then\n local provider, model = opts.model:match('^(.-)/(.+)$')\n params.model = { modelID = model, providerID = provider }\n state.current_model = opts.model\n end\n\n if opts.agent then\n params.agent = opts.agent\n state.current_mode = opts.agent\n end\n\n params.parts = context.format_message(prompt, opts.context)\n M.before_run(opts)\n\n if not state.active_session or not state.active_session.id then\n vim.notify('No active session to send message to', vim.log.levels.ERROR)\n return\n end\n state.api_client\n :create_message(state.active_session.id, params)\n :and_then(function(response)\n if not response or not response.info or not response.parts then\n -- fall back to full render. incremental render is handled\n -- event manager\n ui.render_output()\n end\n\n M.after_run(prompt)\n end)\n :catch(function(err)\n vim.notify('Error sending message to session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n M.cancel()\n end)\nend\n\n---@param title? string\n---@return Session?\nfunction M.create_new_session(title)\n local session_response = state.api_client\n :create_session(title and { title = title } or false)\n :catch(function(err)\n vim.notify('Error creating new session: ' .. vim.inspect(err), vim.log.levels.ERROR)\n end)\n :wait()\n\n if session_response and session_response.id then\n local new_session = session.get_by_id(session_response.id)\n return new_session\n end\nend\n\n---@param prompt string\nfunction M.after_run(prompt)\n context.unload_attachments()\n state.last_sent_context = vim.deepcopy(context.context)\n require('opencode.history').write(prompt)\n M._abort_count = 0\nend\n\n---@param opts? SendMessageOpts\nfunction M.before_run(opts)\n local is_new_session = opts and opts.new_session or not state.active_session\n opts = opts or {}\n\n M.cancel()\n -- ui.clear_output()\n\n M.open({\n new_session = is_new_session,\n })\nend\n\nfunction M.configure_provider()\n require('opencode.provider').select(function(selection)\n if not selection then\n if state.windows then\n ui.focus_input()\n end\n return\n end\n local model_str = string.format('%s/%s', selection.provider, selection.model)\n state.current_model = model_str\n\n if state.windows then\n require('opencode.ui.topbar').render()\n ui.focus_input()\n else\n vim.notify('Changed provider to ' .. selection.display, vim.log.levels.INFO)\n end\n end)\nend\n\nfunction M.cancel()\n if state.windows and state.active_session then\n if state.is_running() then\n M._abort_count = M._abort_count + 1\n\n -- if there's a current permission, reject it\n if state.current_permission then\n require('opencode.api').permission_deny()\n end\n\n local ok, result = pcall(function()\n return state.api_client:abort_session(state.active_session.id):wait()\n end)\n\n if not ok then\n vim.notify('Abort error: ' .. vim.inspect(result))\n end\n\n if M._abort_count >= 3 then\n vim.notify('Re-starting Opencode server')\n M._abort_count = 0\n -- close existing server\n if state.opencode_server then\n state.opencode_server:shutdown():wait()\n end\n\n -- start a new one\n state.opencode_server = nil\n\n -- NOTE: start a new server here to make sure we're subscribed\n -- to server events before a user sends a message\n state.opencode_server = server_job.ensure_server() --[[@as OpencodeServer]]\n end\n end\n require('opencode.ui.footer').clear()\n input_window.set_content('')\n require('opencode.history').index = nil\n ui.focus_input()\n end\nend\n\nfunction M.opencode_ok()\n if vim.fn.executable('opencode') == 0 then\n vim.notify(\n 'opencode command not found - please install and configure opencode before using this plugin',\n vim.log.levels.ERROR\n )\n return false\n end\n\n if not state.opencode_cli_version or state.opencode_cli_version == '' then\n local result = vim.system({ 'opencode', '--version' }):wait()\n local out = (result and result.stdout or ''):gsub('%s+$', '')\n state.opencode_cli_version = out:match('(%d+%%.%d+%%.%d+)') or out\n end\n\n local required = state.required_version\n local current_version = state.opencode_cli_version\n\n if not current_version or current_version == '' then\n vim.notify(string.format('Unable to detect opencode CLI version. Requires >= %s', required), vim.log.levels.ERROR)\n return false\n end\n\n if not util.is_version_greater_or_equal(current_version, required) then\n vim.notify(\n string.format('Unsupported opencode CLI version: %s. Requires >= %s', current_version, required),\n vim.log.levels.ERROR\n )\n return false\n end\n\n return true\nend\n\nlocal function on_opencode_server()\n state.current_permission = nil\nend\n\n--- Switches the current mode to the specified agent.\n--- @param mode string The agent/mode to switch to\n--- @return boolean success Returns true if the mode was switched successfully, false otherwise\nfunction M.switch_to_mode(mode)\n if not mode or mode == '' then\n vim.notify('Mode cannot be empty', vim.log.levels.ERROR)\n return false\n end\n\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not vim.tbl_contains(available_agents, mode) then\n vim.notify(\n string.format('Invalid mode \"%s\". Available modes: %s', mode, table.concat(available_agents, ', ')),\n vim.log.levels.ERROR\n )\n return false\n end\n\n state.current_mode = mode\n ui.render_output()\n return true\nend\n\n--- Ensure the current_mode is set using the config.default_mode or falling back to the first available agent.\n--- @return boolean success Returns true if current_mode is set\nfunction M.ensure_current_mode()\n if state.current_mode == nil then\n local config_file = require('opencode.config_file')\n local available_agents = config_file.get_opencode_agents()\n\n if not available_agents or #available_agents == 0 then\n vim.notify('No available agents found', vim.log.levels.ERROR)\n return false\n end\n\n local default_mode = config.default_mode\n\n -- Try to use the configured default mode if it's available\n if default_mode and vim.tbl_contains(available_agents, default_mode) then\n state.current_mode = default_mode\n else\n -- Fallback to first available agent\n state.current_mode = available_agents[1]\n end\n end\n return true\nend\n\nfunction M.setup()\n state.subscribe('opencode_server', on_opencode_server)\n\n vim.schedule(function()\n M.opencode_ok()\n end)\n local OpencodeApiClient = require('opencode.api_client')\n state.api_client = OpencodeApiClient.create()\nend\n\nreturn M\n"}]},"role":"user","sessionID":"ses_5b612cfbefferUqNCDHOrQunq7"}}},{"type":"session.updated","properties":{"info":{"directory":"/home/francis/Projects/_nvim/opencode.nvim","id":"ses_5b612cfbefferUqNCDHOrQunq7","time":{"created":1762176872514,"updated":1762176918135},"summary":{"diffs":[]},"projectID":"29d43526f88157cd4edd071b899dd01f240b771b","title":"Fixing param-type-not-match and need-check-nil in core.lua line 130","version":"0.15.30"}}},{"type":"custom.emit_events.finished","properties":[]}]