From 24c722454bd232f7de02fc4575f22939caf2a7da Mon Sep 17 00:00:00 2001 From: Jack Wotherspoon Date: Mon, 22 Dec 2025 17:44:41 -0500 Subject: [PATCH] chore: improve error messages for --resume (#15360) --- packages/cli/src/utils/sessionUtils.test.ts | 5 +- packages/cli/src/utils/sessionUtils.ts | 55 ++++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/utils/sessionUtils.test.ts b/packages/cli/src/utils/sessionUtils.test.ts index 0bd2ebb651..29fc5bdff9 100644 --- a/packages/cli/src/utils/sessionUtils.test.ts +++ b/packages/cli/src/utils/sessionUtils.test.ts @@ -10,6 +10,7 @@ import { extractFirstUserMessage, formatRelativeTime, hasUserOrAssistantMessage, + SessionError, } from './sessionUtils.js'; import type { Config, MessageRecord } from '@google/gemini-cli-core'; import { SESSION_FILE_PREFIX } from '@google/gemini-cli-core'; @@ -333,10 +334,10 @@ describe('SessionSelector', () => { await expect( sessionSelector.resolveSession('invalid-uuid'), - ).rejects.toThrow('Invalid session identifier "invalid-uuid"'); + ).rejects.toThrow(SessionError); await expect(sessionSelector.resolveSession('999')).rejects.toThrow( - 'Invalid session identifier "999"', + SessionError, ); }); diff --git a/packages/cli/src/utils/sessionUtils.ts b/packages/cli/src/utils/sessionUtils.ts index ab65847137..1d7be693b8 100644 --- a/packages/cli/src/utils/sessionUtils.ts +++ b/packages/cli/src/utils/sessionUtils.ts @@ -23,6 +23,47 @@ import { stripUnsafeCharacters } from '../ui/utils/textUtils.js'; */ export const RESUME_LATEST = 'latest'; +/** + * Error codes for session-related errors. + */ +export type SessionErrorCode = + | 'NO_SESSIONS_FOUND' + | 'INVALID_SESSION_IDENTIFIER'; + +/** + * Error thrown for session-related failures. + * Uses a code field to differentiate between error types. + */ +export class SessionError extends Error { + constructor( + readonly code: SessionErrorCode, + message: string, + ) { + super(message); + this.name = 'SessionError'; + } + + /** + * Creates an error for when no sessions exist for the current project. + */ + static noSessionsFound(): SessionError { + return new SessionError( + 'NO_SESSIONS_FOUND', + 'No previous sessions found for this project.', + ); + } + + /** + * Creates an error for when a session identifier is invalid. + */ + static invalidSessionIdentifier(identifier: string): SessionError { + return new SessionError( + 'INVALID_SESSION_IDENTIFIER', + `Invalid session identifier "${identifier}".\n Use --list-sessions to see available sessions, then use --resume {number}, --resume {uuid}, or --resume latest.`, + ); + } +} + /** * Represents a text match found during search with surrounding context. */ @@ -370,7 +411,7 @@ export class SessionSelector { const sessions = await this.listSessions(); if (sessions.length === 0) { - throw new Error('No previous sessions found for this project.'); + throw SessionError.noSessionsFound(); } // Sort by startTime (oldest first, so newest sessions get highest numbers) @@ -398,9 +439,7 @@ export class SessionSelector { return sortedSessions[index - 1]; } - throw new Error( - `Invalid session identifier "${identifier}". Use --list-sessions to see available sessions.`, - ); + throw SessionError.invalidSessionIdentifier(identifier); } /** @@ -430,9 +469,13 @@ export class SessionSelector { try { selectedSession = await this.findSession(resumeArg); } catch (error) { - // Re-throw with more detailed message for resume command + // SessionError already has detailed messages - just rethrow + if (error instanceof SessionError) { + throw error; + } + // Wrap unexpected errors with context throw new Error( - `Invalid session identifier "${resumeArg}". Use --list-sessions to see available sessions, then use --resume {number}, --resume {uuid}, or --resume latest. Error: ${error}`, + `Failed to find session "${resumeArg}": ${error instanceof Error ? error.message : String(error)}`, ); } }