From a2c8369e787d78717699e58ea234fd222e2e81d1 Mon Sep 17 00:00:00 2001 From: Tiberius Dourado Date: Wed, 10 Jun 2026 14:44:23 -0300 Subject: [PATCH] fix(models): retarget Composer aliases to Composer 2.5 Cursor retired the Composer 2.x ids; `cursor-agent --list-models` now exposes only `composer-2.5` and `composer-2.5-fast`. The `composer`, `composer-fast`, and `fast` shortcuts resolved to the dead `composer-2-fast` slug, and `composer-full` to `composer-2`. Retarget the short shortcuts to `composer-2.5-fast` and `composer-full` to `composer-2.5`, add explicit identities for the live ids, and keep `composer-2`/`composer-2-fast` as passthrough aliases so users on older cursor-agent builds aren't broken. Update README, the cursor-runner agent guidance, command/package descriptions, and tests to match. Resolves #8 --- .claude-plugin/marketplace.json | 2 +- CHANGELOG.md | 6 ++++++ README.md | 16 ++++++++-------- plugins/cursor/agents/cursor-runner.md | 10 +++++----- plugins/cursor/commands/delegate.md | 2 +- plugins/cursor/package.json | 4 ++-- plugins/cursor/plugin.json | 2 +- plugins/cursor/scripts/lib/cursor.mjs | 15 ++++++++++----- plugins/cursor/tests/cursor.test.mjs | 22 +++++++++++++++------- plugins/cursor/tests/delegate.fg.test.mjs | 2 +- plugins/cursor/tests/jobs.test.mjs | 2 +- 11 files changed, 51 insertions(+), 32 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 1c82b41..c471a18 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,7 @@ { "name": "cursor", "source": "./plugins/cursor", - "description": "Delegate coding tasks from Claude Code to Cursor CLI (Composer 2 by default).", + "description": "Delegate coding tasks from Claude Code to Cursor CLI (Composer by default).", "strict": false } ] diff --git a/CHANGELOG.md b/CHANGELOG.md index f45ca8f..ba371c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Fixed + +- **Model aliases updated for Composer 2.5.** Cursor retired the Composer 2.x ids — `cursor-agent --list-models` now lists only `composer-2.5` and `composer-2.5-fast` (verified on macOS, 2026-06-10). The `composer`, `composer-fast`, and `fast` shortcuts now resolve to `composer-2.5-fast` (was the dead `composer-2-fast`), and `composer-full` resolves to `composer-2.5` (was `composer-2`). The retired `composer-2` / `composer-2-fast` ids are kept as identity passthroughs so users on older `cursor-agent` builds aren't broken. README, the `cursor-runner` agent guidance, command/package descriptions, and tests updated to match. (#8) + ## 0.3.0 — /cursor:review + codebase hardening ### Added diff --git a/README.md b/README.md index f68a32e..aca9ba9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # cursor-plugin-cc > **Claude plans. Cursor writes. Claude reviews.** -> A Claude Code plugin that delegates coding _execution_ to Cursor's Composer 2 — without ever leaving the Claude Code TUI. +> A Claude Code plugin that delegates coding _execution_ to Cursor's Composer — without ever leaving the Claude Code TUI. [![CI](https://github.com/freema/cursor-plugin-cc/actions/workflows/ci.yml/badge.svg)](https://github.com/freema/cursor-plugin-cc/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) @@ -22,7 +22,7 @@ claude ▸ Plan written to ~/.claude/plans/health-endpoint.md you ▸ /cursor:from-plan --delegate plugin ▸ wrote tasks/20260427-1830-health-endpoint.md - ▸ handing off to cursor-agent (composer-2-fast, --force)… + ▸ handing off to cursor-agent (composer-2.5-fast, --force)… cursor ▸ ✓ src/routes/health.ts (new, 24 lines) ▸ ✓ src/app.ts (mounted route) @@ -42,7 +42,7 @@ cursor ▸ ✓ src/routes/health.ts (1 line changed) That's the whole loop. Claude does the **thinking** (plan, review). Cursor does the **typing** (file edits, tests). You stay in one TUI. -**Why this is fast:** `composer-2-fast` is Cursor's tuned-for-CLI variant — it ships small, well-scoped changes in seconds. Claude Code spends its tokens on planning and reviewing, where thinking actually matters. Two tools, each doing what they're best at. +**Why this is fast:** `composer-2.5-fast` is Cursor's tuned-for-CLI variant — it ships small, well-scoped changes in seconds. Claude Code spends its tokens on planning and reviewing, where thinking actually matters. Two tools, each doing what they're best at. ## Install @@ -73,7 +73,7 @@ The first `/cursor:setup` run tells you if `cursor-agent` is missing or unauthen ### Requirements - Node.js **≥ 18.18** -- A Cursor account — paid for Composer 2 models; free works with `--model auto` or other entitled models +- A Cursor account — paid for Composer models; free works with `--model auto` or other entitled models - `cursor-agent` on your `PATH` — install via `curl https://cursor.com/install -fsS | bash` - `cursor-agent login` completed at least once @@ -134,7 +134,7 @@ Plus a `cursor-runner` subagent you can invoke from inside Claude to delegate we ## Why this plugin -Short answer: **Composer 2 is genuinely good at most day-to-day coding work** — and I don't want a pile of terminal windows to drive it. I want Claude Code to be the orchestrator for everything. The flow that keeps working for me is simple: **Claude makes the plan, Composer executes it, Claude reviews the diff.** Two tools, each doing what it is best at. +Short answer: **Composer is genuinely good at most day-to-day coding work** — and I don't want a pile of terminal windows to drive it. I want Claude Code to be the orchestrator for everything. The flow that keeps working for me is simple: **Claude makes the plan, Composer executes it, Claude reviews the diff.** Two tools, each doing what it is best at. "Why not do the whole thing inside Cursor, then?" Claude Code has a certain magic, particularly around planning. It is not purely about the underlying model — it is the whole rig (long-context sessions, subagents, the TUI, the way tools compose) that, in my experience, only really clicks inside Claude Code. @@ -156,7 +156,7 @@ Hand a coding task to `cursor-agent -p …`. | Flag | Default | Effect | | ---------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--model ` | `auto` (or `$CURSOR_PLUGIN_CC_DEFAULT_MODEL`) | Aliases → real Cursor ids: `composer`/`fast` → `composer-2-fast`, `composer-2` → `composer-2`, `sonnet` → `claude-4.6-sonnet-medium`, `opus` → `claude-opus-4-7-high`, `gpt`/`codex` → `gpt-5.3-codex`, `grok` → `grok-4-20`, `gemini` → `gemini-3.1-pro`, `auto` → `auto`. Unknown ids forwarded as-is. `auto` lets Cursor pick whatever model your account is entitled to — safe if you don't have a Composer 2 seat. Run `/cursor:setup --print-models` for the live list. | +| `--model ` | `auto` (or `$CURSOR_PLUGIN_CC_DEFAULT_MODEL`) | Aliases → real Cursor ids: `composer`/`fast` → `composer-2.5-fast`, `composer-full` → `composer-2.5`, `sonnet` → `claude-4.6-sonnet-medium`, `opus` → `claude-opus-4-7-high`, `gpt`/`codex` → `gpt-5.3-codex`, `grok` → `grok-4-20`, `gemini` → `gemini-3.1-pro`, `auto` → `auto`. Unknown or retired ids (e.g. `composer-2`, `composer-2-fast`) are forwarded as-is. `auto` lets Cursor pick whatever model your account is entitled to — safe if you don't have a Composer seat. Run `/cursor:setup --print-models` for the live list. | | `--background` | off | Detach; the command returns a job id immediately. | | `--wait` | on (if not `--background`) | Block until finished. | | `--fresh` | off | Start a brand-new Cursor session (no resume). | @@ -365,11 +365,11 @@ The plugin codebase is English, but it does not impose a language policy on **yo The two-phase loop above is the concept; here is the concrete workflow that falls out of it in practice, and the one I keep reaching for: 1. **Plan in Claude Code and write a task file.** Describe what you want; ask Claude to draft a _task spec_ — a markdown file with **goal**, **acceptance criteria**, **files to touch**, and **how to verify** (the same five sections the `cursor-runner` subagent enforces). Save it under `tasks/.md` in the repo. -2. **Hand the file to Cursor.** Run `/cursor:delegate @tasks/.md implement this`. The `@path` shorthand inlines the file contents into the prompt, so Cursor gets the full spec without Claude having to re-type it. Composer 2 executes — it is genuinely fast, and a precisely defined task is usually a one-shot job. +2. **Hand the file to Cursor.** Run `/cursor:delegate @tasks/.md implement this`. The `@path` shorthand inlines the file contents into the prompt, so Cursor gets the full spec without Claude having to re-type it. Composer executes — it is genuinely fast, and a precisely defined task is usually a one-shot job. 3. **Back in Claude Code: review the diff.** Approve, or iterate with `/cursor:resume "fix X"` on the same thread, or escalate with `/cursor:delegate --model opus --fresh ` if Composer stalled. 4. **Keep the task files around.** `tasks/` becomes a little log of what the repo's delegated changes looked like. Handy when you want to re-delegate a similar slice — just copy an old file, tweak the bullets. -Why this works: Claude's tokens go into **planning and reviewing**, where thinking matters; Cursor's Composer 2 handles **the actual typing**, where it is cheaper and faster. The task file is the contract between the two phases — if it is sloppy, no model will save you. Writing a good one is itself a skill, and it is the only skill this workflow asks of you. +Why this works: Claude's tokens go into **planning and reviewing**, where thinking matters; Cursor's Composer handles **the actual typing**, where it is cheaper and faster. The task file is the contract between the two phases — if it is sloppy, no model will save you. Writing a good one is itself a skill, and it is the only skill this workflow asks of you. If you want Claude to do the whole thing automatically — draft the task file AND hand it off — that is what the `cursor-runner` subagent is for. Ask it to either "draft a task file for X" (it stops there) or "implement X via Cursor" (it drafts, hands off, and reports the diff). diff --git a/plugins/cursor/agents/cursor-runner.md b/plugins/cursor/agents/cursor-runner.md index 2cca4e8..78795f6 100644 --- a/plugins/cursor/agents/cursor-runner.md +++ b/plugins/cursor/agents/cursor-runner.md @@ -1,6 +1,6 @@ --- name: cursor-runner -description: Hand off a well-specified coding task to the Cursor CLI (`cursor-agent`) via `/cursor:delegate`. Use for small-to-medium, well-scoped changes where speed matters (default model `composer-2-fast`). Do NOT use this agent for code review, design decisions, or large refactors — those stay with the main Claude conversation. +description: Hand off a well-specified coding task to the Cursor CLI (`cursor-agent`) via `/cursor:delegate`. Use for small-to-medium, well-scoped changes where speed matters (default model `composer-2.5-fast`). Do NOT use this agent for code review, design decisions, or large refactors — those stay with the main Claude conversation. tools: [Bash, Read] --- @@ -56,9 +56,9 @@ Small slices give Cursor a tight scope, make the diff reviewable, and make failu ### 4. Pick a model -Default is `composer-2-fast` — Cursor's own current default and the fastest Composer variant. Escalate only when the task warrants it: +Default is `composer-2.5-fast` — Cursor's own current default and the fastest Composer variant. Escalate only when the task warrants it: -- `composer-2` (non-fast) — quality matters slightly more than latency, but the task is still well-scoped. +- `composer-2.5` (non-fast) — quality matters slightly more than latency, but the task is still well-scoped. - `sonnet` (`claude-4.6-sonnet-medium`) — more than ~5 files touched, or moderate architecture changes. - `opus` (`claude-opus-4-7-high`) — cross-cutting refactor, subtle correctness, or a prior `composer` run failed. - `gpt` / `codex` (`gpt-5.3-codex`) — only when the user explicitly asks for it. @@ -92,13 +92,13 @@ Do not paraphrase the summary, do not rewrite the file list, do not hide the cha - **Do not edit files yourself.** Use `Read` only to ground the prompt you send to Cursor — never to patch code directly. - **Do not review Cursor's diff.** Review is the main Claude conversation's job. Your job ends when you hand back Cursor's report. - **Do not run `/cursor:status`, `/cursor:result`, or `/cursor:cancel` on your own.** If the main conversation wants them, it will run them itself. -- **Do not escalate models without a reason.** `composer-2-fast` is the default for a reason (speed + cost). Escalate only when the task description itself warrants it. +- **Do not escalate models without a reason.** `composer-2.5-fast` is the default for a reason (speed + cost). Escalate only when the task description itself warrants it. - **Do not impose a language policy on the target repo.** Follow whatever conventions the target repo's `AGENTS.md` / `.cursor/rules` / existing code already establishes. ## Output format Return exactly what `delegate.ts` prints. One line of your own framing is fine: -> Delegated to Cursor (`composer-2-fast`). Result below. +> Delegated to Cursor (`composer-2.5-fast`). Result below. Then Cursor's block, unedited. diff --git a/plugins/cursor/commands/delegate.md b/plugins/cursor/commands/delegate.md index d877c8d..dcd4ebc 100644 --- a/plugins/cursor/commands/delegate.md +++ b/plugins/cursor/commands/delegate.md @@ -1,5 +1,5 @@ --- -description: Delegate a coding task to the Cursor CLI agent (Composer 2 by default). +description: Delegate a coding task to the Cursor CLI agent (Composer by default). argument-hint: '[--background] [--wait] [--fresh] [--resume[=chat-id]] [--model ] [--cloud] [--no-force] [--timeout ] ' allowed-tools: Bash(node:*) --- diff --git a/plugins/cursor/package.json b/plugins/cursor/package.json index 9e2e5bc..db9a4de 100644 --- a/plugins/cursor/package.json +++ b/plugins/cursor/package.json @@ -1,7 +1,7 @@ { "name": "cursor-plugin-cc", "version": "0.3.0", - "description": "Use Cursor CLI from Claude Code to delegate coding tasks to Composer 2 and other Cursor models.", + "description": "Use Cursor CLI from Claude Code to delegate coding tasks to Composer and other Cursor models.", "type": "module", "license": "MIT", "author": { @@ -20,7 +20,7 @@ "cursor", "cursor-cli", "cursor-agent", - "composer-2", + "composer-2.5", "ai-coding", "agent-delegation" ], diff --git a/plugins/cursor/plugin.json b/plugins/cursor/plugin.json index 8a93495..72b909c 100644 --- a/plugins/cursor/plugin.json +++ b/plugins/cursor/plugin.json @@ -1,7 +1,7 @@ { "name": "cursor", "version": "0.3.0", - "description": "Hand off tasks from Claude Code to cursor-agent. Composer 2 optimised.", + "description": "Hand off tasks from Claude Code to cursor-agent. Composer-optimised.", "author": { "name": "Tomas Grasl", "url": "https://www.tomasgrasl.cz/" diff --git a/plugins/cursor/scripts/lib/cursor.mjs b/plugins/cursor/scripts/lib/cursor.mjs index 9a67080..95f047c 100644 --- a/plugins/cursor/scripts/lib/cursor.mjs +++ b/plugins/cursor/scripts/lib/cursor.mjs @@ -8,12 +8,17 @@ import { run } from './run.mjs'; // rotates these over time — `/cursor:setup --print-models` shows the live // list for the current account. Unknown ids are passed through verbatim. export const MODEL_ALIASES = { - composer: 'composer-2-fast', - 'composer-fast': 'composer-2-fast', - fast: 'composer-2-fast', + // Short shortcuts point at Cursor's current Composer line (2.5). + composer: 'composer-2.5-fast', + 'composer-fast': 'composer-2.5-fast', + fast: 'composer-2.5-fast', + 'composer-full': 'composer-2.5', + // Current Composer ids (identity — also documents the live names). + 'composer-2.5-fast': 'composer-2.5-fast', + 'composer-2.5': 'composer-2.5', + // Retired Composer ids kept as passthrough for older cursor-agent builds. 'composer-2-fast': 'composer-2-fast', 'composer-2': 'composer-2', - 'composer-full': 'composer-2', 'composer-1.5': 'composer-1.5', auto: 'auto', sonnet: 'claude-4.6-sonnet-medium', @@ -42,7 +47,7 @@ export const MODEL_ALIASES = { }; // `auto` lets Cursor pick whatever model the account is entitled to — -// safe default for users without a paid `composer-2-fast` seat. Power users +// safe default for users without a paid Composer seat. Power users // can override per-invocation via `--model ` or globally via the env var // CURSOR_PLUGIN_CC_DEFAULT_MODEL. export const DEFAULT_MODEL = 'auto'; diff --git a/plugins/cursor/tests/cursor.test.mjs b/plugins/cursor/tests/cursor.test.mjs index a79dd91..5643ddc 100644 --- a/plugins/cursor/tests/cursor.test.mjs +++ b/plugins/cursor/tests/cursor.test.mjs @@ -6,13 +6,13 @@ import { HAPPY_FIXTURE, STUB_BIN, makeTempHome } from './helpers.mjs'; describe('buildArgs', () => { it('includes the expected flags by default', () => { - const args = buildArgs({ prompt: 'hi', model: 'composer-2' }); + const args = buildArgs({ prompt: 'hi', model: 'composer-2.5' }); expect(args).toContain('-p'); expect(args).toContain('--output-format'); expect(args).toContain('stream-json'); expect(args).toContain('--trust'); expect(args).toContain('--model'); - expect(args).toContain('composer-2'); + expect(args).toContain('composer-2.5'); expect(args.at(-1)).toBe('hi'); }); @@ -51,9 +51,12 @@ describe('resolveModel', () => { }); it('maps aliases to real Cursor ids', () => { - expect(resolveModel('composer')).toBe('composer-2-fast'); - expect(resolveModel('fast')).toBe('composer-2-fast'); - expect(resolveModel('composer-2')).toBe('composer-2'); + expect(resolveModel('composer')).toBe('composer-2.5-fast'); + expect(resolveModel('composer-fast')).toBe('composer-2.5-fast'); + expect(resolveModel('fast')).toBe('composer-2.5-fast'); + expect(resolveModel('composer-full')).toBe('composer-2.5'); + expect(resolveModel('composer-2.5')).toBe('composer-2.5'); + expect(resolveModel('composer-2.5-fast')).toBe('composer-2.5-fast'); expect(resolveModel('sonnet')).toBe('claude-4.6-sonnet-medium'); expect(resolveModel('opus')).toBe('claude-opus-4-7-high'); expect(resolveModel('gpt')).toBe('gpt-5.3-codex'); @@ -61,6 +64,11 @@ describe('resolveModel', () => { expect(resolveModel('gemini')).toBe('gemini-3.1-pro'); }); + it('keeps retired Composer ids as passthrough for older cursor-agent builds', () => { + expect(resolveModel('composer-2')).toBe('composer-2'); + expect(resolveModel('composer-2-fast')).toBe('composer-2-fast'); + }); + it('defaults to auto when empty (no env override)', () => { delete process.env.CURSOR_PLUGIN_CC_DEFAULT_MODEL; expect(resolveModel(undefined)).toBe('auto'); @@ -69,7 +77,7 @@ describe('resolveModel', () => { it('honours CURSOR_PLUGIN_CC_DEFAULT_MODEL when no input is given', () => { process.env.CURSOR_PLUGIN_CC_DEFAULT_MODEL = 'composer'; - expect(resolveModel(undefined)).toBe('composer-2-fast'); + expect(resolveModel(undefined)).toBe('composer-2.5-fast'); process.env.CURSOR_PLUGIN_CC_DEFAULT_MODEL = 'some-custom-id'; expect(resolveModel('')).toBe('some-custom-id'); }); @@ -107,7 +115,7 @@ describe('runHeadless against stub binary', () => { const logPath = `${tmp.dir}/run.ndjson`; const result = await runHeadless({ prompt: 'hi', - model: 'composer-2', + model: 'composer-2.5', force: false, logPath, timeoutSec: 10, diff --git a/plugins/cursor/tests/delegate.fg.test.mjs b/plugins/cursor/tests/delegate.fg.test.mjs index fc1c516..3f09dc4 100644 --- a/plugins/cursor/tests/delegate.fg.test.mjs +++ b/plugins/cursor/tests/delegate.fg.test.mjs @@ -48,7 +48,7 @@ describe('delegate foreground', () => { expect(jobs.length).toBe(1); const job = jobs[0]; expect(job.status).toBe('done'); - expect(job.model).toBe('composer-2-fast'); + expect(job.model).toBe('composer-2.5-fast'); expect(job.cursorChatId).toBe('chat_abc123'); expect(job.filesTouched?.length ?? 0).toBeGreaterThan(0); }); diff --git a/plugins/cursor/tests/jobs.test.mjs b/plugins/cursor/tests/jobs.test.mjs index 9590e51..cdc24a9 100644 --- a/plugins/cursor/tests/jobs.test.mjs +++ b/plugins/cursor/tests/jobs.test.mjs @@ -31,7 +31,7 @@ describe('jobs registry', () => { }); it('creates, reads, and updates a job atomically', () => { - const job = createJob({ id: 'job1', repoPath: repo, prompt: 'do it', model: 'composer-2' }); + const job = createJob({ id: 'job1', repoPath: repo, prompt: 'do it', model: 'composer-2.5' }); expect(job.status).toBe('running'); const read = readJob(repo, 'job1'); expect(read?.prompt).toBe('do it');