feat(tui): implement interactive menu system for model and config selection
This commit is contained in:
@@ -35,11 +35,10 @@ export const COMMANDS: string[] = [
|
||||
"/help",
|
||||
"/quit",
|
||||
"/clear",
|
||||
"/edit",
|
||||
"/mcp add",
|
||||
"/edit <path>",
|
||||
"/mcp",
|
||||
"/model",
|
||||
"/model ls",
|
||||
"/model add",
|
||||
"/config",
|
||||
"/todo",
|
||||
"/usage",
|
||||
"/compact",
|
||||
@@ -256,6 +255,7 @@ export const Overlay = {
|
||||
ModelSelector: "model_selector",
|
||||
ClearConfirm: "clear_confirm",
|
||||
Diff: "diff",
|
||||
Menu: "menu",
|
||||
} as const;
|
||||
export type Overlay = (typeof Overlay)[keyof typeof Overlay];
|
||||
|
||||
@@ -299,6 +299,35 @@ export interface ActivityEntry {
|
||||
count?: number;
|
||||
}
|
||||
|
||||
/* ── Interactive menu ─────────────────────────────────────────────── */
|
||||
|
||||
/**
|
||||
* A single frame in the interactive menu stack. Reusable across every
|
||||
* configuration surface (models, settings, MCP, todo, …) so each is a
|
||||
* picker like Claude Code / opencode — never inline sub-commands.
|
||||
*/
|
||||
export interface MenuFrame {
|
||||
/** Stable id used by the resolver to route Enter (e.g. "model:provider"). */
|
||||
id: string;
|
||||
title: string;
|
||||
/** Selectable option labels (one line each). */
|
||||
items: string[];
|
||||
/** Optional dim detail shown under each option. */
|
||||
details?: string[];
|
||||
/** Footer hint line (keybindings / current value). */
|
||||
hint?: string;
|
||||
selected: number;
|
||||
/** Live type-to-filter: typing narrows/highlights matching rows. */
|
||||
filter?: string;
|
||||
}
|
||||
|
||||
export const emptyMenuFrame = (): MenuFrame => ({
|
||||
id: "",
|
||||
title: "",
|
||||
items: [],
|
||||
selected: 0,
|
||||
});
|
||||
|
||||
/* ── Misc state ───────────────────────────────────────────────────── */
|
||||
|
||||
/** The "miscellaneous" slice of app state. */
|
||||
@@ -320,6 +349,8 @@ export class MiscState {
|
||||
diffScroll = 0;
|
||||
/** Breadcrumb of the current turn's activity (tools / sub-agents). */
|
||||
activity: ActivityEntry[] = [];
|
||||
/** Stack of interactive menu frames (top = currently shown). */
|
||||
menuStack: MenuFrame[] = [];
|
||||
|
||||
pushToast(toast: { kind: string; message: string; createdMs: number; ttlMs: number }): void {
|
||||
this.toasts.push(toast);
|
||||
@@ -523,18 +554,26 @@ export const DEFAULT_HELP_TEXT = ` Zesdex TUI — Keyboard Shortcuts
|
||||
|
||||
─── Overlays ───
|
||||
/help Show this help
|
||||
/model Pick provider → model (interactive)
|
||||
/config Settings menu (internet, review, provider)
|
||||
/todo Open tasks (todo) overlay
|
||||
/usage Open usage statistics
|
||||
/diff Open git diff overlay
|
||||
/plan Open plan overlay
|
||||
/mcp Open MCP server management
|
||||
/model Open model selector
|
||||
/compact Compact conversation
|
||||
/clear Clear transcript
|
||||
|
||||
─── Menus (interactive pickers) ───
|
||||
↑/↓ · j/k Move selection
|
||||
PgUp/PgDn Page Home/End — jump
|
||||
g / G Top / Bottom
|
||||
type a-z Type-to-filter
|
||||
Enter Open / apply
|
||||
Esc Back / close
|
||||
|
||||
─── Editor Mode ───
|
||||
/edit <path> Open file for inline editing
|
||||
Ctrl+S Save changes (not yet wired)
|
||||
Esc Dismiss editor
|
||||
|
||||
─── Legend ───
|
||||
|
||||
Reference in New Issue
Block a user