From 0df48f6b337512c7e50e8d1c2d86339cb671b75c Mon Sep 17 00:00:00 2001 From: Tino Ehrich Date: Wed, 19 Nov 2025 10:38:10 +0100 Subject: [PATCH] feat: add visual thinking level indicator via border colors The horizontal borders around the input editor now change color based on the current thinking level, providing immediate visual feedback: - off: gray (default) - minimal: dim blue - low: blue - medium: cyan - high: magenta The more thinking, the brighter/more vibrant the color. Changes: - Add public borderColor property to Editor component (packages/tui) - Use borderColor instead of hardcoded chalk.gray for borders - Add getThinkingBorderColor() helper in TuiRenderer - Add updateEditorBorderColor() to apply color changes - Update border color when: - Cycling with Tab key - Selecting via /thinking command - Restoring session with thinking level set --- packages/coding-agent/src/tui/tui-renderer.ts | 34 +++++++++++++++++++ packages/tui/src/components/editor.ts | 5 ++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/coding-agent/src/tui/tui-renderer.ts b/packages/coding-agent/src/tui/tui-renderer.ts index 2b64cdd7..8dbdbfb1 100644 --- a/packages/coding-agent/src/tui/tui-renderer.ts +++ b/packages/coding-agent/src/tui/tui-renderer.ts @@ -491,6 +491,9 @@ export class TuiRenderer { // Update footer with loaded state this.footer.updateState(state); + // Update editor border color based on current thinking level + this.updateEditorBorderColor(); + // Render messages for (let i = 0; i < state.messages.length; i++) { const message = state.messages[i]; @@ -579,6 +582,31 @@ export class TuiRenderer { } } + private getThinkingBorderColor(level: ThinkingLevel): (str: string) => string { + // More thinking = more color (gray → dim colors → bright colors) + switch (level) { + case "off": + return chalk.gray; + case "minimal": + return chalk.dim.blue; + case "low": + return chalk.blue; + case "medium": + return chalk.cyan; + case "high": + return chalk.magenta; + default: + return chalk.gray; + } + } + + private updateEditorBorderColor(): void { + const level = this.agent.state.thinkingLevel || "off"; + const color = this.getThinkingBorderColor(level); + this.editor.borderColor = color; + this.ui.requestRender(); + } + private cycleThinkingLevel(): boolean { // Only cycle if model supports thinking if (!this.agent.state.model?.reasoning) { @@ -597,6 +625,9 @@ export class TuiRenderer { // Save thinking level change to session this.sessionManager.saveThinkingLevelChange(nextLevel); + // Update border color + this.updateEditorBorderColor(); + // Show brief notification this.chatContainer.addChild(new Spacer(1)); this.chatContainer.addChild(new Text(chalk.dim(`Thinking level: ${nextLevel}`), 1, 0)); @@ -635,6 +666,9 @@ export class TuiRenderer { // Save thinking level change to session this.sessionManager.saveThinkingLevelChange(level); + // Update border color + this.updateEditorBorderColor(); + // Show confirmation message with proper spacing this.chatContainer.addChild(new Spacer(1)); const confirmText = new Text(chalk.dim(`Thinking level: ${level}`), 1, 0); diff --git a/packages/tui/src/components/editor.ts b/packages/tui/src/components/editor.ts index 4374775d..6195e404 100644 --- a/packages/tui/src/components/editor.ts +++ b/packages/tui/src/components/editor.ts @@ -28,6 +28,9 @@ export class Editor implements Component { private config: TextEditorConfig = {}; + // Border color (can be changed dynamically) + public borderColor: (str: string) => string = chalk.gray; + // Autocomplete support private autocompleteProvider?: AutocompleteProvider; private autocompleteList?: SelectList; @@ -61,7 +64,7 @@ export class Editor implements Component { } render(width: number): string[] { - const horizontal = chalk.gray("─"); + const horizontal = this.borderColor("─"); // Layout the text - use full width const layoutLines = this.layoutText(width);