Files
automaker/plan/cursor-cli-integration
Kacper 55bd9b0dc7 refactor(cursor): Move stream dedup logic to CursorProvider
Move Cursor-specific duplicate text handling from auto-mode-service.ts
into CursorProvider.deduplicateTextBlocks() for cleaner separation.

This handles:
- Duplicate consecutive text blocks (same text twice in a row)
- Final accumulated text block (contains ALL previous text)

Also update REFACTORING-ANALYSIS.md with SpawnStrategy types for
future CLI providers (wsl, npx, direct, cmd).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 00:35:39 +01:00
..

Cursor CLI Integration Plan

Integration of Cursor Agent CLI (cursor-agent) as an alternative AI provider in AutoMaker

Status Overview

Phase Name Status Test Status
0 Analysis & Documentation completed
1 Core Types & Configuration completed
2 Cursor Provider Implementation completed
3 Provider Factory Integration completed
4 Setup Routes & Status Endpoints completed
5 Log Parser Integration completed
6 UI Setup Wizard completed
7 Settings View Provider Tabs completed
8 AI Profiles Integration completed
9 Task Execution Integration completed
10 Testing & Validation pending -

Status Legend: pending | in_progress | completed | blocked



Architecture Summary

Existing Provider Pattern

AutoMaker uses an extensible provider architecture:

BaseProvider (abstract)
    ├── getName(): string
    ├── executeQuery(options): AsyncGenerator<ProviderMessage>
    ├── detectInstallation(): Promise<InstallationStatus>
    └── getAvailableModels(): ModelDefinition[]

ClaudeProvider extends BaseProvider
    └── Uses @anthropic-ai/claude-agent-sdk

ProviderFactory
    └── getProviderForModel(modelId) → routes to correct provider

Target Architecture

BaseProvider
    ├── ClaudeProvider (existing)
    └── CursorProvider (new)
            ├── Spawns cursor-agent CLI process
            ├── Uses --output-format stream-json
            └── Normalizes events to ProviderMessage format

Key Requirements

  1. Model Selection: Explicit model selection via config (not just "auto" mode)
  2. Authentication: Browser login (cursor-agent login) as primary method
  3. Setup Wizard: Optional CLI status check (skippable, configure later)
  4. AI Profiles: Separate Cursor profiles with embedded thinking mode (e.g., claude-sonnet-4-thinking)
  5. Settings View: Separate tabs/sections per provider
  6. Streaming: Full stream-json parsing with tool call events for log-viewer
  7. Error Handling: Detailed error mapping with recovery suggestions

Cursor CLI Reference

Installation

curl https://cursor.com/install -fsS | bash

Authentication Methods

  1. Browser Login (Recommended): cursor-agent login
  2. API Key: CURSOR_API_KEY environment variable

CLI Flags for Integration

cursor-agent \
  -p "prompt"                    # Print/non-interactive mode
  --model gpt-4o                 # Explicit model selection
  --output-format stream-json    # NDJSON streaming
  --stream-partial-output        # Real-time character streaming
  --force                        # Allow file modifications

Available Models (from Cursor docs)

Model ID Description Thinking
auto Auto-select best model -
claude-sonnet-4 Claude Sonnet 4 No
claude-sonnet-4-thinking Claude Sonnet 4 + Thinking Yes
gpt-4o GPT-4o No
gpt-4o-mini GPT-4o Mini No
gemini-2.5-pro Gemini 2.5 Pro No
o3-mini O3 Mini (reasoning) Built-in

Stream JSON Event Types

System Init

{
  "type": "system",
  "subtype": "init",
  "apiKeySource": "login",
  "cwd": "/path",
  "session_id": "uuid",
  "model": "Claude 4 Sonnet",
  "permissionMode": "default"
}

User Message

{
  "type": "user",
  "message": { "role": "user", "content": [{ "type": "text", "text": "prompt" }] },
  "session_id": "uuid"
}

Assistant Message

{
  "type": "assistant",
  "message": { "role": "assistant", "content": [{ "type": "text", "text": "response" }] },
  "session_id": "uuid"
}

