From b49c798fc7c822b468a2c3972e466ef2b4bde8f6 Mon Sep 17 00:00:00 2001 From: sebseb7 Date: Wed, 13 Aug 2025 01:57:11 +0000 Subject: [PATCH] Implement terminal restart functionality and enhance model settings menu in InkApp. Add methods for restarting the terminal and adjusting model settings, improving user interaction and menu navigation. Update state management for better handling of model settings adjustments. --- src/terminalService.js | 6 +++ src/ui/InkApp.jsx | 84 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/terminalService.js b/src/terminalService.js index bec595b..52e3b7b 100644 --- a/src/terminalService.js +++ b/src/terminalService.js @@ -118,10 +118,16 @@ class TerminalService extends EventEmitter { this.ptyProcess.kill(); this.ptyProcess = null; } + this.started = false; } catch { // ignore } } + + restart() { + try { this.dispose(); } catch {} + try { this.start(); } catch {} + } } const terminalService = new TerminalService(); diff --git a/src/ui/InkApp.jsx b/src/ui/InkApp.jsx index e402887..068aca3 100644 --- a/src/ui/InkApp.jsx +++ b/src/ui/InkApp.jsx @@ -124,6 +124,8 @@ export default class InkApp extends React.Component { this.toggleMenu = this.toggleMenu.bind(this); this.onKeypress = this.onKeypress.bind(this); this.menuAction = this.menuAction.bind(this); + this.getModelSettingsItems = this.getModelSettingsItems.bind(this); + this.handleModelSettingAdjust = this.handleModelSettingAdjust.bind(this); } componentDidMount() { @@ -230,6 +232,8 @@ export default class InkApp extends React.Component { const isUp = data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41; const isDown = data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42; const isEnter = data.length === 1 && data[0] === 0x0d; + const isLeft = data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x44; + const isRight = data.length >= 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x43; const isCtrlC = data.length === 1 && data[0] === 0x03; if (!this.state.menuOpen) { @@ -245,7 +249,32 @@ export default class InkApp extends React.Component { return; } - // Menu navigation + // Submenu: Model settings adjustments + if (this.state.menuOpen && this.state.menuMode === 'model') { + const items = this.getModelSettingsItems(); + if (isUp) { + this.setState((s) => ({ menuIndex: (s.menuIndex - 1 + items.length) % items.length })); + return; + } + if (isDown) { + this.setState((s) => ({ menuIndex: (s.menuIndex + 1) % items.length })); + return; + } + if (isLeft || isRight) { + const idx = this.state.menuIndex; + const dir = isRight ? 1 : -1; + this.handleModelSettingAdjust(items[idx].key, dir); + return; + } + if (isEnter) { + // Enter exits model submenu back to main menu + this.setState({ menuMode: undefined, menuIndex: 0 }); + return; + } + return; + } + + // Menu navigation (main menu) const items = this.getMenuItems(); if (isUp) { this.setState((s) => ({ menuIndex: (s.menuIndex - 1 + items.length) % items.length })); @@ -278,12 +307,11 @@ export default class InkApp extends React.Component { try { terminalService.write('\x03'); } catch {} break; case 'Restart Terminal': - try { terminalService.dispose(); } catch {} - try { terminalService.start(); } catch {} + try { terminalService.restart(); } catch {} break; case 'Model settings': // Toggle a sub-menu state - this.setState({ menuMode: 'model' }); + this.setState({ menuMode: 'model', menuIndex: 0 }); break; case 'Exit the app': try { process.exit(0); } catch {} @@ -296,6 +324,30 @@ export default class InkApp extends React.Component { } } + getModelSettingsItems() { + return [ + { key: 'model', label: 'Model', options: ['gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano'] }, + { key: 'reasoningEffort', label: 'Reasoning effort', options: ['minimal', 'low', 'medium', 'high'] }, + { key: 'outputVerbosity', label: 'Output verbosity', options: ['low', 'medium', 'high'] }, + { key: 'back', label: 'Back to main menu' } + ]; + } + + handleModelSettingAdjust(key, dir) { + if (key === 'back') { + this.setState({ menuMode: undefined, menuIndex: 0 }); + return; + } + const items = this.getModelSettingsItems(); + const item = items.find((i) => i.key === key); + if (!item || !item.options) return; + const currentValue = this.state[key]; + const idx = item.options.indexOf(currentValue); + const nextIdx = ((idx === -1 ? 0 : idx) + dir + item.options.length) % item.options.length; + const nextValue = item.options[nextIdx]; + this.setState({ [key]: nextValue }); + } + render() { const { input, logs, terminal, chainOfThought, llmOutput } = this.state; const totalCols = (process && process.stdout && process.stdout.columns) ? process.stdout.columns : 80; @@ -337,7 +389,7 @@ export default class InkApp extends React.Component { - {this.state.menuOpen && ( + {this.state.menuOpen && this.state.menuMode !== 'model' && ( Main Menu (Up/Down to navigate, Enter to select) {menuItems.map((label, i) => ( @@ -345,17 +397,17 @@ export default class InkApp extends React.Component { {i === selected ? '› ' : ' '}{label} ))} - {this.state.menuMode === 'model' && ( - - Model: {this.state.model} - Reasoning effort: {this.state.reasoningEffort} - Output verbosity: {this.state.outputVerbosity} - - (Adjustments pending wiring: model list [gpt-5, gpt-5-mini, gpt-5-nano, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano], - reasoning effort [minimal, low, medium, high], output verbosity [low, medium, high]) - - - )} + + )} + {this.state.menuOpen && this.state.menuMode === 'model' && ( + + Model Settings (Up/Down select, Left/Right change, Enter back) + {this.getModelSettingsItems().map((item, i) => ( + + {i === selected ? '› ' : ' '} + {item.label}{item.options ? `: ${this.state[item.key]}` : ''} + + ))} )}