From 9da4c1be1fcb0e256862f56293c3cec264733419 Mon Sep 17 00:00:00 2001 From: Nash Kabbara Date: Tue, 13 Jan 2026 10:39:21 -0300 Subject: [PATCH 1/2] Select session --- lua/opencode.lua | 1 + lua/opencode/cli/client.lua | 23 +++++++++++ lua/opencode/config.lua | 1 + lua/opencode/ui/select.lua | 6 ++- lua/opencode/ui/select_session.lua | 61 ++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 lua/opencode/ui/select_session.lua diff --git a/lua/opencode.lua b/lua/opencode.lua index 1e6880b1..47d9cc72 100644 --- a/lua/opencode.lua +++ b/lua/opencode.lua @@ -3,6 +3,7 @@ local M = {} M.ask = require("opencode.ui.ask").ask M.select = require("opencode.ui.select").select +M.select_session = require("opencode.ui.select_session").select_session M.prompt = require("opencode.api.prompt").prompt M.operator = require("opencode.api.operator").operator diff --git a/lua/opencode/cli/client.lua b/lua/opencode/cli/client.lua index 85530656..353a5892 100644 --- a/lua/opencode/cli/client.lua +++ b/lua/opencode/cli/client.lua @@ -214,6 +214,29 @@ function M.get_commands(port, callback) M.call(port, "/command", "GET", nil, callback) end +---@class opencode.cli.client.SessionTime +---@field created integer +---@field updated integer + +---@class opencode.cli.client.Session +---@field id string +---@field title string +---@field time opencode.cli.client.SessionTime + +---Get sessions from `opencode`. +--- +---@param port number +---@param callback fun(sessions: opencode.cli.client.Session[]) +function M.get_sessions(port, callback) + M.call(port, "/session", "GET", nil, callback) +end + +---Select session in `opencode`. +--- +function M.select_session(port, session_id) + M.call(port, "/tui/select-session", "POST", { sessionID = session_id }, nil) +end + ---@class opencode.cli.client.PathResponse ---@field directory string ---@field worktree string diff --git a/lua/opencode/config.lua b/lua/opencode/config.lua index 2b1a3d78..7f860e4d 100644 --- a/lua/opencode/config.lua +++ b/lua/opencode/config.lua @@ -89,6 +89,7 @@ local defaults = { prompts = true, commands = { ["session.new"] = "Start a new session", + ["session.select"] = "Select a session", ["session.share"] = "Share the current session", ["session.interrupt"] = "Interrupt the current session", ["session.compact"] = "Compact the current session (reduce context size)", diff --git a/lua/opencode/ui/select.lua b/lua/opencode/ui/select.lua index 9e74829c..98186d9b 100644 --- a/lua/opencode/ui/select.lua +++ b/lua/opencode/ui/select.lua @@ -221,7 +221,11 @@ function M.select(opts) require("opencode").prompt(prompt.prompt, prompt) end elseif choice.__type == "command" then - require("opencode").command(choice.name) + if choice.name == "session.select" then + require("opencode").select_session() + else + require("opencode").command(choice.name) + end elseif choice.__type == "provider" then if choice.name == "toggle" then require("opencode").toggle() diff --git a/lua/opencode/ui/select_session.lua b/lua/opencode/ui/select_session.lua new file mode 100644 index 00000000..82074209 --- /dev/null +++ b/lua/opencode/ui/select_session.lua @@ -0,0 +1,61 @@ +local M = {} + +function M.select_session() + require("opencode.cli.server") + .get_port() + :next(function(port) + return require("opencode.promise").new(function(resolve) + require("opencode.cli.client").get_sessions(port, function(sessions) + resolve({ sessions = sessions, port = port }) + end) + end) + end) + :next(function(session_data) + local sessions = {} + for _, session in ipairs(session_data.sessions) do + ---@type opencode.cli.client.Session + local item = { + id = session.id, + title = session.title, + time = { + created = math.floor(session.time.created), + updated = math.floor(session.time.updated), + }, + } + table.insert(sessions, item) + end + + table.sort(sessions, function(a, b) + return a.time.updated > b.time.updated + end) + + vim.ui.select(sessions, { + prompt = "Select session (recently updated first):", + format_item = function(item) + local title_length = 60 + local updated = os.date("%b %d, %Y %H:%M:%S", item.time.updated / 1000) + local title = M.ellipsize(item.title, title_length) + return ("%s%s%s"):format(title, string.rep(" ", title_length - #title), updated) + end, + }, function(choice) + if choice then + require("opencode.cli.client").select_session(session_data.port, choice.id) + end + end) + end) + :catch(function(err) + vim.notify(err, vim.log.levels.ERROR) + end) +end + +function M.ellipsize(s, max_len) + if vim.fn.strdisplaywidth(s) <= max_len then + return s + end + local truncated = vim.fn.strcharpart(s, 0, max_len - 3) + truncated = truncated:gsub("%s+%S*$", "") + + return truncated .. "..." +end + +return M From 661c96d8902d263e8592d00f54a43f04894b8552 Mon Sep 17 00:00:00 2001 From: Nash Kabbara Date: Tue, 20 Jan 2026 14:18:17 -0300 Subject: [PATCH 2/2] fix review comment --- lua/opencode/cli/client.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/opencode/cli/client.lua b/lua/opencode/cli/client.lua index 353a5892..33926a9d 100644 --- a/lua/opencode/cli/client.lua +++ b/lua/opencode/cli/client.lua @@ -233,6 +233,8 @@ end ---Select session in `opencode`. --- +---@param port number +---@param session_id number function M.select_session(port, session_id) M.call(port, "/tui/select-session", "POST", { sessionID = session_id }, nil) end