Tool Call Started

{
  "type": "tool_call",
  "subtype": "started",
  "call_id": "id",
  "tool_call": { "readToolCall": { "args": { "path": "file.txt" } } },
  "session_id": "uuid"
}

Tool Call Completed

{
  "type": "tool_call",
  "subtype": "completed",
  "call_id": "id",
  "tool_call": {
    "readToolCall": {
      "args": { "path": "file.txt" },
      "result": { "success": { "content": "...", "totalLines": 54 } }
    }
  },
  "session_id": "uuid"
}

Result (Final)

{
  "type": "result",
  "subtype": "success",
  "duration_ms": 1234,
  "is_error": false,
  "result": "full text",
  "session_id": "uuid"
}

File Map

Files to Create

File Phase Description
libs/types/src/cursor-models.ts 1 Cursor model definitions
apps/server/src/providers/cursor-provider.ts 2 Main provider implementation
apps/server/src/providers/cursor-config-manager.ts 2 Config file management
apps/server/src/routes/setup/routes/cursor-status.ts 4 CLI status endpoint
apps/server/src/routes/setup/routes/cursor-config.ts 4 Config management endpoints
apps/ui/src/components/views/setup-view/steps/cursor-setup-step.tsx 6 Setup wizard step
apps/ui/src/components/views/settings-view/providers/cursor-settings-tab.tsx 7 Settings tab
apps/ui/src/components/views/settings-view/providers/provider-tabs.tsx 7 Tab container
apps/server/tests/unit/providers/cursor-provider.test.ts 10 Unit tests

Files to Modify

File Phase Changes
libs/types/src/index.ts 1 Export Cursor types
libs/types/src/settings.ts 1 Extend ModelProvider type
apps/server/src/providers/provider-factory.ts 3 Add Cursor routing
apps/server/src/routes/setup/index.ts 4 Register Cursor routes
apps/ui/src/lib/log-parser.ts 5 Add Cursor event normalization
apps/ui/src/components/views/setup-view.tsx 6 Add Cursor setup step
apps/ui/src/components/views/profiles-view/components/profile-form.tsx 8 Add Cursor provider fields
apps/server/src/services/agent-service.ts 9 Use ProviderFactory

Dependencies

Between Phases

Phase 0 ─────────────────────────────────────────────┐
    │                                                │
Phase 1 (Types) ─────────────────────────────────────┤
    │                                                │
Phase 2 (Provider) ──────────────────────────────────┤
    │                                                │
Phase 3 (Factory) ───────────────────────────────────┤
    │                                                │
    ├── Phase 4 (Routes) ────────────────────────────┤
    │       │                                        │
    │       ├── Phase 6 (Setup Wizard) ──────────────┤
    │       │                                        │
    │       └── Phase 7 (Settings View) ─────────────┤
    │                                                │
    ├── Phase 5 (Log Parser) ────────────────────────┤
    │                                                │
    └── Phase 8 (Profiles) ──────────────────────────┤
            │                                        │
            Phase 9 (Execution) ─────────────────────┤
                                                     │
                                    Phase 10 (Tests) ┘

External Dependencies

  • cursor-agent CLI must be installed for testing
  • Cursor account for authentication testing

Design Decisions

1. Use HttpApiClient for All API Requests

All UI components must use HttpApiClient from @/lib/http-api-client.ts instead of raw fetch():

// ✓ Correct - uses HttpApiClient
import { api } from '@/lib/http-api-client';
const result = await api.setup.getCursorStatus();

// ✗ Incorrect - raw fetch
const response = await fetch('/api/setup/cursor-status');

New Cursor API methods added to HttpApiClient.setup:

  • getCursorStatus() - Installation and auth status
  • getCursorConfig() - Configuration settings
  • setCursorDefaultModel(model) - Update default model
  • setCursorModels(models) - Update enabled models

2. Use Existing UI Components

