From 270079422890c7e4d5bcbe0da9df1434aa2137b5 Mon Sep 17 00:00:00 2001 From: Vignesh Natarajan Date: Tue, 20 Jan 2026 18:21:55 -0800 Subject: [PATCH 1/2] feat(tui): add input history for submitted messages (WIP) Record submitted inputs in the editor history so up/down arrow can recall previous messages. Adds a small helper to wire submit handling and unit tests for routing/recording behavior. No PR yet (per request). --- src/tui/tui-input-history.test.ts | 99 +++++++++++++++++++++++++++++++ src/tui/tui.ts | 39 ++++++++---- 2 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 src/tui/tui-input-history.test.ts diff --git a/src/tui/tui-input-history.test.ts b/src/tui/tui-input-history.test.ts new file mode 100644 index 000000000..1a6870b99 --- /dev/null +++ b/src/tui/tui-input-history.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it, vi } from "vitest"; + +import { createEditorSubmitHandler } from "./tui.js"; + +describe("createEditorSubmitHandler", () => { + it("adds submitted messages to editor history", () => { + const editor = { + setText: vi.fn(), + addToHistory: vi.fn(), + }; + + const handler = createEditorSubmitHandler({ + editor, + handleCommand: vi.fn(), + sendMessage: vi.fn(), + }); + + handler("hello world"); + + expect(editor.setText).toHaveBeenCalledWith(""); + expect(editor.addToHistory).toHaveBeenCalledWith("hello world"); + }); + + it("trims input before adding to history", () => { + const editor = { + setText: vi.fn(), + addToHistory: vi.fn(), + }; + + const handler = createEditorSubmitHandler({ + editor, + handleCommand: vi.fn(), + sendMessage: vi.fn(), + }); + + handler(" hi "); + + expect(editor.addToHistory).toHaveBeenCalledWith("hi"); + }); + + it("does not add empty submissions to history", () => { + const editor = { + setText: vi.fn(), + addToHistory: vi.fn(), + }; + + const handler = createEditorSubmitHandler({ + editor, + handleCommand: vi.fn(), + sendMessage: vi.fn(), + }); + + handler(" "); + + expect(editor.addToHistory).not.toHaveBeenCalled(); + }); + + it("routes slash commands to handleCommand", () => { + const editor = { + setText: vi.fn(), + addToHistory: vi.fn(), + }; + const handleCommand = vi.fn(); + const sendMessage = vi.fn(); + + const handler = createEditorSubmitHandler({ + editor, + handleCommand, + sendMessage, + }); + + handler("/models"); + + expect(editor.addToHistory).toHaveBeenCalledWith("/models"); + expect(handleCommand).toHaveBeenCalledWith("/models"); + expect(sendMessage).not.toHaveBeenCalled(); + }); + + it("routes normal messages to sendMessage", () => { + const editor = { + setText: vi.fn(), + addToHistory: vi.fn(), + }; + const handleCommand = vi.fn(); + const sendMessage = vi.fn(); + + const handler = createEditorSubmitHandler({ + editor, + handleCommand, + sendMessage, + }); + + handler("hello"); + + expect(editor.addToHistory).toHaveBeenCalledWith("hello"); + expect(sendMessage).toHaveBeenCalledWith("hello"); + expect(handleCommand).not.toHaveBeenCalled(); + }); +}); diff --git a/src/tui/tui.ts b/src/tui/tui.ts index a5e6e34d7..bf777f133 100644 --- a/src/tui/tui.ts +++ b/src/tui/tui.ts @@ -36,6 +36,30 @@ import type { export { resolveFinalAssistantText } from "./tui-formatters.js"; export type { TuiOptions } from "./tui-types.js"; +export function createEditorSubmitHandler(params: { + editor: { + setText: (value: string) => void; + addToHistory: (value: string) => void; + }; + handleCommand: (value: string) => Promise | void; + sendMessage: (value: string) => Promise | void; +}) { + return (text: string) => { + const value = text.trim(); + params.editor.setText(""); + if (!value) return; + + // Enable built-in editor prompt history navigation (up/down). + params.editor.addToHistory(value); + + if (value.startsWith("/")) { + void params.handleCommand(value); + return; + } + void params.sendMessage(value); + }; +} + export async function runTui(opts: TuiOptions) { const config = loadConfig(); const initialSessionInput = (opts.session ?? "").trim(); @@ -473,16 +497,11 @@ export async function runTui(opts: TuiOptions) { }); updateAutocompleteProvider(); - editor.onSubmit = (text) => { - const value = text.trim(); - editor.setText(""); - if (!value) return; - if (value.startsWith("/")) { - void handleCommand(value); - return; - } - void sendMessage(value); - }; + editor.onSubmit = createEditorSubmitHandler({ + editor, + handleCommand, + sendMessage, + }); editor.onEscape = () => { void abortActive(); From 6f37f1d8fff6c3310ae4725110ba4511aaa69c43 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 21 Jan 2026 04:37:22 +0000 Subject: [PATCH 2/2] fix: record tui input history (#1348) (thanks @vignesh07) --- CHANGELOG.md | 1 + src/cli/program/command-registry.ts | 1 - src/cli/program/register.subclis.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 897bb18f3..5058a6ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Docs: https://docs.clawd.bot - Skills: add download installs with OS-filtered install options; add local sherpa-onnx-tts skill. - Docs: clarify WhatsApp voice notes and Windows WSL portproxy LAN access notes. - UI: add copy-as-markdown with error feedback and drop legacy list view. (#1345) — thanks @bradleypriest. +- TUI: add input history (up/down) for submitted messages. (#1348) — thanks @vignesh07. ### Fixes - Discovery: shorten Bonjour DNS-SD service type to `_clawdbot-gw._tcp` and update discovery clients/docs. - Agents: preserve subagent announce thread/topic routing + queued replies across channels. (#1241) — thanks @gnarco. diff --git a/src/cli/program/command-registry.ts b/src/cli/program/command-registry.ts index 122cacdb6..0b4618ef0 100644 --- a/src/cli/program/command-registry.ts +++ b/src/cli/program/command-registry.ts @@ -70,7 +70,6 @@ const routeSessions: RouteSpec = { match: (path) => path[0] === "sessions", run: async (argv) => { const json = hasFlag(argv, "--json"); - const verbose = getVerboseFlag(argv); const store = getFlagValue(argv, "--store"); if (store === null) return false; const active = getFlagValue(argv, "--active"); diff --git a/src/cli/program/register.subclis.ts b/src/cli/program/register.subclis.ts index 2f5e46921..74b075af0 100644 --- a/src/cli/program/register.subclis.ts +++ b/src/cli/program/register.subclis.ts @@ -18,7 +18,7 @@ const shouldRegisterPrimaryOnly = (argv: string[]) => { return true; }; -const shouldEagerRegisterSubcommands = (argv: string[]) => { +const shouldEagerRegisterSubcommands = (_argv: string[]) => { return isTruthyEnvValue(process.env.CLAWDBOT_DISABLE_LAZY_SUBCOMMANDS); };