From fbb46a63e4dbdfcf5dfa99708e6d70069726dca9 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 12 Aug 2026 18:42:08 -0700 Subject: [PATCH] fix(ai-vault): tolerate unavailable Cursor CLI in session rows --- .../src/lib/ai-vault-cursor-command.test.ts | 25 ++++++++++++++++++- .../src/lib/ai-vault-cursor-command.ts | 7 ++---- .../src/lib/ai-vault-resume-command.test.ts | 20 +++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/lib/ai-vault-cursor-command.test.ts b/src/renderer/src/lib/ai-vault-cursor-command.test.ts index 7943e5991fe..cbac9add5a1 100644 --- a/src/renderer/src/lib/ai-vault-cursor-command.test.ts +++ b/src/renderer/src/lib/ai-vault-cursor-command.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it } from 'vitest' import type { AppState } from '@/store/types' -import { resolveAiVaultCursorCommand } from './ai-vault-cursor-command' +import { + resolveAiVaultCursorCommand, + resolveAiVaultResumeCommandOverride +} from './ai-vault-cursor-command' function state( overrides: Partial< @@ -100,3 +103,23 @@ describe('resolveAiVaultCursorCommand', () => { ).toBe('cursor-dev') }) }) + +describe('resolveAiVaultResumeCommandOverride', () => { + it('leaves incomplete Cursor sessions inert while their resume controls are disabled', () => { + const source = state() + + expect( + resolveAiVaultResumeCommandOverride({ + state: source, + session: { agent: 'cursor', cwd: '/work/demo-project' } + }) + ).toBeUndefined() + expect( + resolveAiVaultResumeCommandOverride({ + state: source, + session: { agent: 'cursor', cwd: null }, + commandOverride: 'cursor-agent' + }) + ).toBeUndefined() + }) +}) diff --git a/src/renderer/src/lib/ai-vault-cursor-command.ts b/src/renderer/src/lib/ai-vault-cursor-command.ts index 4ee6aa19334..bf15babb4d6 100644 --- a/src/renderer/src/lib/ai-vault-cursor-command.ts +++ b/src/renderer/src/lib/ai-vault-cursor-command.ts @@ -125,11 +125,8 @@ export function resolveAiVaultResumeCommandOverride(args: { } const command = resolveAiVaultCursorCommand(args) if (!args.session.cwd || !command?.trim()) { - throw new Error( - args.session.cwd - ? 'Cursor CLI not detected on this host.' - : 'Cursor did not record a resumable workspace for this session.' - ) + // Resume controls gate these incomplete sessions; row rendering still builds an inert startup. + return undefined } return command } diff --git a/src/renderer/src/lib/ai-vault-resume-command.test.ts b/src/renderer/src/lib/ai-vault-resume-command.test.ts index bb51836e0f8..9cf247d3231 100644 --- a/src/renderer/src/lib/ai-vault-resume-command.test.ts +++ b/src/renderer/src/lib/ai-vault-resume-command.test.ts @@ -151,6 +151,26 @@ describe('ai vault resume command runtime', () => { ) }) + it('builds disabled Cursor row startup data when the CLI is unavailable', () => { + const state = makeState({ worktreePath: '/work/demo-project' }) + state.repos = [{ id: 'repo-1', path: '/work/demo-project', connectionId: 'ssh-1' }] as never + + expect( + buildAiVaultResumeStartupForWorktree({ + state, + worktreeId: 'repo-1::worktree-1', + session: { + agent: 'cursor', + sessionId: 'session one', + cwd: '/work/demo-project', + codexHome: null, + executionHostId: 'ssh:ssh-1', + executionHostPlatform: 'linux' + } + }) + ).toEqual({ command: "cd '/work/demo-project' && cursor-agent --resume 'session one'" }) + }) + it('queues a PowerShell-valid local OMP resume by absolute transcript path', () => { // Regression: local rebuilds must forward session.filePath so OMP resumes by // path, and queued Windows commands must match the live tab shell.