Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ mayros -p "refactor auth flow" # headless mode (non-interactive)

- 🎨 3 themes (dark, light, high-contrast) — `/theme`
- 📝 3 output styles (standard, explanatory, learning) — `/style`
- ⌨️ Vim mode with motions, operators, undo — `/vim`
- 📋 `Ctrl+V` image paste from clipboard
- 📊 `/diff` inline diff viewer · `/context` token usage chart
- 🗺️ `/plan` semantic plan mode (Cortex-backed)
Expand All @@ -165,15 +164,15 @@ mayros -p "refactor auth flow" # headless mode (non-interactive)

**Slash commands (30+):**

| Command | Description | Command | Description |
| ---------------- | ----------------- | ---------------- | -------------------- |
| `/help` | List all commands | `/plan` | Semantic plan mode |
| `/new` | Reset session | `/diff` | Show pending changes |
| `/compact` | Compact context | `/context` | Token usage chart |
| `/think <level>` | Set thinking | `/theme` | Cycle themes |
| `/model <name>` | Switch model | `/vim` | Toggle vim mode |
| `/permission` | Permission mode | `/copy` | Copy last response |
| `/fast` | Fast mode | `/export [file]` | Export session |
| Command | Description | Command | Description |
| ---------------- | ----------------- | ------------- | -------------------- |
| `/help` | List all commands | `/plan` | Semantic plan mode |
| `/new` | Reset session | `/diff` | Show pending changes |
| `/compact` | Compact context | `/context` | Token usage chart |
| `/think <level>` | Set thinking | `/theme` | Cycle themes |
| `/model <name>` | Switch model | `/permission` | Permission mode |
| `/fast` | Fast mode | `/copy` | Copy last response |
| `/export [file]` | Export session | `/context` | Token usage chart |

**Markdown-driven extensibility:**

Expand Down
2 changes: 1 addition & 1 deletion docs/platforms/tui-redesign.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Priorities are assigned as P0 (correctness or blocker), P1 (high-value polish),

### P0 — Correctness and blockers

1. **Verify the vim bridge is connected.** If the editor bridge is never set from the TUI side, every vim motion that relies on it silently no-ops. Confirm or fix before any further vim work.
1. ~~**Verify the vim bridge is connected.**~~ **Resolved: vim mode has been disabled.** The bridge was never wired and the rendering dependency does not expose the cursor API needed to fix it cleanly. The `/vim` command now reports that the feature is unavailable, the dead handler and its tests have been removed, and the config flag is deprecated. Emacs/readline-style keybindings (Ctrl+A/E/W/U/K) remain available via the editor.
2. **Accessibility TUI feature parity.** Either linearize the graphical renderer for screen readers or bring slash commands, session switching, and abort into the accessibility TUI. The current split excludes users from most functionality.

### P1 — High-value polish
Expand Down
2 changes: 1 addition & 1 deletion src/config/types.mayros.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export type MayrosConfig = {
seamColor?: string;
/** TUI color theme preset, or "auto" to detect from the terminal. */
theme?: "auto" | "dark" | "light" | "high-contrast";
/** Enable vim editing mode in the TUI. */
/** Deprecated: vim mode is not available. Kept for config backward compat. */
vim?: boolean;
/** Custom keybindings for TUI actions. */
keybindings?: Record<string, string | string[]>;
Expand Down
2 changes: 1 addition & 1 deletion src/tui/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export function getSlashCommands(options: SlashCommandOptions = {}): SlashComman
},
{
name: "vim",
description: "Toggle vim editing mode",
description: "Vim mode (unavailable)",
},
{
name: "permission",
Expand Down
12 changes: 0 additions & 12 deletions src/tui/components/custom-editor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Editor, Key, matchesKey } from "@earendil-works/pi-tui";
import type { ClipboardImage } from "../clipboard-image.js";
import type { TuiKeybindingResolver } from "../keybinding-resolver.js";
import type { VimHandler } from "../vim-handler.js";

