From a359a4ab8bde14b665f99f449aac69449131072d Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Fri, 29 May 2026 04:07:21 +0000 Subject: [PATCH] coder(providers): remove retired cursor and copilot providers Drop both retired providers from BooCoder's provider layer: acp-spawn argv cases, provider-manifest mode blocks + manifest keys, provider-commands maps, the provider-snapshot cursor model-CLI branch (+ orphaned exec/promisify imports), the agent-probe copilot ACP-detect branch, and the now-dead cursor-models module + its test. The PROVIDERS registry array already lacked both. Built-ins unchanged: claude, opencode, goose, qwen, native boocode. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../services/__tests__/cursor-models.test.ts | 47 ------------------- .../__tests__/provider-commands.test.ts | 2 +- apps/coder/src/services/acp-spawn.ts | 13 +---- apps/coder/src/services/agent-probe.ts | 9 ---- apps/coder/src/services/cursor-models.ts | 39 --------------- apps/coder/src/services/provider-commands.ts | 18 ------- apps/coder/src/services/provider-manifest.ts | 33 ------------- apps/coder/src/services/provider-registry.ts | 3 +- apps/coder/src/services/provider-snapshot.ts | 16 ------- 9 files changed, 3 insertions(+), 177 deletions(-) delete mode 100644 apps/coder/src/services/__tests__/cursor-models.test.ts delete mode 100644 apps/coder/src/services/cursor-models.ts diff --git a/apps/coder/src/services/__tests__/cursor-models.test.ts b/apps/coder/src/services/__tests__/cursor-models.test.ts deleted file mode 100644 index ba402ec..0000000 --- a/apps/coder/src/services/__tests__/cursor-models.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, it, expect } from 'vitest'; -import { parseCursorAgentModelsOutput } from '../cursor-models.js'; - -describe('parseCursorAgentModelsOutput', () => { - it('parses cursor-agent models output with default marker', () => { - const output = ` -Available models -claude-4-sonnet - Claude 4 Sonnet (default) -gpt-4.1 - GPT-4.1 -Tip: use cursor-agent models for full list -`.trim(); - - const models = parseCursorAgentModelsOutput(output); - - expect(models).toEqual([ - { id: 'claude-4-sonnet', label: 'Claude 4 Sonnet', isDefault: true }, - { id: 'gpt-4.1', label: 'GPT-4.1', isDefault: false }, - ]); - }); - - it('uses current marker when no default', () => { - const output = ` -model-a - Model A (current) -model-b - Model B -`.trim(); - - const models = parseCursorAgentModelsOutput(output); - - expect(models.find((m) => m.id === 'model-a')?.isDefault).toBe(true); - expect(models.find((m) => m.id === 'model-b')?.isDefault).toBe(false); - }); - - it('defaults to first model when no markers', () => { - const output = 'alpha - Alpha\nbeta - Beta'; - const models = parseCursorAgentModelsOutput(output); - - expect(models[0]?.isDefault).toBe(true); - expect(models[1]?.isDefault).toBe(false); - }); - - it('skips malformed lines', () => { - const output = 'no-separator\nvalid - Valid'; - const models = parseCursorAgentModelsOutput(output); - - expect(models).toEqual([{ id: 'valid', label: 'Valid', isDefault: true }]); - }); -}); diff --git a/apps/coder/src/services/__tests__/provider-commands.test.ts b/apps/coder/src/services/__tests__/provider-commands.test.ts index c8b07a0..32a82ff 100644 --- a/apps/coder/src/services/__tests__/provider-commands.test.ts +++ b/apps/coder/src/services/__tests__/provider-commands.test.ts @@ -3,7 +3,7 @@ import { getManifestCommands, mergeCommands, PROVIDER_COMMANDS } from '../provid describe('provider-commands', () => { it('defines commands for every external harness', () => { - for (const name of ['claude', 'opencode', 'cursor', 'goose', 'qwen', 'copilot']) { + for (const name of ['claude', 'opencode', 'goose', 'qwen']) { expect(getManifestCommands(name).length, name).toBeGreaterThan(0); } }); diff --git a/apps/coder/src/services/acp-spawn.ts b/apps/coder/src/services/acp-spawn.ts index 9ef3a2f..f2da474 100644 --- a/apps/coder/src/services/acp-spawn.ts +++ b/apps/coder/src/services/acp-spawn.ts @@ -6,10 +6,6 @@ export function resolveAcpSpawnArgs(agent: string): string[] | null { case 'opencode': case 'goose': return ['acp']; - case 'cursor': - return ['acp']; - case 'copilot': - return ['--acp']; case 'qwen': return ['--acp']; default: @@ -18,12 +14,5 @@ export function resolveAcpSpawnArgs(agent: string): string[] | null { } export function resolveAcpProbeBinaries(agent: string): string[] { - switch (agent) { - case 'cursor': - return ['cursor-agent', 'agent']; - case 'copilot': - return ['copilot']; - default: - return [agent]; - } + return [agent]; } diff --git a/apps/coder/src/services/agent-probe.ts b/apps/coder/src/services/agent-probe.ts index 041b5d6..488b7d3 100644 --- a/apps/coder/src/services/agent-probe.ts +++ b/apps/coder/src/services/agent-probe.ts @@ -27,15 +27,6 @@ async function detectAcpSupport(agentName: string, installPath: string): Promise const transport = PROVIDERS_BY_NAME.get(agentName)?.transport; if (transport !== 'acp') return false; - if (agentName === 'copilot') { - try { - const { stdout } = await exec(`"${installPath}" --help`, { timeout: 10_000 }); - return stdout.includes('--acp'); - } catch { - return false; - } - } - if (agentName === 'qwen') { try { const { stdout } = await exec(`"${installPath}" --help`, { timeout: 10_000 }); diff --git a/apps/coder/src/services/cursor-models.ts b/apps/coder/src/services/cursor-models.ts deleted file mode 100644 index ecf9fa0..0000000 --- a/apps/coder/src/services/cursor-models.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Cursor model list parser — lifted from Paseo cursor-acp-agent.ts - */ -import type { ProviderModel } from './provider-types.js'; - -const CURSOR_MODEL_MARKER_PATTERN = /\s+\((?:default|current)\)$/; - -export function parseCursorAgentModelsOutput(output: string): ProviderModel[] { - const parsed = output - .split(/\r?\n/) - .map((line) => line.trim()) - .filter((line) => line && line !== 'Available models' && !line.startsWith('Tip:')) - .map((line) => { - const separatorIndex = line.indexOf(' - '); - if (separatorIndex <= 0) return null; - - const id = line.slice(0, separatorIndex).trim(); - const rawLabel = line.slice(separatorIndex + 3).trim(); - if (!id || !rawLabel) return null; - - let marker: 'default' | 'current' | null = null; - if (rawLabel.endsWith(' (default)')) marker = 'default'; - else if (rawLabel.endsWith(' (current)')) marker = 'current'; - - return { id, label: rawLabel.replace(CURSOR_MODEL_MARKER_PATTERN, ''), marker }; - }) - .filter((m): m is { id: string; label: string; marker: 'default' | 'current' | null } => m !== null); - - const defaultModelId = - parsed.find((m) => m.marker === 'default')?.id ?? - parsed.find((m) => m.marker === 'current')?.id ?? - parsed[0]?.id; - - return parsed.map((model) => ({ - id: model.id, - label: model.label, - isDefault: model.id === defaultModelId, - })); -} diff --git a/apps/coder/src/services/provider-commands.ts b/apps/coder/src/services/provider-commands.ts index e9f2a08..80a3156 100644 --- a/apps/coder/src/services/provider-commands.ts +++ b/apps/coder/src/services/provider-commands.ts @@ -27,13 +27,6 @@ const OPENCODE_COMMANDS: AgentCommand[] = [ { name: 'export', description: 'Export session' }, ]; -const CURSOR_COMMANDS: AgentCommand[] = [ - { name: 'help', description: 'Show available slash commands' }, - { name: 'clear', description: 'Clear conversation' }, - { name: 'compact', description: 'Compact context' }, - { name: 'resume', description: 'Resume a prior session' }, -]; - const GOOSE_COMMANDS: AgentCommand[] = [ { name: 'help', description: 'Show available commands' }, { name: 'clear', description: 'Clear conversation' }, @@ -49,23 +42,12 @@ const QWEN_COMMANDS: AgentCommand[] = [ { name: 'review', description: 'Review changes' }, ]; -const COPILOT_COMMANDS: AgentCommand[] = [ - { name: 'help', description: 'Show available commands' }, - { name: 'explain', description: 'Explain selected code' }, - { name: 'fix', description: 'Fix issues in context' }, - { name: 'tests', description: 'Generate or run tests' }, - { name: 'doc', description: 'Generate documentation' }, - { name: 'clear', description: 'Clear conversation' }, -]; - /** boocode harness uses /api/skills — merged on the frontend. */ export const PROVIDER_COMMANDS: Record = { claude: CLAUDE_COMMANDS, opencode: OPENCODE_COMMANDS, - cursor: CURSOR_COMMANDS, goose: GOOSE_COMMANDS, qwen: QWEN_COMMANDS, - copilot: COPILOT_COMMANDS, boocode: [], }; diff --git a/apps/coder/src/services/provider-manifest.ts b/apps/coder/src/services/provider-manifest.ts index 6972708..3bad485 100644 --- a/apps/coder/src/services/provider-manifest.ts +++ b/apps/coder/src/services/provider-manifest.ts @@ -24,31 +24,6 @@ const OPENCODE_MODES: ProviderMode[] = [ { id: 'full-access', label: 'Full Access', description: 'Auto-approves all tool prompts', isUnattended: true }, ]; -const COPILOT_MODES: ProviderMode[] = [ - { - id: 'https://agentclientprotocol.com/protocol/session-modes#agent', - label: 'Agent', - description: 'Default agent mode', - }, - { - id: 'https://agentclientprotocol.com/protocol/session-modes#plan', - label: 'Plan', - description: 'Plan mode for multi-step work', - }, - { - id: 'allow-all', - label: 'Allow All', - description: 'Automatically approves all tool, path, and URL requests', - isUnattended: true, - }, -]; - -const CURSOR_CLI_MODES: ProviderMode[] = [ - { id: 'agent', label: 'Agent', description: 'Full agent capabilities with tool access' }, - { id: 'plan', label: 'Plan', description: 'Read-only planning mode' }, - { id: 'ask', label: 'Ask', description: 'Q&A read-only mode' }, -]; - const QWEN_PTY_MODES: ProviderMode[] = [ { id: 'default', label: 'Default', description: 'Prompt for approval' }, { id: 'plan', label: 'Plan', description: 'Plan only — no edits' }, @@ -75,14 +50,6 @@ export const PROVIDER_MANIFEST: Record = { defaultModeId: 'build', modes: OPENCODE_MODES, }, - copilot: { - defaultModeId: 'https://agentclientprotocol.com/protocol/session-modes#agent', - modes: COPILOT_MODES, - }, - cursor: { - defaultModeId: 'agent', - modes: CURSOR_CLI_MODES, - }, goose: { defaultModeId: null, modes: [], diff --git a/apps/coder/src/services/provider-registry.ts b/apps/coder/src/services/provider-registry.ts index b1db3b7..0e33f83 100644 --- a/apps/coder/src/services/provider-registry.ts +++ b/apps/coder/src/services/provider-registry.ts @@ -13,8 +13,7 @@ export interface ProviderDef { * - boocode: llama-swap only * - opencode: ACP probe + mergeLlamaSwap (prefixed llama-swap/* ids) * - qwen: ACP probe + merge ~/.qwen/settings.json; PTY fallback reads settings only - * - cursor: ACP probe + cursor-agent models CLI fallback - * - goose / copilot: ACP probe only + * - goose: ACP probe only * - claude: static manifest models + thinking options */ export const PROVIDERS: ProviderDef[] = [ diff --git a/apps/coder/src/services/provider-snapshot.ts b/apps/coder/src/services/provider-snapshot.ts index 2643109..c8378f6 100644 --- a/apps/coder/src/services/provider-snapshot.ts +++ b/apps/coder/src/services/provider-snapshot.ts @@ -2,8 +2,6 @@ * Provider snapshot cache — cold ACP probe per provider + static manifest merge. */ import { homedir } from 'node:os'; -import { exec as execCb } from 'node:child_process'; -import { promisify } from 'node:util'; import type { FastifyBaseLogger } from 'fastify'; import type { Sql } from '../db.js'; import type { Config } from '../config.js'; @@ -14,13 +12,10 @@ import { PROVIDER_MANIFEST, } from './provider-manifest.js'; import { probeAcpProvider } from './acp-probe.js'; -import { parseCursorAgentModelsOutput } from './cursor-models.js'; import type { ProviderModel, ProviderSnapshotEntry } from './provider-types.js'; import { getManifestCommands, mergeCommands } from './provider-commands.js'; import { readQwenSettingsModels } from './qwen-settings.js'; -const exec = promisify(execCb); - interface AgentRow { name: string; install_path: string | null; @@ -41,15 +36,6 @@ async function fetchLlamaSwapModels(config: Config): Promise { } } -async function fetchCursorModelsCli(installPath: string): Promise { - try { - const { stdout } = await exec(`"${installPath}" models`, { timeout: 15_000, maxBuffer: 1024 * 1024 }); - return parseCursorAgentModelsOutput(stdout); - } catch { - return []; - } -} - /** Prefix llama-swap model ids so they don't collide with provider-native models. */ export function prefixLlamaSwapModels(models: ProviderModel[]): ProviderModel[] { return models.map((m) => ({ @@ -141,8 +127,6 @@ async function buildProviderEntry( const probe = await probeAcpProvider(provider.name, agentRow.install_path, cwd); if (probe.models.length > 0) { models = probe.models; - } else if (provider.name === 'cursor' && agentRow.install_path) { - models = await fetchCursorModelsCli(agentRow.install_path); } else if (provider.modelSource === 'llama-swap') { models = llamaModels; }