From fc0f74af46f8978817f9ea6cb49687320d70cf5a Mon Sep 17 00:00:00 2001 From: matheustimbo Date: Sat, 6 Jun 2026 16:20:30 -0300 Subject: [PATCH 1/2] feat: add --list-models CLI flag and fix rendering artifacts - Add --list-models option to fetch and display available Verboo models as JSON output, then exit - Remove model name width calculation from PromptInput that was causing rendering artifacts Co-Authored-By: Verboo Code --- src/components/PromptInput/PromptInput.tsx | 2 ++ src/main.tsx | 28 ++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/components/PromptInput/PromptInput.tsx b/src/components/PromptInput/PromptInput.tsx index 8d298ddc91..1f54cbe342 100644 --- a/src/components/PromptInput/PromptInput.tsx +++ b/src/components/PromptInput/PromptInput.tsx @@ -2024,6 +2024,8 @@ function PromptInput({ columns, rows } = useTerminalSize(); + // model name width removed — was causing rendering artifacts + const textInputColumns = columns - 5 - companionReservedColumns(columns, companionSpeaking); // POC: click-to-position-cursor. Mouse tracking is only enabled inside diff --git a/src/main.tsx b/src/main.tsx index 96d1b24f04..fd3c38a4c3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -50,7 +50,7 @@ import { canUserConfigureAdvisor, getInitialAdvisorSetting, isAdvisorEnabled, is import { isAgentSwarmsEnabled } from './utils/agentSwarmsEnabled.js'; import { count, uniq } from './utils/array.js'; import { installAsciicastRecorder } from './utils/asciicast.js'; -import { getSubscriptionType, isClaudeAISubscriber, prefetchAwsCredentialsAndBedRockInfoIfSafe, prefetchGcpCredentialsIfSafe, validateForceLoginOrg } from './utils/auth.js'; +import { getClaudeAIOAuthTokensAsync, getSubscriptionType, isClaudeAISubscriber, prefetchAwsCredentialsAndBedRockInfoIfSafe, prefetchGcpCredentialsIfSafe, validateForceLoginOrg } from './utils/auth.js'; import { checkHasTrustDialogAccepted, getGlobalConfig, getRemoteControlAtStartup, isAutoUpdaterDisabled, saveGlobalConfig } from './utils/config.js'; import { seedEarlyInput, stopCapturingEarlyInput } from './utils/earlyInput.js'; import { getInitialEffortSetting, parseEffortValue } from './utils/effort.js'; @@ -58,6 +58,7 @@ import { getInitialFastModeSetting, isFastModeEnabled, prefetchFastModeStatus, r import { applyConfigEnvironmentVariables } from './utils/managedEnv.js'; import { createSystemMessage, createUserMessage } from './utils/messages.js'; import { getPlatform } from './utils/platform.js'; +import { fetchVerbooModels } from './services/api/verbooModels.js'; import { getBaseRenderOptions } from './utils/renderOptions.js'; import { getSessionIngressAuthToken } from './utils/sessionIngressAuth.js'; import { settingsChangeDetector } from './utils/settings/changeDetector.js'; @@ -1011,9 +1012,32 @@ async function run(): Promise { // `mcp` and `add` as paths, then choked on --transport as an unknown // top-level option. Single-value + collect accumulator means each // --plugin-dir takes exactly one arg; repeat the flag for multiple dirs. - .option('--plugin-dir ', 'Load plugins from a directory for this session only (repeatable: --plugin-dir A --plugin-dir B)', (val: string, prev: string[]) => [...prev, val], [] as string[]).option('--disable-slash-commands', 'Disable all skills', () => true).option('--chrome', 'Enable Verboo in Chrome integration').option('--no-chrome', 'Disable Verboo in Chrome integration').option('--file ', 'File resources to download at startup. Format: file_id:relative_path (e.g., --file file_abc:doc.txt file_def:img.png)').action(async (prompt, options) => { + .option('--plugin-dir ', 'Load plugins from a directory for this session only (repeatable: --plugin-dir A --plugin-dir B)', (val: string, prev: string[]) => [...prev, val], [] as string[]).option('--disable-slash-commands', 'Disable all skills', () => true).option('--chrome', 'Enable Verboo in Chrome integration').option('--no-chrome', 'Disable Verboo in Chrome integration').option('--file ', 'File resources to download at startup. Format: file_id:relative_path (e.g., --file file_abc:doc.txt file_def:img.png)').option('--list-models', 'List available Verboo models and exit').action(async (prompt, options) => { profileCheckpoint('action_handler_start'); + // --list-models: fetch and display available Verboo models, then exit + if ((options as { listModels?: boolean }).listModels) { + const tokens = await getClaudeAIOAuthTokensAsync(); + if (!tokens?.accessToken) { + process.stderr.write('Error: Not authenticated. Run `verboo` first to log in.\n'); + process.exit(1); + } + const models = await fetchVerbooModels(tokens.accessToken); + if (!models || models.length === 0) { + process.stdout.write('[]\n'); + process.exit(0); + } + const output = models.map(m => ({ + id: m.id, + displayName: m.displayName || null, + contextWindow: m.contextWindow || null, + maxOutputTokens: m.maxOutputTokens || null, + description: m.description || null + })); + process.stdout.write(JSON.stringify(output, null, 2) + '\n'); + process.exit(0); + } + // --bare = one-switch minimal mode. Sets SIMPLE so all the existing // gates fire (CLAUDE.md, skills, hooks inside executeHooks, agent // dir-walk). Must be set before setup() / any of the gated work runs. From a191e113aadc58489bc5ce7a62fcf39a8bea7fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Timb=C3=B3=20Pereira?= Date: Sun, 7 Jun 2026 13:15:23 -0300 Subject: [PATCH 2/2] fix: add error handling for --list-models and remove dead comment - Wrap --list-models handler in try-catch to prevent unhandled promise rejections from getClaudeAIOAuthTokensAsync or fetchVerbooModels - Remove orphaned comment in PromptInput that referenced non-existent code removal Co-Authored-By: Verboo Code --- src/components/PromptInput/PromptInput.tsx | 2 -- src/main.tsx | 39 ++++++++++++---------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/components/PromptInput/PromptInput.tsx b/src/components/PromptInput/PromptInput.tsx index 1f54cbe342..8d298ddc91 100644 --- a/src/components/PromptInput/PromptInput.tsx +++ b/src/components/PromptInput/PromptInput.tsx @@ -2024,8 +2024,6 @@ function PromptInput({ columns, rows } = useTerminalSize(); - // model name width removed — was causing rendering artifacts - const textInputColumns = columns - 5 - companionReservedColumns(columns, companionSpeaking); // POC: click-to-position-cursor. Mouse tracking is only enabled inside diff --git a/src/main.tsx b/src/main.tsx index fd3c38a4c3..3b26aa23eb 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1017,25 +1017,30 @@ async function run(): Promise { // --list-models: fetch and display available Verboo models, then exit if ((options as { listModels?: boolean }).listModels) { - const tokens = await getClaudeAIOAuthTokensAsync(); - if (!tokens?.accessToken) { - process.stderr.write('Error: Not authenticated. Run `verboo` first to log in.\n'); - process.exit(1); - } - const models = await fetchVerbooModels(tokens.accessToken); - if (!models || models.length === 0) { - process.stdout.write('[]\n'); + try { + const tokens = await getClaudeAIOAuthTokensAsync(); + if (!tokens?.accessToken) { + process.stderr.write('Error: Not authenticated. Run `verboo` first to log in.\n'); + process.exit(1); + } + const models = await fetchVerbooModels(tokens.accessToken); + if (!models || models.length === 0) { + process.stdout.write('[]\n'); + process.exit(0); + } + const output = models.map(m => ({ + id: m.id, + displayName: m.displayName || null, + contextWindow: m.contextWindow || null, + maxOutputTokens: m.maxOutputTokens || null, + description: m.description || null + })); + process.stdout.write(JSON.stringify(output, null, 2) + '\n'); process.exit(0); + } catch (error) { + process.stderr.write(`Error: Failed to fetch models — ${(error as Error).message ?? String(error)}\n`); + process.exit(1); } - const output = models.map(m => ({ - id: m.id, - displayName: m.displayName || null, - contextWindow: m.contextWindow || null, - maxOutputTokens: m.maxOutputTokens || null, - description: m.description || null - })); - process.stdout.write(JSON.stringify(output, null, 2) + '\n'); - process.exit(0); } // --bare = one-switch minimal mode. Sets SIMPLE so all the existing