From 04f3a7c27f5736c8e8703f4e655ea6360a968c2a Mon Sep 17 00:00:00 2001 From: harshitsinghbhandari <24b4506@iitb.ac.in> Date: Thu, 9 Apr 2026 19:17:41 +0530 Subject: [PATCH] fix(cursor): register plugin in all discovery/resolution layers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address PR review feedback from #1076 to make Cursor agent fully functional. ## Changes ### Plugin Registration (High Severity Fixes) - **core/plugin-registry.ts**: Add cursor to BUILTIN_PLUGINS array for config-based resolution - **cli/plugins.ts**: Import and register cursor in agentPlugins map for getAgent/getAgentByName - **cli/detect-agent.ts**: Add cursor to AGENT_PLUGINS array for detectAvailableAgents() - **web/services.ts**: Import and register cursor plugin for dashboard SessionManager/LifecycleManager - **web/package.json**: Add @composio/ao-plugin-agent-cursor dependency ### Activity Detection Fix (Medium Severity) - **cursor/index.ts**: Remove overly broad blocked detection patterns (error:/failed:) - Compiler errors, test failures, and linter output are normal tool output - Terminal-based detection can't distinguish between actionable agent errors and normal output - Follow Aider/OpenCode pattern: only Claude Code detects blocked (has native JSONL) - Added comment explaining why blocked detection is removed - **cursor/index.test.ts**: Remove blocked detection test cases ## Why These Changes Are Needed Before these fixes: - `defaults.agent: cursor` in config would throw "Unknown agent plugin: cursor" - `ao spawn --agent cursor` would fail - Dashboard couldn't resolve cursor agent (SessionManager/LifecycleManager failures) - `detectAvailableAgents()` never discovered Cursor - False "blocked" states when agent encountered normal compiler errors After these fixes: - Cursor agent fully discoverable and usable via config and CLI - Dashboard can spawn and manage Cursor sessions - Activity detection matches other terminal-based agents (Aider, OpenCode) - No false positives from normal tool output ## Testing - ✅ cursor plugin tests: 51/51 passing (reduced from 52 due to removed blocked tests) - ✅ core typecheck: clean - ✅ web typecheck: clean - ✅ CLI can import cursor plugin without errors Addresses: ComposioHQ/agent-orchestrator#1076 Co-Authored-By: Claude Sonnet 4.5 --- packages/cli/src/lib/detect-agent.ts | 1 + packages/cli/src/lib/plugins.ts | 2 ++ packages/core/src/plugin-registry.ts | 1 + packages/plugins/agent-cursor/src/index.test.ts | 5 ----- packages/plugins/agent-cursor/src/index.ts | 9 ++++++--- packages/web/package.json | 1 + packages/web/src/lib/services.ts | 2 ++ pnpm-lock.yaml | 3 +++ 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/lib/detect-agent.ts b/packages/cli/src/lib/detect-agent.ts index b8c15bd53..87684eb9c 100644 --- a/packages/cli/src/lib/detect-agent.ts +++ b/packages/cli/src/lib/detect-agent.ts @@ -18,6 +18,7 @@ const AGENT_PLUGINS: Array<{ name: string; pkg: string }> = [ { name: "claude-code", pkg: "@composio/ao-plugin-agent-claude-code" }, { name: "aider", pkg: "@composio/ao-plugin-agent-aider" }, { name: "codex", pkg: "@composio/ao-plugin-agent-codex" }, + { name: "cursor", pkg: "@composio/ao-plugin-agent-cursor" }, { name: "opencode", pkg: "@composio/ao-plugin-agent-opencode" }, ]; diff --git a/packages/cli/src/lib/plugins.ts b/packages/cli/src/lib/plugins.ts index 215cd006c..32a8e6eec 100644 --- a/packages/cli/src/lib/plugins.ts +++ b/packages/cli/src/lib/plugins.ts @@ -2,6 +2,7 @@ import type { Agent, OrchestratorConfig, PluginRegistry, SCM } from "@composio/a import claudeCodePlugin from "@composio/ao-plugin-agent-claude-code"; import codexPlugin from "@composio/ao-plugin-agent-codex"; import aiderPlugin from "@composio/ao-plugin-agent-aider"; +import cursorPlugin from "@composio/ao-plugin-agent-cursor"; import opencodePlugin from "@composio/ao-plugin-agent-opencode"; import githubSCMPlugin from "@composio/ao-plugin-scm-github"; @@ -9,6 +10,7 @@ const agentPlugins: Record = { "claude-code": claudeCodePlugin, codex: codexPlugin, aider: aiderPlugin, + cursor: cursorPlugin, opencode: opencodePlugin, }; diff --git a/packages/core/src/plugin-registry.ts b/packages/core/src/plugin-registry.ts index 224d8a456..4d1dd7d22 100644 --- a/packages/core/src/plugin-registry.ts +++ b/packages/core/src/plugin-registry.ts @@ -38,6 +38,7 @@ const BUILTIN_PLUGINS: Array<{ slot: PluginSlot; name: string; pkg: string }> = { slot: "agent", name: "claude-code", pkg: "@composio/ao-plugin-agent-claude-code" }, { slot: "agent", name: "codex", pkg: "@composio/ao-plugin-agent-codex" }, { slot: "agent", name: "aider", pkg: "@composio/ao-plugin-agent-aider" }, + { slot: "agent", name: "cursor", pkg: "@composio/ao-plugin-agent-cursor" }, { slot: "agent", name: "opencode", pkg: "@composio/ao-plugin-agent-opencode" }, // Workspaces { slot: "workspace", name: "worktree", pkg: "@composio/ao-plugin-workspace-worktree" }, diff --git a/packages/plugins/agent-cursor/src/index.test.ts b/packages/plugins/agent-cursor/src/index.test.ts index 69fc335c0..865f75a1f 100644 --- a/packages/plugins/agent-cursor/src/index.test.ts +++ b/packages/plugins/agent-cursor/src/index.test.ts @@ -322,11 +322,6 @@ describe("detectActivity", () => { expect(agent.detectActivity("Press Enter to continue")).toBe("waiting_input"); }); - it("returns blocked for error messages", () => { - expect(agent.detectActivity("error: failed to connect")).toBe("blocked"); - expect(agent.detectActivity("failed: timeout exceeded")).toBe("blocked"); - }); - it("returns active for non-empty terminal output", () => { expect(agent.detectActivity("cursor is processing files\n")).toBe("active"); }); diff --git a/packages/plugins/agent-cursor/src/index.ts b/packages/plugins/agent-cursor/src/index.ts index 478b7cf2f..e46fa5574 100644 --- a/packages/plugins/agent-cursor/src/index.ts +++ b/packages/plugins/agent-cursor/src/index.ts @@ -178,9 +178,12 @@ function createCursorAgent(): Agent { if (/proceed\?/i.test(tail)) return "waiting_input"; if (/Press Enter to continue/i.test(tail)) return "waiting_input"; - // Check for error indicators - if (/error:/i.test(tail)) return "blocked"; - if (/failed:/i.test(tail)) return "blocked"; + // Note: "blocked" detection removed — compiler errors, test failures, and linter + // messages are extremely common in normal tool output. Unlike Claude Code (which + // has native JSONL with rich "error" types), terminal-based detection can't + // distinguish between actionable agent errors and normal tool output. + // If Cursor CLI provides native JSONL in the future, blocked detection can be + // added to getActivityState() based on JSONL entry types. return "active"; }, diff --git a/packages/web/package.json b/packages/web/package.json index 38d7d4515..64e17bfdd 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -29,6 +29,7 @@ "dependencies": { "@composio/ao-core": "workspace:*", "@composio/ao-plugin-agent-claude-code": "workspace:*", + "@composio/ao-plugin-agent-cursor": "workspace:*", "@composio/ao-plugin-agent-opencode": "workspace:*", "@composio/ao-plugin-runtime-tmux": "workspace:*", "@composio/ao-plugin-scm-github": "workspace:*", diff --git a/packages/web/src/lib/services.ts b/packages/web/src/lib/services.ts index 7715136f8..b9c947a69 100644 --- a/packages/web/src/lib/services.ts +++ b/packages/web/src/lib/services.ts @@ -39,6 +39,7 @@ import { // Static plugin imports — webpack needs these to be string literals import pluginRuntimeTmux from "@composio/ao-plugin-runtime-tmux"; import pluginAgentClaudeCode from "@composio/ao-plugin-agent-claude-code"; +import pluginAgentCursor from "@composio/ao-plugin-agent-cursor"; import pluginAgentOpencode from "@composio/ao-plugin-agent-opencode"; import pluginWorkspaceWorktree from "@composio/ao-plugin-workspace-worktree"; import pluginScmGithub from "@composio/ao-plugin-scm-github"; @@ -81,6 +82,7 @@ async function initServices(): Promise { // Register plugins explicitly (webpack can't handle dynamic import() in core) registry.register(pluginRuntimeTmux); registry.register(pluginAgentClaudeCode); + registry.register(pluginAgentCursor); registry.register(pluginAgentOpencode); registry.register(pluginWorkspaceWorktree); registry.register(pluginScmGithub); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc09d9189..060c25446 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -600,6 +600,9 @@ importers: '@composio/ao-plugin-agent-claude-code': specifier: workspace:* version: link:../plugins/agent-claude-code + '@composio/ao-plugin-agent-cursor': + specifier: workspace:* + version: link:../plugins/agent-cursor '@composio/ao-plugin-agent-opencode': specifier: workspace:* version: link:../plugins/agent-opencode