feat: Add Cursor CLI configuration and status endpoints

- Implemented new routes for managing Cursor CLI configuration, including getting current settings and updating default models.
- Created status endpoint to check Cursor CLI installation and authentication status.
- Updated HttpApiClient to include methods for interacting with the new Cursor API endpoints.
- Marked completion of the setup routes and status endpoints phase in the integration plan.
This commit is contained in:
Shirone
2025-12-28 00:53:31 +01:00
parent 6e9468a56e
commit 59612231bb
6 changed files with 272 additions and 19 deletions

View File

@@ -12,6 +12,12 @@ import { createApiKeysHandler } from './routes/api-keys.js';
import { createPlatformHandler } from './routes/platform.js';
import { createVerifyClaudeAuthHandler } from './routes/verify-claude-auth.js';
import { createGhStatusHandler } from './routes/gh-status.js';
import { createCursorStatusHandler } from './routes/cursor-status.js';
import {
createGetCursorConfigHandler,
createSetCursorDefaultModelHandler,
createSetCursorModelsHandler,
} from './routes/cursor-config.js';
export function createSetupRoutes(): Router {
const router = Router();
@@ -26,5 +32,11 @@ export function createSetupRoutes(): Router {
router.post('/verify-claude-auth', createVerifyClaudeAuthHandler());
router.get('/gh-status', createGhStatusHandler());
// Cursor CLI routes
router.get('/cursor-status', createCursorStatusHandler());
router.get('/cursor-config', createGetCursorConfigHandler());
router.post('/cursor-config/default-model', createSetCursorDefaultModelHandler());
router.post('/cursor-config/models', createSetCursorModelsHandler());
return router;
}

View File

@@ -0,0 +1,136 @@
/**
* Cursor CLI configuration routes
*
* Provides endpoints for managing Cursor CLI configuration:
* - GET /api/setup/cursor-config - Get current configuration
* - POST /api/setup/cursor-config/default-model - Set default model
* - POST /api/setup/cursor-config/models - Set enabled models
*/
import type { Request, Response } from 'express';
import { CursorConfigManager } from '../../../providers/cursor-config-manager.js';
import { CURSOR_MODEL_MAP, type CursorModelId } from '@automaker/types';
import { getErrorMessage, logError } from '../common.js';
/**
* Creates handler for GET /api/setup/cursor-config
* Returns current Cursor configuration and available models
*/
export function createGetCursorConfigHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const projectPath = req.query.projectPath as string;
if (!projectPath) {
res.status(400).json({
success: false,
error: 'projectPath query parameter is required',
});
return;
}
const configManager = new CursorConfigManager(projectPath);
res.json({
success: true,
config: configManager.getConfig(),
availableModels: Object.values(CURSOR_MODEL_MAP),
});
} catch (error) {
logError(error, 'Get Cursor config failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}
/**
* Creates handler for POST /api/setup/cursor-config/default-model
* Sets the default Cursor model
*/
export function createSetCursorDefaultModelHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const { model, projectPath } = req.body;
if (!projectPath) {
res.status(400).json({
success: false,
error: 'projectPath is required',
});
return;
}
if (!model || !(model in CURSOR_MODEL_MAP)) {
res.status(400).json({
success: false,
error: `Invalid model ID. Valid models: ${Object.keys(CURSOR_MODEL_MAP).join(', ')}`,
});
return;
}
const configManager = new CursorConfigManager(projectPath);
configManager.setDefaultModel(model as CursorModelId);
res.json({ success: true, model });
} catch (error) {
logError(error, 'Set Cursor default model failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}
/**
* Creates handler for POST /api/setup/cursor-config/models
* Sets the enabled Cursor models list
*/
export function createSetCursorModelsHandler() {
return async (req: Request, res: Response): Promise<void> => {
try {
const { models, projectPath } = req.body;
if (!projectPath) {
res.status(400).json({
success: false,
error: 'projectPath is required',
});
return;
}
if (!Array.isArray(models)) {
res.status(400).json({
success: false,
error: 'Models must be an array',
});
return;
}
// Filter to valid models only
const validModels = models.filter((m): m is CursorModelId => m in CURSOR_MODEL_MAP);
if (validModels.length === 0) {
res.status(400).json({
success: false,
error: 'No valid models provided',
});
return;
}
const configManager = new CursorConfigManager(projectPath);
configManager.setEnabledModels(validModels);
res.json({ success: true, models: validModels });
} catch (error) {
logError(error, 'Set Cursor models failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}

View File

@@ -0,0 +1,52 @@
/**
* GET /cursor-status endpoint - Get Cursor CLI installation and auth status
*/
import type { Request, Response } from 'express';
import { CursorProvider } from '../../../providers/cursor-provider.js';
import { getErrorMessage, logError } from '../common.js';
/**
* Creates handler for GET /api/setup/cursor-status
* Returns Cursor CLI installation and authentication status
*/
export function createCursorStatusHandler() {
const installCommand = 'curl https://cursor.com/install -fsS | bash';
const loginCommand = 'cursor-agent login';
return async (_req: Request, res: Response): Promise<void> => {
try {
const provider = new CursorProvider();
const [installed, version, auth] = await Promise.all([
provider.isInstalled(),
provider.getVersion(),
provider.checkAuth(),
]);
// Get CLI path from provider (using type assertion since cliPath is private)
const cliPath = installed
? (provider as unknown as { cliPath: string | null }).cliPath
: null;
res.json({
success: true,
installed,
version: version || null,
path: cliPath,
auth: {
authenticated: auth.authenticated,
method: auth.method,
},
installCommand,
loginCommand,
});
} catch (error) {
logError(error, 'Get Cursor status failed');
res.status(500).json({
success: false,
error: getErrorMessage(error),
});
}
};
}

View File

@@ -508,6 +508,59 @@ export class HttpApiClient implements ElectronAPI {
error?: string;
}> => this.get('/api/setup/gh-status'),
// Cursor CLI methods
getCursorStatus: (): Promise<{
success: boolean;
installed?: boolean;
version?: string | null;
path?: string | null;
auth?: {
authenticated: boolean;
method: string;
};
installCommand?: string;
loginCommand?: string;
error?: string;
}> => this.get('/api/setup/cursor-status'),
getCursorConfig: (
projectPath: string
): Promise<{
success: boolean;
config?: {
defaultModel?: string;
models?: string[];
mcpServers?: string[];
rules?: string[];
};
availableModels?: Array<{
id: string;
label: string;
description: string;
hasThinking: boolean;
tier: 'free' | 'pro';
}>;
error?: string;
}> => this.get(`/api/setup/cursor-config?projectPath=${encodeURIComponent(projectPath)}`),
setCursorDefaultModel: (
projectPath: string,
model: string
): Promise<{
success: boolean;
model?: string;
error?: string;
}> => this.post('/api/setup/cursor-config/default-model', { projectPath, model }),
setCursorModels: (
projectPath: string,
models: string[]
): Promise<{
success: boolean;
models?: string[];
error?: string;
}> => this.post('/api/setup/cursor-config/models', { projectPath, models }),
onInstallProgress: (callback: (progress: unknown) => void) => {
return this.subscribeToEvent('agent:stream', callback);
},

View File

@@ -10,7 +10,7 @@
| 1 | [Core Types & Configuration](phases/phase-1-types.md) | `completed` | ✅ |
| 2 | [Cursor Provider Implementation](phases/phase-2-provider.md) | `completed` | ✅ |
| 3 | [Provider Factory Integration](phases/phase-3-factory.md) | `completed` | ✅ |
| 4 | [Setup Routes & Status Endpoints](phases/phase-4-routes.md) | `pending` | - |
| 4 | [Setup Routes & Status Endpoints](phases/phase-4-routes.md) | `completed` | |
| 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` | - |

View File

@@ -1,6 +1,6 @@
# Phase 4: Setup Routes & Status Endpoints
**Status:** `pending`
**Status:** `completed`
**Dependencies:** Phase 3 (Factory)
**Estimated Effort:** Medium (API endpoints)
@@ -16,7 +16,7 @@ Create API endpoints for checking Cursor CLI status and managing configuration.
### Task 4.1: Create Cursor Status Route
**Status:** `pending`
**Status:** `completed`
**File:** `apps/server/src/routes/setup/routes/cursor-status.ts`
@@ -74,7 +74,7 @@ export function createCursorStatusRoute(): Router {
### Task 4.2: Create Cursor Config Routes
**Status:** `pending`
**Status:** `completed`
**File:** `apps/server/src/routes/setup/routes/cursor-config.ts`
@@ -182,7 +182,7 @@ export function createCursorConfigRoutes(dataDir: string): Router {
### Task 4.3: Register Routes in Setup Index
**Status:** `pending`
**Status:** `completed`
**File:** `apps/server/src/routes/setup/index.ts`
@@ -210,7 +210,7 @@ export function createSetupRouter(dataDir: string): Router {
### Task 4.4: Update HttpApiClient
**Status:** `pending`
**Status:** `completed`
**File:** `apps/ui/src/lib/http-api-client.ts`
@@ -320,24 +320,24 @@ curl -X POST http://localhost:3001/api/setup/cursor-config/default-model \
Before marking this phase complete:
- [ ] `/api/setup/cursor-status` returns installation status
- [ ] `/api/setup/cursor-config` returns current config
- [ ] `/api/setup/cursor-config/default-model` updates default
- [ ] `/api/setup/cursor-config/models` updates enabled models
- [ ] Error responses have correct status codes (400, 500)
- [ ] Config persists to file after changes
- [ ] SetupAPI type updated (if using Electron IPC)
- [x] `/api/setup/cursor-status` returns installation status
- [x] `/api/setup/cursor-config` returns current config
- [x] `/api/setup/cursor-config/default-model` updates default
- [x] `/api/setup/cursor-config/models` updates enabled models
- [x] Error responses have correct status codes (400, 500)
- [x] Config persists to file after changes
- [x] HttpApiClient updated with Cursor methods (using web mode, not Electron IPC)
---
## Files Changed
| File | Action | Description |
| ------------------------------------------------------ | ------ | ---------------- |
| `apps/server/src/routes/setup/routes/cursor-status.ts` | Create | Status endpoint |
| `apps/server/src/routes/setup/routes/cursor-config.ts` | Create | Config endpoints |
| `apps/server/src/routes/setup/index.ts` | Modify | Register routes |
| `apps/ui/src/lib/electron.ts` | Modify | Add API types |
| File | Action | Description |
| ------------------------------------------------------ | ------ | ----------------------------- |
| `apps/server/src/routes/setup/routes/cursor-status.ts` | Create | Status endpoint |
| `apps/server/src/routes/setup/routes/cursor-config.ts` | Create | Config endpoints |
| `apps/server/src/routes/setup/index.ts` | Modify | Register routes |
| `apps/ui/src/lib/http-api-client.ts` | Modify | Add Cursor API client methods |
---