All UI must use components from @/components/ui/*:

  • Card, CardHeader, CardTitle, CardContent - Layout
  • Button, Badge, Label - Controls
  • Select, SelectContent, SelectItem, SelectTrigger, SelectValue - Selection
  • Checkbox - Toggle inputs
  • Alert, AlertDescription - Messages
  • Tabs, TabsList, TabsTrigger, TabsContent - Navigation

Icons from lucide-react:

  • Terminal - Cursor provider
  • Bot - Claude provider
  • CheckCircle2, XCircle - Status indicators
  • Loader2 - Loading states
  • RefreshCw - Refresh action
  • ExternalLink - External links

3. Cursor CLI Installation Paths

Based on official cursor-agent install script:

Linux/macOS:

  • Primary symlink: ~/.local/bin/cursor-agent
  • Versions directory: ~/.local/share/cursor-agent/versions/<version>/cursor-agent
  • Fallback: /usr/local/bin/cursor-agent

Windows:

  • Primary: %APPDATA%\Local\Programs\cursor-agent\cursor-agent.exe
  • Fallback: ~/.local/bin/cursor-agent.exe
  • Fallback: C:\Program Files\cursor-agent\cursor-agent.exe

4. Use @automaker/* Packages

All server-side code must use shared packages from libs/:

From @automaker/types:

  • Reuse existing InstallationStatus (don't create CursorInstallationStatus)
  • Extend ModelProvider type to include 'cursor'
  • Extend DEFAULT_MODELS to include cursor: 'auto'
  • Update ModelOption.provider from 'claude' to ModelProvider

From @automaker/utils:

import { createLogger, isAbortError } from '@automaker/utils';

const logger = createLogger('CursorProvider');
// Use isAbortError() for abort signal detection

From @automaker/platform:

import { spawnJSONLProcess, getAutomakerDir } from '@automaker/platform';

// Use spawnJSONLProcess for JSONL streaming (handles buffering, timeout, abort)
// Use getAutomakerDir for consistent .automaker path resolution

5. Do NOT Extend @automaker/model-resolver

The model-resolver is Claude-specific and should not be extended for Cursor:

  • Claude uses aliases (sonnetclaude-sonnet-4-5-20250929)
  • Cursor model IDs are final-form (claude-sonnet-4 passed directly to CLI)
  • Cursor models have metadata (hasThinking, tier) that doesn't fit the string-only map

Cursor models use their own CURSOR_MODEL_MAP in @automaker/types.


Risk Mitigation

  1. Phase Isolation: Each phase can be tested independently
  2. Feature Flags: Cursor provider can be disabled if issues arise
  3. Fallback: Default to Claude provider for unknown models
  4. Graceful Degradation: UI shows "not installed" state clearly

How to Use This Plan

  1. Start with Phase 0 - Read and understand existing patterns
  2. Complete phases sequentially - Dependencies require order
  3. Test each phase - Run the verification steps before moving on
  4. Update status - Mark phases as in_progress, completed, or blocked
  5. Document issues - Add notes to individual phase files

Changelog

Date Phase Change
2025-12-27 - Initial plan created
2025-12-27 2 Updated findCliPath() with platform-specific paths and versions directory scanning
2025-12-27 4 Updated to use HttpApiClient instead of raw fetch
2025-12-27 6 Updated to use HttpApiClient and existing UI components
2025-12-27 7 Updated to use HttpApiClient and existing UI components
2025-12-27 - Added Design Decisions section to README
2025-12-27 2 Updated to use createLogger from @automaker/utils
2025-12-27 4 Updated to use createLogger from @automaker/utils
2025-12-27 8 Added proper UI component imports from @/components/ui/*
2025-12-27 1 Added tasks 1.5-1.7: ModelOption, DEFAULT_MODELS, reuse InstallationStatus
2025-12-27 2 Refactored to use spawnJSONLProcess and isAbortError from @automaker packages
2025-12-27 - Added design decisions 4-5: @automaker packages usage, model-resolver note
2025-12-28 9 Completed: ModelSelector with Cursor models, provider tracking in execution events