Merge pull request #1348 from vignesh07/feat/tui-input-history
feat(tui): add input history (↑/↓) for submitted messages
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
99
src/tui/tui-input-history.test.ts
Normal file
99
src/tui/tui-input-history.test.ts
Normal file
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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> | void;
|
||||
sendMessage: (value: string) => Promise<void> | 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();
|
||||
|
||||
Reference in New Issue
Block a user