From 6592e167d79d2b3f0b721109ded877de82c69cea Mon Sep 17 00:00:00 2001 From: Samuel O'Neal Date: Mon, 21 Sep 2026 06:49:39 -0600 Subject: [PATCH 1/3] fix(ai): restore opencode.nvim integration with OpenCode V1 CLI opencode.nvim drives the HTTP API that `opencode --port` exposes, but the installed OpenCode v2.0.11 CLI removed the --port flag and replaced the server API (pairing auth, new endpoints). opencode.nvim does not support v2 yet (upstream issue nickjvandyke/opencode.nvim#322), so: - Bump opencode.nvim to v1.0.2 (latest V1-compatible release) - Migrate to its current API: snacks `opencode_send` picker action now uses format()/prompt() (snacks_picker_send was removed in v0.12.0), drop the opencode.terminal on_win hook and the removed server.stop/server.toggle and lsp opts - Move at toggling to snacks.terminal.toggle (opencode.toggle() was removed in v1.0.2) - Fix the session.half.page.up typo (sesion -> session) in the scroll-up keymap - Document the V1 CLI requirement and pin instructions in the README --- .secrets.baseline | 4 ++-- README.md | 23 +++++++++++++++++++---- lua/config/keymaps.lua | 8 ++++++-- lua/plugins/ai.lua | 35 ++++++++++++++++++----------------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 34032de..d7d5633 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -142,7 +142,7 @@ "filename": "README.md", "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", "is_verified": false, - "line_number": 85 + "line_number": 101 } ], "lazy-lock.json": [ @@ -582,5 +582,5 @@ } ] }, - "generated_at": "2026-06-06T21:52:58Z" + "generated_at": "2026-09-21T12:49:12Z" } diff --git a/README.md b/README.md index c227427..e83e032 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,22 @@ AI is intentionally **environment-agnostic**: opencode.nvim drives the external OpenAI, local models, etc.) is chosen in opencode's own config rather than here. Install the `opencode` CLI separately and configure your provider there. +> [!IMPORTANT] +> This integration requires the OpenCode **V1** CLI. opencode.nvim connects to +> the API server that `opencode --port` exposes; OpenCode **v2 removed that +> flag** and replaced the server API (v2 support in opencode.nvim is tracked +> upstream in [nickjvandyke/opencode.nvim#322](https://github.com/nickjvandyke/opencode.nvim/issues/322)). +> +> Pin V1 with the install script (replace `1.18.31` with the latest V1 release): +> +> ```sh +> curl -fsSL https://opencode.ai/install | bash -s -- --version 1.18.31 +> ``` +> +> If you're already on V1, downgrade with `opencode upgrade v1.18.31`. Set +> `OPENCODE_DISABLE_AUTOUPDATE=1` so the pinned V1 binary is not auto-upgraded +> to v2 the next time an update check runs. + ### Database (vim-dadbod) Open the UI with `Du`. Add a connection with `Da`. Examples: @@ -353,7 +369,6 @@ project, branch, and worktree count when inside a git repo. ## Known issues (in current repo) -Two unrelated typos exist in `lua/config/keymaps.lua`'s opencode block (present -before these docs): the scroll-up command string reads `sesion.half.page.up` -(should be `session.…`), and `at` is mapped in `t` (terminal) mode where -`n`/`x` is likely intended. Documented here for accuracy; fix when convenient. +One quirk remains in `lua/config/keymaps.lua`'s opencode block (present before +these docs): `at` is also mapped in `t` (terminal) mode, not just `n` — +intentional, so the TUI terminal window itself can toggle the split. diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index ac482ee..665e45d 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -69,7 +69,11 @@ map({ "n", "x" }, "ax", function() require("opencode").select() end, { desc = "AI Ask (selection)" }) map({ "n", "t" }, "at", function() - require("opencode").toggle() + -- opencode.nvim v1.0.2 removed `opencode.toggle()`; toggle the TUI terminal + -- directly. Command must match `opencode_cmd` in lua/plugins/ai.lua. + require("snacks.terminal").toggle("opencode --port", { + win = { position = "right", enter = false }, + }) end, { desc = "AI Toggle" }) map({ "n", "x" }, "go", function() @@ -80,7 +84,7 @@ map("n", "goo", function() end, { desc = "Add line to AI chat", expr = true }) map("n", "", function() - require("opencode").command("sesion.half.page.up") + require("opencode").command("session.half.page.up") end, { desc = "Scroll AI chat up" }) map("n", "", function() require("opencode").command("session.half.page.down") diff --git a/lua/plugins/ai.lua b/lua/plugins/ai.lua index 9d50fce..d6b080d 100644 --- a/lua/plugins/ai.lua +++ b/lua/plugins/ai.lua @@ -1,7 +1,13 @@ return { { + -- Drive the OpenCode TUI from Neovim. + -- + -- IMPORTANT: this integration requires the OpenCode **V1** CLI. opencode.nvim + -- connects to the HTTP API that `opencode --port` exposes; OpenCode v2 removed + -- that flag and replaced the server API, which opencode.nvim does not support + -- yet (https://github.com/nickjvandyke/opencode.nvim/issues/322). "nickjvandyke/opencode.nvim", - version = "v0.10.1", + version = "v1.0.2", dependencies = { { ---@module "snacks" @@ -11,8 +17,14 @@ return { input = {}, -- Enhances `ask()` picker = { -- Enhances `select()` actions = { - opencode_send = function(...) - return require("opencode").snacks_picker_send(...) + opencode_send = function(picker) ---@param picker snacks.Picker + local items = vim.tbl_map(function(item) ---@param item snacks.picker.Item + return item.file + and require("opencode").format({ path = item.file, from = item.pos, to = item.end_pos }) + or item.text + end, picker:selected({ fallback = true })) + + require("opencode").prompt(table.concat(items, ", ") .. " ") end, }, win = { @@ -27,38 +39,27 @@ return { }, }, config = function() + -- `--port` exposes OpenCode's HTTP API, which opencode.nvim discovers and + -- connects to. V1 CLI only; v2 removed this flag. local opencode_cmd = "opencode --port" ---@type snacks.terminal.Opts local snacks_terminal_opts = { win = { position = "right", enter = false, - on_win = function(win) - -- Set up keymaps and cleanup for an arbitary terminal - require("opencode.terminal").setup(win.win) - end, }, } ---@type opencode.Opts vim.g.opencode_opts = { - -- Specific configuration around opencode server = { start = function() require("snacks.terminal").open(opencode_cmd, snacks_terminal_opts) end, - stop = function() - require("snacks.terminal").get(opencode_cmd, snacks_terminal_opts):close() - end, - toggle = function() - require("snacks.terminal").toggle(opencode_cmd, snacks_terminal_opts) - end, - }, - lsp = { - enabled = true, }, } + -- Reload buffers that OpenCode edits (the plugin also sets this itself) vim.o.autoread = true -- Required for `opts.events.reload` end, }, -- 2.54.0 From 01780e13e89341ad5e6902508d2dd93d1f865ef5 Mon Sep 17 00:00:00 2001 From: Samuel O'Neal Date: Mon, 21 Sep 2026 07:03:08 -0600 Subject: [PATCH 2/3] fix(ai): point opencode.nvim at pinned V1 binary; keep terminal on v2 opencode.nvim requires the V1 CLI (--port was removed in v2). Use the pinned V1 binary at ~/.opencode/bin/opencode explicitly for both the server spawn (ai.lua) and the at toggle (keymaps.lua), so the interactive shell keeps resolving 'opencode' (v2) from its normal PATH. Scope OPENCODE_DISABLE_AUTOUPDATE=1 to the spawned V1 process via snacks.terminal env (jobstart merges env over the parent environment) so the pinned binary cannot replace itself with v2, without freezing the terminal's v2 updates. --- .secrets.baseline | 4 ++-- README.md | 15 ++++++++++++--- lua/config/keymaps.lua | 7 +++++-- lua/plugins/ai.lua | 11 ++++++++++- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index d7d5633..865ec41 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -142,7 +142,7 @@ "filename": "README.md", "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", "is_verified": false, - "line_number": 101 + "line_number": 110 } ], "lazy-lock.json": [ @@ -582,5 +582,5 @@ } ] }, - "generated_at": "2026-09-21T12:49:12Z" + "generated_at": "2026-09-21T13:00:27Z" } diff --git a/README.md b/README.md index e83e032..3a8a87d 100644 --- a/README.md +++ b/README.md @@ -83,15 +83,24 @@ Install the `opencode` CLI separately and configure your provider there. > flag** and replaced the server API (v2 support in opencode.nvim is tracked > upstream in [nickjvandyke/opencode.nvim#322](https://github.com/nickjvandyke/opencode.nvim/issues/322)). > +> **Binary split:** Neovim explicitly launches the pinned V1 binary at +> `~/.opencode/bin/opencode` (see `opencode_cmd` in `lua/plugins/ai.lua` and the +> `at` toggle in `lua/config/keymaps.lua`), so your terminal is free to +> keep using the latest `opencode` (v2) from its normal PATH. +> > Pin V1 with the install script (replace `1.18.31` with the latest V1 release): > > ```sh > curl -fsSL https://opencode.ai/install | bash -s -- --version 1.18.31 > ``` > -> If you're already on V1, downgrade with `opencode upgrade v1.18.31`. Set -> `OPENCODE_DISABLE_AUTOUPDATE=1` so the pinned V1 binary is not auto-upgraded -> to v2 the next time an update check runs. +> Do **not** put `~/.opencode/bin` on your shell PATH or set +> `OPENCODE_DISABLE_AUTOUPDATE=1` globally: installing the pinned binary via the +> script above prepends `~/.opencode/bin` to `PATH` in `~/.zshrc` (remove that +> line) and a global env var would stop the terminal's v2 from auto-updating. +> Instead, the config sets `OPENCODE_DISABLE_AUTOUPDATE=1` on the spawned V1 +> process only, so the pinned binary can't replace itself with v2 while your +> terminal's opencode keeps updating. ### Database (vim-dadbod) diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua index 665e45d..19fdd42 100644 --- a/lua/config/keymaps.lua +++ b/lua/config/keymaps.lua @@ -70,8 +70,11 @@ map({ "n", "x" }, "ax", function() end, { desc = "AI Ask (selection)" }) map({ "n", "t" }, "at", function() -- opencode.nvim v1.0.2 removed `opencode.toggle()`; toggle the TUI terminal - -- directly. Command must match `opencode_cmd` in lua/plugins/ai.lua. - require("snacks.terminal").toggle("opencode --port", { + -- directly. Command, `env` and window opts must match `opencode_cmd` and + -- `snacks_terminal_opts` in lua/plugins/ai.lua so `snacks.terminal.tid` + -- identifies the same terminal. + require("snacks.terminal").toggle(vim.fn.expand("$HOME/.opencode/bin/opencode") .. " --port", { + env = { OPENCODE_DISABLE_AUTOUPDATE = "1" }, win = { position = "right", enter = false }, }) end, { desc = "AI Toggle" }) diff --git a/lua/plugins/ai.lua b/lua/plugins/ai.lua index d6b080d..d349d4f 100644 --- a/lua/plugins/ai.lua +++ b/lua/plugins/ai.lua @@ -41,9 +41,18 @@ return { config = function() -- `--port` exposes OpenCode's HTTP API, which opencode.nvim discovers and -- connects to. V1 CLI only; v2 removed this flag. - local opencode_cmd = "opencode --port" + -- + -- Binary split: nvim explicitly uses the pinned V1 binary at + -- ~/.opencode/bin/opencode while the interactive shell keeps using the + -- latest `opencode` (v2) from its PATH. Keep this in sync with the + -- `at` toggle in lua/config/keymaps.lua. + local opencode_cmd = vim.fn.expand("$HOME/.opencode/bin/opencode") .. " --port" ---@type snacks.terminal.Opts local snacks_terminal_opts = { + -- V1 checks for updates on startup and would replace itself with V2; + -- disable autoupdate for this pinned binary only (does not affect the + -- terminal's v2, which keeps updating). + env = { OPENCODE_DISABLE_AUTOUPDATE = "1" }, win = { position = "right", enter = false, -- 2.54.0 From 249fcb687ae57428640e61a38fd7806f91334475 Mon Sep 17 00:00:00 2001 From: Samuel O'Neal Date: Mon, 21 Sep 2026 07:04:23 -0600 Subject: [PATCH 3/3] chore(lazy): pin opencode.nvim v1.0.2 in lazy-lock.json --- lazy-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/lazy-lock.json b/lazy-lock.json index 4209a75..e936fc6 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -31,6 +31,7 @@ "neotest-golang": { "branch": "main", "commit": "53f06063780b0b244583d3d32b138fc2df21e162" }, "neotest-python": { "branch": "master", "commit": "b0d3a861bd85689d8ed73f0590c47963a7eb1bf9" }, "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" }, + "opencode.nvim": { "branch": "main", "commit": "84eabfbe65a44f452ee302fe360cea9fd9939f31" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, "nvim-colorizer.lua": { "branch": "master", "commit": "81e676d3203c9eb6e4c0ccf1eba1679296ef923f" }, "nvim-coverage": { "branch": "main", "commit": "a939e425e363319d952a6c35fb3f38b34041ded2" }, -- 2.54.0