rename cursor to cursor agent (vibe-kanban) (#1072)

* Done! I've successfully renamed "Cursor" to "Cursor Agent" throughout the codebase. The changes include:

- Renamed the Rust struct from `Cursor` to `CursorAgent` in [crates/executors/src/executors/cursor.rs](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/crates/executors/src/executors/cursor.rs)
- Updated the enum variant in [crates/executors/src/executors/mod.rs](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/crates/executors/src/executors/mod.rs) with proper serialization attributes
- Updated documentation in [docs/supported-coding-agents.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/supported-coding-agents.mdx) and [docs/index.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/index.mdx)
- Regenerated TypeScript types
- All type checks pass (frontend and backend)

The serialization still uses "CURSOR" for backwards compatibility, but the struct is now named `CursorAgent` in Rust, making it clear this refers to the Cursor Agent CLI tool.

* Perfect! All checks pass. The renaming is complete. The struct is now `CursorAgent` everywhere, serializing as `CURSOR_AGENT`.

* Perfect! Done. I've reverted all internal code changes and kept only the user-facing documentation updates:

**What remains changed (user-visible):**
- [docs/supported-coding-agents.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/supported-coding-agents.mdx) - Title changed from "Cursor CLI" to "Cursor Agent CLI"
- [docs/index.mdx](file:///private/var/folders/5q/5vgq75y92dz0k7n62z93299r0000gn/T/vibe-kanban/worktrees/51f5-rename-cursor-to/docs/index.mdx) - "Cursor CLI" changed to "Cursor Agent CLI"

**What was reverted (internal, not user-visible):**
- All Rust struct/enum names back to `Cursor`
- All serialization formats back to `CURSOR`
- TypeScript types back to `CURSOR`
- JSON config files back to `CURSOR`

All checks pass 

* Perfect! Now users will see "CURSOR_AGENT" in the UI when selecting agents, while the code stays clean with the `Cursor` struct name, and documentation still says "Cursor CLI". All checks pass 

**What changed (user-visible in UI):**
- Agent selection dropdowns show "CURSOR_AGENT" instead of "CURSOR"
- JSON configs use "CURSOR_AGENT"
- MCP server documentation shows `cursor_agent` / `CURSOR_AGENT`

**What stayed the same:**
- Rust code uses `Cursor` struct name internally (clean code)
- User-facing documentation still says "Cursor CLI" (no doc changes needed)

* Perfect! Now it's backwards compatible. The `#[serde(alias = "CURSOR")]` attribute means:

 **Backwards Compatible:**
- Old configs with `"CURSOR"` will still deserialize correctly
- New configs with `"CURSOR_AGENT"` also work
- All serialization (saving configs) uses the new `"CURSOR_AGENT"` format

**Summary of changes:**
- Users see "CURSOR_AGENT" in the UI dropdown
- New configs are saved with "CURSOR_AGENT"
- Old configs with "CURSOR" continue to work
- Code internally still uses clean `Cursor` struct name
- All checks pass 

* Perfect!  Now it's fully backwards compatible:

**What works:**
-  Old configs with `"CURSOR"` deserialize correctly (via `alias`)
-  New configs with `"CURSOR_AGENT"` deserialize correctly
-  All new saves use `"CURSOR_AGENT"` (via `rename`)
-  The discriminant enum `BaseCodingAgent` also accepts both formats
-  Users see "CURSOR_AGENT" in the UI
-  All type checks pass

The `#[strum_discriminants(serde(rename = "CURSOR_AGENT", alias = "CURSOR"))]` ensures both the full enum AND the discriminant enum accept both old and new formats.

* Perfect!  Now `cursor_agent.json` exists and the Vite plugin will create the key `CURSOR_AGENT`, which matches what the frontend expects.

* cursor agent | fix (vibe-kanban 6594df22)

http://localhost:3044/api/task-attempts

This fails

Payload:
{"task_id":"18fdd148-5049-4772-9385-6d9196087524","executor_profile_id":{"executor":"CURSOR_AGENT","variant":null},"base_branch":"main"}

Response: Failed to deserialize the JSON body into the target type: executor_profile_id.executor: unknown executor 'CURSOR_AGENT' (normalized to 'CURSOR_AGENT') at line 1 column 98

Check the diff of this branch vs main to understand what we've been trying to do (users should see CURSOR_AGENT instead of CURSOR)

Server log:
[0] 2025-10-23T08:38:00.475636Z DEBUG server::routes::tasks: Creating task 'hey' in project f8c8d410-fd1b-48a4-829a-a6bf4b550a62

* rename CodingAgent::Cursor -> CodingAgent::CursorAgent

* update types
This commit is contained in:
Britannio Jarrett
2025-10-27 10:24:53 +00:00
committed by GitHub
parent e160571f67
commit 074199f2d2
14 changed files with 62 additions and 37 deletions

View File

@@ -69,39 +69,39 @@
}
}
},
"CURSOR": {
"CURSOR_AGENT": {
"DEFAULT": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "auto"
}
},
"SONNET_4_5": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "sonnet-4.5"
}
},
"SONNET_4_5_THINKING": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "sonnet-4.5-thinking"
}
},
"OPUS_4_1": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "opus-4.1"
}
},
"GPT_5": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "gpt-5"
}
},
"GROK": {
"CURSOR": {
"CURSOR_AGENT": {
"force": true,
"model": "grok"
}

View File

@@ -32,7 +32,7 @@ use crate::{
mod mcp;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS, JsonSchema)]
pub struct Cursor {
pub struct CursorAgent {
#[serde(default)]
pub append_prompt: AppendPrompt,
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -45,7 +45,7 @@ pub struct Cursor {
pub cmd: CmdOverrides,
}
impl Cursor {
impl CursorAgent {
fn build_command_builder(&self) -> CommandBuilder {
let mut builder =
CommandBuilder::new("cursor-agent").params(["-p", "--output-format=stream-json"]);
@@ -63,7 +63,7 @@ impl Cursor {
}
#[async_trait]
impl StandardCodingAgentExecutor for Cursor {
impl StandardCodingAgentExecutor for CursorAgent {
async fn spawn(&self, current_dir: &Path, prompt: &str) -> Result<SpawnedChild, ExecutorError> {
mcp::ensure_mcp_server_trust(self, current_dir).await;
@@ -178,7 +178,7 @@ impl StandardCodingAgentExecutor for Cursor {
// Provide a useful sign-in message if needed
let line = if line == "Press any key to sign in..." {
"Please sign in to Cursor CLI using `cursor-agent login` or set the CURSOR_API_KEY environment variable.".to_string()
"Please sign in to Cursor Agent CLI using `cursor-agent login` or set the CURSOR_API_KEY environment variable.".to_string()
} else {
line
};
@@ -1182,7 +1182,7 @@ mod tests {
#[tokio::test]
async fn test_cursor_streaming_patch_generation() {
// Avoid relying on feature flag in tests; construct with a dummy command
let executor = Cursor {
let executor = CursorAgent {
// No command field needed anymore
append_prompt: AppendPrompt::default(),
force: None,

View File

@@ -4,10 +4,10 @@ use sha2::{Digest, Sha256};
use tokio::fs;
use tracing::warn;
use super::Cursor;
use super::CursorAgent;
use crate::executors::{CodingAgent, ExecutorError, StandardCodingAgentExecutor};
pub async fn ensure_mcp_server_trust(cursor: &Cursor, current_dir: &Path) {
pub async fn ensure_mcp_server_trust(cursor: &CursorAgent, current_dir: &Path) {
if let Err(err) = ensure_mcp_server_trust_impl(cursor, current_dir).await {
tracing::warn!(
error = %err,
@@ -17,7 +17,7 @@ pub async fn ensure_mcp_server_trust(cursor: &Cursor, current_dir: &Path) {
}
async fn ensure_mcp_server_trust_impl(
cursor: &Cursor,
cursor: &CursorAgent,
current_dir: &Path,
) -> Result<(), ExecutorError> {
let current_dir =
@@ -166,7 +166,7 @@ fn compute_cursor_approval_id(
Some(format!("{server_name}-{}", &hex[..16]))
}
fn default_cursor_mcp_servers(cursor: &Cursor) -> serde_json::Value {
let mcpc = CodingAgent::Cursor(cursor.clone()).get_mcp_config();
fn default_cursor_mcp_servers(cursor: &CursorAgent) -> serde_json::Value {
let mcpc = CodingAgent::CursorAgent(cursor.clone()).get_mcp_config();
serde_json::json!({ "mcpServers": mcpc.preconfigured })
}

View File

@@ -15,7 +15,7 @@ use workspace_utils::msg_store::MsgStore;
use crate::{
approvals::ExecutorApprovalService,
executors::{
amp::Amp, claude::ClaudeCode, codex::Codex, copilot::Copilot, cursor::Cursor,
amp::Amp, claude::ClaudeCode, codex::Codex, copilot::Copilot, cursor::CursorAgent,
gemini::Gemini, opencode::Opencode, qwen::QwenCode,
},
mcp_config::McpConfig,
@@ -78,7 +78,9 @@ pub enum CodingAgent {
Gemini,
Codex,
Opencode,
Cursor,
#[serde(alias = "CURSOR")]
#[strum_discriminants(strum(serialize = "CURSOR", serialize = "CURSOR_AGENT"))]
CursorAgent,
QwenCode,
Copilot,
}
@@ -133,7 +135,7 @@ impl CodingAgent {
Self::Codex(_) => vec![BaseAgentCapability::SessionFork],
Self::Gemini(_) => vec![BaseAgentCapability::SessionFork],
Self::QwenCode(_) => vec![BaseAgentCapability::SessionFork],
Self::Opencode(_) | Self::Cursor(_) | Self::Copilot(_) => vec![],
Self::Opencode(_) | Self::CursorAgent(_) | Self::Copilot(_) => vec![],
}
}
}
@@ -204,3 +206,26 @@ impl AppendPrompt {
}
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::*;
#[test]
fn test_cursor_agent_deserialization() {
// Test that CURSOR_AGENT is accepted
let result = BaseCodingAgent::from_str("CURSOR_AGENT");
assert!(result.is_ok(), "CURSOR_AGENT should be valid");
assert_eq!(result.unwrap(), BaseCodingAgent::CursorAgent);
// Test that legacy CURSOR is still accepted for backwards compatibility
let result = BaseCodingAgent::from_str("CURSOR");
assert!(
result.is_ok(),
"CURSOR should be valid for backwards compatibility"
);
assert_eq!(result.unwrap(), BaseCodingAgent::CursorAgent);
}
}

View File

@@ -295,7 +295,7 @@ impl CodingAgent {
let adapter = match self {
CodingAgent::ClaudeCode(_) | CodingAgent::Amp(_) => Passthrough,
CodingAgent::QwenCode(_) | CodingAgent::Gemini(_) => Gemini,
CodingAgent::Cursor(_) => Cursor,
CodingAgent::CursorAgent(_) => Cursor,
CodingAgent::Codex(_) => Codex,
CodingAgent::Opencode(_) => Opencode,
CodingAgent::Copilot(..) => Copilot,

View File

@@ -83,7 +83,7 @@ fn generate_types_content() -> String {
executors::executors::codex::ReasoningEffort::decl(),
executors::executors::codex::ReasoningSummary::decl(),
executors::executors::codex::ReasoningSummaryFormat::decl(),
executors::executors::cursor::Cursor::decl(),
executors::executors::cursor::CursorAgent::decl(),
executors::executors::copilot::Copilot::decl(),
executors::executors::opencode::Opencode::decl(),
executors::executors::qwen::QwenCode::decl(),
@@ -180,8 +180,8 @@ fn generate_schemas() -> Result<HashMap<&'static str, String>, serde_json::Error
generate_json_schema::<executors::executors::codex::Codex>()?,
),
(
"cursor",
generate_json_schema::<executors::executors::cursor::Cursor>()?,
"cursor_agent",
generate_json_schema::<executors::executors::cursor::CursorAgent>()?,
),
(
"opencode",

View File

@@ -203,7 +203,7 @@ pub struct StartTaskAttemptRequest {
#[schemars(description = "The ID of the task to start")]
pub task_id: Uuid,
#[schemars(
description = "The coding agent executor to run ('CLAUDE_CODE', 'CODEX', 'GEMINI', 'CURSOR', 'OPENCODE')"
description = "The coding agent executor to run ('CLAUDE_CODE', 'CODEX', 'GEMINI', 'CURSOR_AGENT', 'OPENCODE')"
)]
pub executor: String,
#[schemars(description = "Optional executor variant, if needed")]

View File

@@ -1,11 +1,11 @@
---
title: "Cursor CLI"
title: "Cursor Agent CLI"
description: "Set up Cursor's command-line agent"
icon: https://www.vibekanban.com/images/logos/cursor-logo-light.png
---
<Steps>
<Step title="Install Cursor CLI">
<Step title="Install Cursor Agent CLI">
```bash
curl https://cursor.com/install -fsS | bash
```
@@ -24,6 +24,6 @@ icon: https://www.vibekanban.com/images/logos/cursor-logo-light.png
npx vibe-kanban
```
You can now select Cursor CLI when creating task attempts.
You can now select Cursor Agent CLI when creating task attempts.
</Step>
</Steps>

View File

@@ -20,7 +20,7 @@ Vibe Kanban is an **orchestration platform for AI coding agents** that helps dev
</Card>
<Card title="Multi-Agent Support" icon="users">
Switch between Claude Code, OpenAI Codex, Amp, Cursor CLI, Gemini, and other agents without changing workflows.
Switch between Claude Code, OpenAI Codex, Amp, Cursor Agent CLI, Gemini, and other agents without changing workflows.
</Card>
<Card title="Visual Code Review" icon="code-compare">

View File

@@ -85,7 +85,7 @@ When using `start_task_attempt`, the following executors are supported (case-ins
- `gemini` / `GEMINI`
- `codex` / `CODEX`
- `opencode` / `OPENCODE`
- `cursor` / `CURSOR`
- `cursor_agent` / `CURSOR_AGENT`
- `qwen-code` / `QWEN_CODE`
- `copilot` / `COPILOT`

View File

@@ -28,8 +28,8 @@ Google Gemini CLI
Amp Code
</Card>
<Card title="Cursor CLI" icon="https://www.vibekanban.com/images/logos/cursor-logo-light.png" href="/agents/cursor-cli">
Cursor CLI agent
<Card title="Cursor Agent CLI" icon="https://www.vibekanban.com/images/logos/cursor-logo-light.png" href="/agents/cursor-cli">
Cursor Agent CLI
</Card>
<Card title="OpenCode" icon="https://www.vibekanban.com/images/logos/opencode-light.svg" href="/agents/opencode">

View File

@@ -15,7 +15,7 @@ type ExecutorType =
| 'CLAUDE_CODE'
| 'GEMINI'
| 'CODEX'
| 'CURSOR'
| 'CURSOR_AGENT'
| 'COPILOT'
| 'OPENCODE'
| 'QWEN_CODE';

View File

@@ -30,9 +30,9 @@ export type ScriptRequest = { script: string, language: ScriptRequestLanguage, c
export type ScriptRequestLanguage = "Bash";
export enum BaseCodingAgent { CLAUDE_CODE = "CLAUDE_CODE", AMP = "AMP", GEMINI = "GEMINI", CODEX = "CODEX", OPENCODE = "OPENCODE", CURSOR = "CURSOR", QWEN_CODE = "QWEN_CODE", COPILOT = "COPILOT" }
export enum BaseCodingAgent { CLAUDE_CODE = "CLAUDE_CODE", AMP = "AMP", GEMINI = "GEMINI", CODEX = "CODEX", OPENCODE = "OPENCODE", CURSOR_AGENT = "CURSOR_AGENT", QWEN_CODE = "QWEN_CODE", COPILOT = "COPILOT" }
export type CodingAgent = { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR": Cursor } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot };
export type CodingAgent = { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR_AGENT": CursorAgent } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot };
export type Tag = { id: string, tag_name: string, content: string, created_at: string, updated_at: string, };
@@ -154,7 +154,7 @@ executor: BaseCodingAgent,
*/
variant: string | null, };
export type ExecutorConfig = { [key in string]?: { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR": Cursor } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot } };
export type ExecutorConfig = { [key in string]?: { "CLAUDE_CODE": ClaudeCode } | { "AMP": Amp } | { "GEMINI": Gemini } | { "CODEX": Codex } | { "OPENCODE": Opencode } | { "CURSOR_AGENT": CursorAgent } | { "QWEN_CODE": QwenCode } | { "COPILOT": Copilot } };
export type BaseAgentCapability = "SESSION_FORK";
@@ -178,7 +178,7 @@ export type ReasoningSummary = "auto" | "concise" | "detailed" | "none";
export type ReasoningSummaryFormat = "none" | "experimental";
export type Cursor = { append_prompt: AppendPrompt, force?: boolean | null, model?: string | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type CursorAgent = { append_prompt: AppendPrompt, force?: boolean | null, model?: string | null, base_command_override?: string | null, additional_params?: Array<string> | null, };
export type Copilot = { append_prompt: AppendPrompt, model?: string | null, allow_all_tools?: boolean | null, allow_tool?: string | null, deny_tool?: string | null, add_dir?: Array<string> | null, disable_mcp_server?: Array<string> | null, base_command_override?: string | null, additional_params?: Array<string> | null, };