mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 20:03:05 +00:00
The Editor component now accepts TUI as the first constructor parameter, enabling it to query terminal dimensions. When content exceeds available height, the editor scrolls vertically keeping the cursor visible. Features: - Max editor height is 30% of terminal rows (minimum 5 lines) - Page Up/Down keys scroll by page size - Scroll indicators show lines above/below: ─── ↑ 5 more ─── Breaking change: Editor constructor signature changed from new Editor(theme) to new Editor(tui, theme) fixes #732
129 lines
3.4 KiB
TypeScript
129 lines
3.4 KiB
TypeScript
/**
|
|
* Simple chat interface demo using tui.ts
|
|
*/
|
|
|
|
import chalk from "chalk";
|
|
import { CombinedAutocompleteProvider } from "../src/autocomplete.js";
|
|
import { Editor } from "../src/components/editor.js";
|
|
import { Loader } from "../src/components/loader.js";
|
|
import { Markdown } from "../src/components/markdown.js";
|
|
import { Text } from "../src/components/text.js";
|
|
import { ProcessTerminal } from "../src/terminal.js";
|
|
import { TUI } from "../src/tui.js";
|
|
import { defaultEditorTheme, defaultMarkdownTheme } from "./test-themes.js";
|
|
|
|
// Create terminal
|
|
const terminal = new ProcessTerminal();
|
|
|
|
// Create TUI
|
|
const tui = new TUI(terminal);
|
|
|
|
// Create chat container with some initial messages
|
|
tui.addChild(
|
|
new Text("Welcome to Simple Chat!\n\nType your messages below. Type '/' for commands. Press Ctrl+C to exit."),
|
|
);
|
|
|
|
// Create editor with autocomplete
|
|
const editor = new Editor(tui, defaultEditorTheme);
|
|
|
|
// Set up autocomplete provider with slash commands and file completion
|
|
const autocompleteProvider = new CombinedAutocompleteProvider(
|
|
[
|
|
{ name: "delete", description: "Delete the last message" },
|
|
{ name: "clear", description: "Clear all messages" },
|
|
],
|
|
process.cwd(),
|
|
);
|
|
editor.setAutocompleteProvider(autocompleteProvider);
|
|
|
|
tui.addChild(editor);
|
|
|
|
// Focus the editor
|
|
tui.setFocus(editor);
|
|
|
|
// Track if we're waiting for bot response
|
|
let isResponding = false;
|
|
|
|
// Handle message submission
|
|
editor.onSubmit = (value: string) => {
|
|
// Prevent submission if already responding
|
|
if (isResponding) {
|
|
return;
|
|
}
|
|
|
|
const trimmed = value.trim();
|
|
|
|
// Handle slash commands
|
|
if (trimmed === "/delete") {
|
|
const children = tui.children;
|
|
// Remove component before editor (if there are any besides the initial text)
|
|
if (children.length > 3) {
|
|
// children[0] = "Welcome to Simple Chat!"
|
|
// children[1] = "Type your messages below..."
|
|
// children[2...n-1] = messages
|
|
// children[n] = editor
|
|
children.splice(children.length - 2, 1);
|
|
}
|
|
tui.requestRender();
|
|
return;
|
|
}
|
|
|
|
if (trimmed === "/clear") {
|
|
const children = tui.children;
|
|
// Remove all messages but keep the welcome text and editor
|
|
children.splice(2, children.length - 3);
|
|
tui.requestRender();
|
|
return;
|
|
}
|
|
|
|
if (trimmed) {
|
|
isResponding = true;
|
|
editor.disableSubmit = true;
|
|
|
|
const userMessage = new Markdown(value, 1, 1, defaultMarkdownTheme);
|
|
|
|
const children = tui.children;
|
|
children.splice(children.length - 1, 0, userMessage);
|
|
|
|
const loader = new Loader(
|
|
tui,
|
|
(s) => chalk.cyan(s),
|
|
(s) => chalk.dim(s),
|
|
"Thinking...",
|
|
);
|
|
children.splice(children.length - 1, 0, loader);
|
|
|
|
tui.requestRender();
|
|
|
|
setTimeout(() => {
|
|
tui.removeChild(loader);
|
|
|
|
// Simulate a response
|
|
const responses = [
|
|
"That's interesting! Tell me more.",
|
|
"I see what you mean.",
|
|
"Fascinating perspective!",
|
|
"Could you elaborate on that?",
|
|
"That makes sense to me.",
|
|
"I hadn't thought of it that way.",
|
|
"Great point!",
|
|
"Thanks for sharing that.",
|
|
];
|
|
const randomResponse = responses[Math.floor(Math.random() * responses.length)];
|
|
|
|
// Add assistant message with no background (transparent)
|
|
const botMessage = new Markdown(randomResponse, 1, 1, defaultMarkdownTheme);
|
|
children.splice(children.length - 1, 0, botMessage);
|
|
|
|
// Re-enable submit
|
|
isResponding = false;
|
|
editor.disableSubmit = false;
|
|
|
|
// Request render
|
|
tui.requestRender();
|
|
}, 1000);
|
|
}
|
|
};
|
|
|
|
// Start the TUI
|
|
tui.start();
|