const BRACKET_PASTE_START = "\x1b[200~";
const BRACKET_PASTE_END = "\x1b[201~";
Expand All @@ -25,7 +24,6 @@ export class CustomEditor extends Editor {
onAltEnter?: () => void;
onImagePaste?: (image: ImagePasteEvent) => void;
tuiResolver?: TuiKeybindingResolver;
vimHandler?: VimHandler;

private imageCounter = 0;
captureClipboardImage: (() => ClipboardImage | null) | null = null;
Expand Down Expand Up @@ -58,12 +56,6 @@ export class CustomEditor extends Editor {
// No image on clipboard — ignore the empty paste
return;
}
// Vim mode intercept: if vim is in normal mode, consume keys there.
if (this.vimHandler?.isNormalMode()) {
if (this.vimHandler.handleKey(data)) {
return;
}
}
if (matchesKey(data, Key.alt("enter")) && this.onAltEnter) {
this.onAltEnter();
return;
Expand Down Expand Up @@ -118,10 +110,6 @@ export class CustomEditor extends Editor {
return;
}
if (matchesKey(data, Key.escape) && !this.isShowingAutocomplete()) {
// In vim insert mode, Escape switches to normal mode
if (this.vimHandler && this.vimHandler.handleKey(data)) {
return;
}
if (this.onEscape) {
this.onEscape();
return;
Expand Down
5 changes: 2 additions & 3 deletions src/tui/keybinding-resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ describe("TuiKeybindingResolver", () => {
expect(piTuiMocks.matchesKey).toHaveBeenCalledWith("\x07", "ctrl+g");
});

it("returns false when action has no keys", () => {
it("returns false when the data does not match any action", () => {
const resolver = new TuiKeybindingResolver();
expect(resolver.matches("\x00", "toggleVim")).toBe(false);
expect(resolver.matches("\x00", "toggleTools")).toBe(false);
});
});

Expand All @@ -69,7 +69,6 @@ describe("DEFAULT_TUI_KEYBINDINGS", () => {
expect(DEFAULT_TUI_KEYBINDINGS).toHaveProperty("selectSession");
expect(DEFAULT_TUI_KEYBINDINGS).toHaveProperty("toggleTools");
expect(DEFAULT_TUI_KEYBINDINGS).toHaveProperty("toggleThinking");
expect(DEFAULT_TUI_KEYBINDINGS).toHaveProperty("toggleVim");
});
});

Expand Down
4 changes: 1 addition & 3 deletions src/tui/keybinding-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ export type TuiAction =
| "selectModel"
| "selectSession"
| "toggleTools"
| "toggleThinking"
| "toggleVim";
| "toggleThinking";

export const DEFAULT_TUI_KEYBINDINGS: Record<TuiAction, KeyId> = {
selectAgent: "ctrl+g",
selectModel: "ctrl+l",
selectSession: "ctrl+p",
toggleTools: "ctrl+o",
toggleThinking: "ctrl+t",
toggleVim: "ctrl+shift+v",
};

export class TuiKeybindingResolver {
Expand Down
4 changes: 1 addition & 3 deletions src/tui/tui-command-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -773,9 +773,7 @@ export function createCommandHandlers(context: CommandHandlerContext) {
}
break;
case "vim": {
const enabled = !state.vimEnabled;
state.vimEnabled = enabled;
chatLog.addSystem(`vim mode ${enabled ? "enabled" : "disabled"}`);
chatLog.addSystem("vim mode is not available in this build");
break;
}
case "permission": {
Expand Down
16 changes: 1 addition & 15 deletions src/tui/tui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import { editorTheme, theme, setThemePreset } from "./theme/theme.js";
import { createCommandHandlers } from "./tui-command-handlers.js";
import { createEventHandlers } from "./tui-event-handlers.js";
import { MouseHandler, createMouseInputListener } from "./mouse-handler.js";
import { VimHandler } from "./vim-handler.js";
import { formatTokens } from "./tui-formatters.js";
import { createLocalShellRunner } from "./tui-local-shell.js";
import { createOverlayHandlers } from "./tui-overlays.js";
Expand Down Expand Up @@ -316,8 +315,7 @@ export async function runTui(opts: TuiOptions) {
let permissionMode: "auto" | "ask" | "deny" = "auto";
let fastMode = false;
let previousThinkingLevel: string | undefined;
let vimEnabled = config.ui?.vim ?? false;
const vimHandler = new VimHandler();
let vimEnabled = false;
const mouseHandler = new MouseHandler({
scrollLines: 3,
scrollAcceleration: true,
Expand Down Expand Up @@ -476,12 +474,6 @@ export async function runTui(opts: TuiOptions) {
},
set vimEnabled(value) {
vimEnabled = value ?? false;
if (vimEnabled) {
vimHandler.enable();
} else {
vimHandler.disable();
}
updateFooter();
},
get permissionMode() {
return permissionMode;
Expand Down Expand Up @@ -560,14 +552,10 @@ export async function runTui(opts: TuiOptions) {
const chatLog = new ChatLog();
const editor = new CustomEditor(tui, editorTheme);
editor.tuiResolver = tuiResolver;
editor.vimHandler = vimHandler;
editor.captureClipboardImage = captureClipboardImage;
editor.onImagePaste = (img) => {
pendingImages.set(img.marker, { base64: img.base64, mimeType: img.mimeType });
};
if (vimEnabled) {
vimHandler.enable();
}

// Mouse scroll → ChatLog scroll + re-render
mouseHandler.onScroll((direction, lines) => {
Expand Down Expand Up @@ -818,7 +806,6 @@ export async function runTui(opts: TuiOptions) {
const reasoning = sessionInfo.reasoningLevel ?? "off";
const reasoningLabel =
reasoning === "on" ? "reasoning" : reasoning === "stream" ? "reasoning:stream" : null;
const vimLabel = vimEnabled ? vimHandler.getModeIndicator() : null;
const permLabel = permissionMode !== "auto" ? `perm ${permissionMode}` : null;
const fastLabel = fastMode ? "FAST" : null;
const footerParts = [
Expand All @@ -829,7 +816,6 @@ export async function runTui(opts: TuiOptions) {
verbose !== "off" ? `verbose ${verbose}` : null,
reasoningLabel,
tokens,
vimLabel,
permLabel,
fastLabel,
].filter(Boolean);
Expand Down
Loading
Loading