diff --git a/libs/types/src/cursor-cli.ts b/libs/types/src/cursor-cli.ts new file mode 100644 index 00000000..a936c735 --- /dev/null +++ b/libs/types/src/cursor-cli.ts @@ -0,0 +1,114 @@ +import type { CursorModelId } from './cursor-models.js'; + +/** + * Cursor CLI configuration file schema + * Stored in: .automaker/cursor-config.json + */ +export interface CursorCliConfig { + defaultModel?: CursorModelId; + models?: CursorModelId[]; // Enabled models + mcpServers?: string[]; // MCP server configs to load + rules?: string[]; // .cursor/rules paths +} + +/** + * Cursor authentication status + */ +export interface CursorAuthStatus { + authenticated: boolean; + method: 'login' | 'api_key' | 'none'; + hasCredentialsFile?: boolean; +} + +/** + * NOTE: Reuse existing InstallationStatus from provider.ts + * The existing type already has: installed, path, version, method, hasApiKey, authenticated + * + * Add 'login' to the method union if needed: + * method?: 'cli' | 'npm' | 'brew' | 'sdk' | 'login'; + */ + +/** + * Cursor stream-json event types (from CLI output) + */ +export interface CursorSystemEvent { + type: 'system'; + subtype: 'init'; + apiKeySource: 'env' | 'flag' | 'login'; + cwd: string; + session_id: string; + model: string; + permissionMode: string; +} + +export interface CursorUserEvent { + type: 'user'; + message: { + role: 'user'; + content: Array<{ type: 'text'; text: string }>; + }; + session_id: string; +} + +export interface CursorAssistantEvent { + type: 'assistant'; + message: { + role: 'assistant'; + content: Array<{ type: 'text'; text: string }>; + }; + session_id: string; +} + +export interface CursorToolCallEvent { + type: 'tool_call'; + subtype: 'started' | 'completed'; + call_id: string; + tool_call: { + readToolCall?: { + args: { path: string }; + result?: { + success?: { + content: string; + isEmpty: boolean; + exceededLimit: boolean; + totalLines: number; + totalChars: number; + }; + }; + }; + writeToolCall?: { + args: { path: string; fileText: string; toolCallId?: string }; + result?: { + success?: { + path: string; + linesCreated: number; + fileSize: number; + }; + }; + }; + function?: { + name: string; + arguments: string; + }; + }; + session_id: string; +} + +export interface CursorResultEvent { + type: 'result'; + subtype: 'success' | 'error'; + duration_ms: number; + duration_api_ms: number; + is_error: boolean; + result: string; + session_id: string; + request_id?: string; + error?: string; +} + +export type CursorStreamEvent = + | CursorSystemEvent + | CursorUserEvent + | CursorAssistantEvent + | CursorToolCallEvent + | CursorResultEvent; diff --git a/libs/types/src/cursor-models.ts b/libs/types/src/cursor-models.ts new file mode 100644 index 00000000..861796d4 --- /dev/null +++ b/libs/types/src/cursor-models.ts @@ -0,0 +1,99 @@ +/** + * Cursor CLI Model IDs + * Reference: https://cursor.com/docs + */ +export type CursorModelId = + | 'auto' // Auto-select best model + | 'claude-sonnet-4' // Claude Sonnet 4 + | 'claude-sonnet-4-thinking' // Claude Sonnet 4 with extended thinking + | 'gpt-4o' // GPT-4o + | 'gpt-4o-mini' // GPT-4o Mini + | 'gemini-2.5-pro' // Gemini 2.5 Pro + | 'o3-mini'; // O3 Mini + +/** + * Cursor model metadata + */ +export interface CursorModelConfig { + id: CursorModelId; + label: string; + description: string; + hasThinking: boolean; + tier: 'free' | 'pro'; +} + +/** + * Complete model map for Cursor CLI + */ +export const CURSOR_MODEL_MAP: Record = { + auto: { + id: 'auto', + label: 'Auto (Recommended)', + description: 'Automatically selects the best model for each task', + hasThinking: false, + tier: 'free', + }, + 'claude-sonnet-4': { + id: 'claude-sonnet-4', + label: 'Claude Sonnet 4', + description: 'Anthropic Claude Sonnet 4 via Cursor', + hasThinking: false, + tier: 'pro', + }, + 'claude-sonnet-4-thinking': { + id: 'claude-sonnet-4-thinking', + label: 'Claude Sonnet 4 (Thinking)', + description: 'Claude Sonnet 4 with extended thinking enabled', + hasThinking: true, + tier: 'pro', + }, + 'gpt-4o': { + id: 'gpt-4o', + label: 'GPT-4o', + description: 'OpenAI GPT-4o via Cursor', + hasThinking: false, + tier: 'pro', + }, + 'gpt-4o-mini': { + id: 'gpt-4o-mini', + label: 'GPT-4o Mini', + description: 'OpenAI GPT-4o Mini (faster, cheaper)', + hasThinking: false, + tier: 'free', + }, + 'gemini-2.5-pro': { + id: 'gemini-2.5-pro', + label: 'Gemini 2.5 Pro', + description: 'Google Gemini 2.5 Pro via Cursor', + hasThinking: false, + tier: 'pro', + }, + 'o3-mini': { + id: 'o3-mini', + label: 'O3 Mini', + description: 'OpenAI O3 Mini reasoning model', + hasThinking: true, + tier: 'pro', + }, +}; + +/** + * Helper: Check if model has thinking capability + */ +export function cursorModelHasThinking(modelId: CursorModelId): boolean { + return CURSOR_MODEL_MAP[modelId]?.hasThinking ?? false; +} + +/** + * Helper: Get display name for model + */ +export function getCursorModelLabel(modelId: CursorModelId): string { + return CURSOR_MODEL_MAP[modelId]?.label ?? modelId; +} + +/** + * Helper: Get all cursor model IDs + */ +export function getAllCursorModelIds(): CursorModelId[] { + return Object.keys(CURSOR_MODEL_MAP) as CursorModelId[]; +} diff --git a/libs/types/src/index.ts b/libs/types/src/index.ts index 64962d2a..5c97dfbc 100644 --- a/libs/types/src/index.ts +++ b/libs/types/src/index.ts @@ -105,3 +105,7 @@ export type { BacklogPlanRequest, BacklogPlanApplyResult, } from './backlog-plan.js'; + +// Cursor types +export * from './cursor-models.js'; +export * from './cursor-cli.js'; diff --git a/libs/types/src/model-display.ts b/libs/types/src/model-display.ts index e7604fd1..92b63686 100644 --- a/libs/types/src/model-display.ts +++ b/libs/types/src/model-display.ts @@ -5,22 +5,23 @@ * and thinking levels used throughout the application UI. */ -import type { AgentModel, ThinkingLevel } from './settings.js'; +import type { AgentModel, ThinkingLevel, ModelProvider } from './settings.js'; +import type { CursorModelId } from './cursor-models.js'; /** * ModelOption - Display metadata for a model option in the UI */ export interface ModelOption { - /** Model identifier */ - id: AgentModel; + /** Model identifier (supports both Claude and Cursor models) */ + id: AgentModel | CursorModelId; /** Display name shown to user */ label: string; /** Descriptive text explaining model capabilities */ description: string; /** Optional badge text (e.g., "Speed", "Balanced", "Premium") */ badge?: string; - /** AI provider (currently only "claude") */ - provider: 'claude'; + /** AI provider (supports 'claude' and 'cursor') */ + provider: ModelProvider; } /** diff --git a/libs/types/src/model.ts b/libs/types/src/model.ts index ab186baf..27ea3b75 100644 --- a/libs/types/src/model.ts +++ b/libs/types/src/model.ts @@ -12,6 +12,7 @@ export const CLAUDE_MODEL_MAP: Record = { */ export const DEFAULT_MODELS = { claude: 'claude-opus-4-5-20251101', + cursor: 'auto', // Cursor's recommended default } as const; export type ModelAlias = keyof typeof CLAUDE_MODEL_MAP; diff --git a/libs/types/src/settings.ts b/libs/types/src/settings.ts index e73e7269..40d1e04a 100644 --- a/libs/types/src/settings.ts +++ b/libs/types/src/settings.ts @@ -68,7 +68,7 @@ export type PlanningMode = 'skip' | 'lite' | 'spec' | 'full'; export type ThinkingLevel = 'none' | 'low' | 'medium' | 'high' | 'ultrathink'; /** ModelProvider - AI model provider for credentials and API key management */ -export type ModelProvider = 'claude'; +export type ModelProvider = 'claude' | 'cursor'; /** * WindowBounds - Electron window position and size for persistence diff --git a/plan/cursor-cli-integration/README.md b/plan/cursor-cli-integration/README.md index 0ca19185..f352f592 100644 --- a/plan/cursor-cli-integration/README.md +++ b/plan/cursor-cli-integration/README.md @@ -4,19 +4,19 @@ ## Status Overview -| Phase | Name | Status | Test Status | -| ----- | ------------------------------------------------------------ | --------- | ----------- | -| 0 | [Analysis & Documentation](phases/phase-0-analysis.md) | `pending` | - | -| 1 | [Core Types & Configuration](phases/phase-1-types.md) | `pending` | - | -| 2 | [Cursor Provider Implementation](phases/phase-2-provider.md) | `pending` | - | -| 3 | [Provider Factory Integration](phases/phase-3-factory.md) | `pending` | - | -| 4 | [Setup Routes & Status Endpoints](phases/phase-4-routes.md) | `pending` | - | -| 5 | [Log Parser Integration](phases/phase-5-log-parser.md) | `pending` | - | -| 6 | [UI Setup Wizard](phases/phase-6-setup-wizard.md) | `pending` | - | -| 7 | [Settings View Provider Tabs](phases/phase-7-settings.md) | `pending` | - | -| 8 | [AI Profiles Integration](phases/phase-8-profiles.md) | `pending` | - | -| 9 | [Task Execution Integration](phases/phase-9-execution.md) | `pending` | - | -| 10 | [Testing & Validation](phases/phase-10-testing.md) | `pending` | - | +| Phase | Name | Status | Test Status | +| ----- | ------------------------------------------------------------ | ----------- | ----------- | +| 0 | [Analysis & Documentation](phases/phase-0-analysis.md) | `completed` | ✅ | +| 1 | [Core Types & Configuration](phases/phase-1-types.md) | `completed` | ✅ | +| 2 | [Cursor Provider Implementation](phases/phase-2-provider.md) | `pending` | - | +| 3 | [Provider Factory Integration](phases/phase-3-factory.md) | `pending` | - | +| 4 | [Setup Routes & Status Endpoints](phases/phase-4-routes.md) | `pending` | - | +| 5 | [Log Parser Integration](phases/phase-5-log-parser.md) | `pending` | - | +| 6 | [UI Setup Wizard](phases/phase-6-setup-wizard.md) | `pending` | - | +| 7 | [Settings View Provider Tabs](phases/phase-7-settings.md) | `pending` | - | +| 8 | [AI Profiles Integration](phases/phase-8-profiles.md) | `pending` | - | +| 9 | [Task Execution Integration](phases/phase-9-execution.md) | `pending` | - | +| 10 | [Testing & Validation](phases/phase-10-testing.md) | `pending` | - | **Status Legend:** `pending` | `in_progress` | `completed` | `blocked` diff --git a/plan/cursor-cli-integration/phases/phase-1-types.md b/plan/cursor-cli-integration/phases/phase-1-types.md index d3b1cc6a..d0daff96 100644 --- a/plan/cursor-cli-integration/phases/phase-1-types.md +++ b/plan/cursor-cli-integration/phases/phase-1-types.md @@ -1,6 +1,6 @@ # Phase 1: Core Types & Configuration -**Status:** `pending` +**Status:** `completed` **Dependencies:** Phase 0 (Analysis) **Estimated Effort:** Small (type definitions only) @@ -16,7 +16,7 @@ Define all Cursor-specific types and extend existing types to support the new pr ### Task 1.1: Create Cursor Model Definitions -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/cursor-models.ts` @@ -124,7 +124,7 @@ export function getAllCursorModelIds(): CursorModelId[] { ### Task 1.2: Create Cursor CLI Types -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/cursor-cli.ts` @@ -247,7 +247,7 @@ export type CursorStreamEvent = ### Task 1.3: Extend ModelProvider Type -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/settings.ts` @@ -263,7 +263,7 @@ export type ModelProvider = 'claude' | 'cursor'; ### Task 1.4: Add Cursor Profile Config Type -**Status:** `pending` +**Status:** `skipped` (not needed - thinking is embedded in model ID) **File:** `libs/types/src/settings.ts` @@ -282,7 +282,7 @@ export interface CursorProfileConfig { ### Task 1.5: Update ModelOption Interface -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/model-display.ts` @@ -312,7 +312,7 @@ export interface ModelOption { ### Task 1.6: Extend DEFAULT_MODELS -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/model.ts` @@ -333,7 +333,7 @@ export const DEFAULT_MODELS = { ### Task 1.7: Update Type Exports -**Status:** `pending` +**Status:** `completed` **File:** `libs/types/src/index.ts`