import type { CursorConfig } from '../config/unified-config-types'; import { checkAuthStatus } from './cursor-auth'; import { isDaemonRunning, startDaemon } from './cursor-daemon'; import { getModelsForDaemon, resolveCursorRequestModel } from './cursor-models'; export interface CursorProbeResult { ok: boolean; stage: 'config' | 'auth' | 'daemon' | 'runtime'; status: number; duration_ms: number; model?: string; error_type?: string | null; message: string; } const PROBE_PROMPT = 'Reply with OK only.'; const PROBE_TIMEOUT_MS = 15_000; const PROBE_SUCCESS_PATTERN = /^ok[.!]?$/i; function isDaemonReachabilityError(error: unknown): boolean { if (!(error instanceof Error)) return false; const message = error.message.toLowerCase(); if ( message.includes('fetch failed') || message.includes('econnrefused') || message.includes('econnreset') || message.includes('socket hang up') || message.includes('connection refused') ) { return true; } const cause = (error as Error & { cause?: unknown }).cause; if (!cause || typeof cause !== 'object' || !('code' in cause)) { return false; } const code = String((cause as { code?: unknown }).code ?? '').toUpperCase(); return ['ECONNREFUSED', 'ECONNRESET', 'ECONNABORTED', 'EPIPE', 'UND_ERR_SOCKET'].includes(code); } function parseProbeError(text: string): { errorType: string | null; message: string } { try { const parsed = JSON.parse(text) as { error?: { type?: string; message?: string }; type?: string; }; if (parsed.error?.message) { return { errorType: parsed.error.type ?? null, message: parsed.error.message, }; } if (parsed.type === 'error') { return { errorType: null, message: text, }; } } catch { // fall through to raw text } return { errorType: null, message: text || 'Unknown probe failure', }; } function parseProbeSuccess(text: string): { ok: boolean; message: string } { try { const parsed = JSON.parse(text) as { choices?: Array<{ message?: { content?: string | null }; }>; error?: { message?: string }; }; if (parsed.error?.message) { return { ok: false, message: parsed.error.message }; } const content = parsed.choices?.[0]?.message?.content; if (typeof content !== 'string' || !content.trim()) { return { ok: false, message: 'Probe response was missing assistant content.' }; } return { ok: PROBE_SUCCESS_PATTERN.test(content.trim()), message: PROBE_SUCCESS_PATTERN.test(content.trim()) ? 'Live probe succeeded.' : `Probe returned unexpected assistant content: ${content.trim()}`, }; } catch { return { ok: false, message: 'Probe response was not valid JSON.' }; } } export async function probeCursorRuntime(config: CursorConfig): Promise { const startedAt = Date.now(); if (!config.enabled) { return { ok: false, stage: 'config', status: 400, duration_ms: Date.now() - startedAt, message: 'Cursor integration is disabled.', error_type: 'configuration_error', }; } const authStatus = checkAuthStatus(); if (!authStatus.authenticated || !authStatus.credentials) { return { ok: false, stage: 'auth', status: 401, duration_ms: Date.now() - startedAt, message: 'Cursor credentials not found. Run `ccs legacy cursor auth` first.', error_type: 'authentication_error', }; } if (authStatus.expired) { return { ok: false, stage: 'auth', status: 401, duration_ms: Date.now() - startedAt, message: 'Cursor credentials expired. Run `ccs legacy cursor auth` again.', error_type: 'authentication_error', }; } let daemonRunning = await isDaemonRunning(config.port); if (!daemonRunning && config.auto_start) { const startResult = await startDaemon({ port: config.port, ghost_mode: config.ghost_mode, }); if (!startResult.success) { daemonRunning = await isDaemonRunning(config.port); } else { daemonRunning = true; } if (!daemonRunning) { return { ok: false, stage: 'daemon', status: 503, duration_ms: Date.now() - startedAt, message: startResult.error || 'Failed to start Cursor daemon for live probe.', error_type: 'daemon_start_failed', }; } } if (!daemonRunning) { return { ok: false, stage: 'daemon', status: 503, duration_ms: Date.now() - startedAt, message: 'Cursor daemon is not running. Start it with `ccs legacy cursor start` or enable auto_start.', error_type: 'daemon_not_running', }; } try { const credentials = { accessToken: authStatus.credentials.accessToken, machineId: authStatus.credentials.machineId, ghostMode: config.ghost_mode, }; const availableModels = await getModelsForDaemon({ credentials }); const model = resolveCursorRequestModel(config.model, availableModels); const abortController = new AbortController(); const timeout = setTimeout(() => abortController.abort(), PROBE_TIMEOUT_MS); try { const response = await fetch(`http://127.0.0.1:${config.port}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, max_tokens: 8, messages: [{ role: 'user', content: PROBE_PROMPT }], }), signal: abortController.signal, }); const text = await response.text(); const duration = Date.now() - startedAt; if (!response.ok) { const error = parseProbeError(text); return { ok: false, stage: 'runtime', status: response.status, duration_ms: duration, model, error_type: error.errorType, message: error.message, }; } const success = parseProbeSuccess(text); return { ok: success.ok, stage: 'runtime', status: success.ok ? response.status : 502, duration_ms: duration, model, error_type: success.ok ? null : 'probe_validation_failed', message: success.message, }; } finally { clearTimeout(timeout); } } catch (error) { const daemonReachabilityError = isDaemonReachabilityError(error); return { ok: false, stage: error instanceof Error && error.name === 'AbortError' ? 'runtime' : daemonReachabilityError ? 'daemon' : 'runtime', status: error instanceof Error && error.name === 'AbortError' ? 504 : daemonReachabilityError ? 503 : 500, duration_ms: Date.now() - startedAt, error_type: error instanceof Error && error.name === 'AbortError' ? 'probe_timeout' : daemonReachabilityError ? 'daemon_unreachable' : 'runtime_error', message: error instanceof Error && error.name === 'AbortError' ? `Live probe timed out after ${PROBE_TIMEOUT_MS}ms.` : daemonReachabilityError ? 'Cursor daemon became unreachable during the live probe. Start it again and retry.' : error instanceof Error ? error.message : 'Unknown runtime probe failure.', }; } }