From 8195497cecd0422ccf69ae9f17ef59976883590b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 23 Jan 2026 18:58:41 +0000 Subject: [PATCH] fix: surface gateway slash commands in TUI --- CHANGELOG.md | 1 + src/tui/commands.test.ts | 8 +++++++- src/tui/commands.ts | 20 +++++++++++++++++++- src/tui/tui.ts | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 889c8ef67..d9b07c888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Docs: https://docs.clawd.bot ### Fixes - TUI: forward unknown slash commands (for example, `/context`) to the Gateway. +- TUI: include Gateway slash commands in autocomplete and `/help`. - Media: preserve PNG alpha when possible; fall back to JPEG when still over size cap. (#1491) Thanks @robbyczgw-cla. - Agents: treat plugin-only tool allowlists as opt-ins; keep core tools enabled. (#1467) diff --git a/src/tui/commands.test.ts b/src/tui/commands.test.ts index 2c0fde55d..43be20733 100644 --- a/src/tui/commands.test.ts +++ b/src/tui/commands.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { parseCommand } from "./commands.js"; +import { getSlashCommands, parseCommand } from "./commands.js"; describe("tui slash commands", () => { it("treats /elev as an alias for /elevated", () => { @@ -13,4 +13,10 @@ describe("tui slash commands", () => { args: "off", }); }); + + it("includes gateway text commands", () => { + const commands = getSlashCommands({}); + expect(commands.some((command) => command.name === "context")).toBe(true); + expect(commands.some((command) => command.name === "commands")).toBe(true); + }); }); diff --git a/src/tui/commands.ts b/src/tui/commands.ts index 59806cfbd..04f40bd2c 100644 --- a/src/tui/commands.ts +++ b/src/tui/commands.ts @@ -1,5 +1,7 @@ import type { SlashCommand } from "@mariozechner/pi-tui"; +import { listChatCommands, listChatCommandsForConfig } from "../auto-reply/commands-registry.js"; import { formatThinkingLevels, listThinkingLevelLabels } from "../auto-reply/thinking.js"; +import type { ClawdbotConfig } from "../config/types.js"; const VERBOSE_LEVELS = ["on", "off"]; const REASONING_LEVELS = ["on", "off"]; @@ -13,6 +15,7 @@ export type ParsedCommand = { }; export type SlashCommandOptions = { + cfg?: ClawdbotConfig; provider?: string; model?: string; }; @@ -34,7 +37,7 @@ export function parseCommand(input: string): ParsedCommand { export function getSlashCommands(options: SlashCommandOptions = {}): SlashCommand[] { const thinkLevels = listThinkingLevelLabels(options.provider, options.model); - return [ + const commands: SlashCommand[] = [ { name: "help", description: "Show slash command help" }, { name: "status", description: "Show gateway status summary" }, { name: "agent", description: "Switch agent (or open picker)" }, @@ -115,6 +118,20 @@ export function getSlashCommands(options: SlashCommandOptions = {}): SlashComman { name: "exit", description: "Exit the TUI" }, { name: "quit", description: "Exit the TUI" }, ]; + + const seen = new Set(commands.map((command) => command.name)); + const gatewayCommands = options.cfg ? listChatCommandsForConfig(options.cfg) : listChatCommands(); + for (const command of gatewayCommands) { + const aliases = command.textAliases.length > 0 ? command.textAliases : [`/${command.key}`]; + for (const alias of aliases) { + const name = alias.replace(/^\//, "").trim(); + if (!name || seen.has(name)) continue; + seen.add(name); + commands.push({ name, description: command.description }); + } + } + + return commands; } export function helpText(options: SlashCommandOptions = {}): string { @@ -122,6 +139,7 @@ export function helpText(options: SlashCommandOptions = {}): string { return [ "Slash commands:", "/help", + "/commands", "/status", "/agent (or /agents)", "/session (or /sessions)", diff --git a/src/tui/tui.ts b/src/tui/tui.ts index 37e5752e8..cf8341d59 100644 --- a/src/tui/tui.ts +++ b/src/tui/tui.ts @@ -245,6 +245,7 @@ export async function runTui(opts: TuiOptions) { editor.setAutocompleteProvider( new CombinedAutocompleteProvider( getSlashCommands({ + cfg: config, provider: sessionInfo.modelProvider, model: sessionInfo.model, }),