From f4564b0694f04157f60d58ef74dc4adedf482de4 Mon Sep 17 00:00:00 2001 From: Talha Imtiaz Date: Tue, 9 Jun 2026 20:35:09 +0500 Subject: [PATCH] feat(opencode): expose built-in TUI commands via GET /opencode/command GET /opencode/command previously returned [] when no native OpenCode proxy was configured (e.g. Claude Code mode), so the built-in TUI commands (compact, clear, scroll, etc.) were undiscoverable via the API. Return the built-in command set in that fallback path so frontends can render a complete command palette without depending on a native OpenCode server. Built-ins carry a type: "builtin" discriminator since they are TUI actions rather than prompt-template commands. Closes #142 --- server/packages/opencode-adapter/src/lib.rs | 45 ++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/server/packages/opencode-adapter/src/lib.rs b/server/packages/opencode-adapter/src/lib.rs index b4e04d8a..f476e794 100644 --- a/server/packages/opencode-adapter/src/lib.rs +++ b/server/packages/opencode-adapter/src/lib.rs @@ -924,7 +924,50 @@ async fn oc_command_list(State(state): State>, headers: Header { return response; } - (StatusCode::OK, Json(json!([]))).into_response() + // No native OpenCode proxy is available (e.g. Claude Code mode). Previously + // this returned `[]`, leaving the built-in TUI commands (compact, clear, + // scroll, etc.) undiscoverable via the API. Surface them here so frontends + // can render a complete command palette without depending on a native + // OpenCode server. + (StatusCode::OK, Json(Value::Array(builtin_tui_commands()))).into_response() +} + +/// Built-in TUI commands exposed by the OpenCode TUI client via +/// `EventTuiCommandExecute` and executable through `POST /tui/execute-command`. +/// +/// These are actions (not prompt-template commands), so they are returned with +/// a `type: "builtin"` discriminator alongside the `name`/`description` a +/// command palette needs, to distinguish them from custom/user commands. +fn builtin_tui_commands() -> Vec { + const BUILTINS: &[(&str, &str)] = &[ + ("session.compact", "Compact/summarize context"), + ("session.list", "List sessions"), + ("session.new", "Create new session"), + ("session.share", "Share session"), + ("session.interrupt", "Interrupt current generation"), + ("prompt.clear", "Clear prompt input"), + ("prompt.submit", "Submit prompt"), + ("agent.cycle", "Cycle between agents"), + ("session.page.up", "Scroll page up"), + ("session.page.down", "Scroll page down"), + ("session.line.up", "Scroll line up"), + ("session.line.down", "Scroll line down"), + ("session.half.page.up", "Scroll half page up"), + ("session.half.page.down", "Scroll half page down"), + ("session.first", "Jump to first message"), + ("session.last", "Jump to last message"), + ]; + + BUILTINS + .iter() + .map(|(name, description)| { + json!({ + "name": name, + "description": description, + "type": "builtin", + }) + }) + .collect() } async fn oc_config_get(State(state): State>, headers: HeaderMap) -> Response {