Skip to content

feat: add support for cursor cli #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AgentAPI

Control [Claude Code](https://github.com/anthropics/claude-code), [Goose](https://github.com/block/goose), [Aider](https://github.com/Aider-AI/aider), [Gemini](https://github.com/google-gemini/gemini-cli), [Sourcegraph Amp](https://github.com/sourcegraph/amp-cli) and [Codex](https://github.com/openai/codex) with an HTTP API.
Control [Claude Code](https://github.com/anthropics/claude-code), [Goose](https://github.com/block/goose), [Aider](https://github.com/Aider-AI/aider), [Gemini](https://github.com/google-gemini/gemini-cli), [Sourcegraph Amp](https://github.com/sourcegraph/amp-cli), [Codex](https://github.com/openai/codex) and [Cursor CLI](https://cursor.com/en/cli) with an HTTP API.

![agentapi-chat](https://github.com/user-attachments/assets/57032c9f-4146-4b66-b219-09e38ab7690d)

Expand Down
2 changes: 2 additions & 0 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
AgentTypeCodex AgentType = msgfmt.AgentTypeCodex
AgentTypeGemini AgentType = msgfmt.AgentTypeGemini
AgentTypeAmp AgentType = msgfmt.AgentTypeAmp
AgentTypeCursor AgentType = msgfmt.AgentTypeCursor
AgentTypeCustom AgentType = msgfmt.AgentTypeCustom
)

Expand All @@ -40,6 +41,7 @@ var agentTypeMap = map[AgentType]bool{
AgentTypeCodex: true,
AgentTypeGemini: true,
AgentTypeAmp: true,
AgentTypeCursor: true,
AgentTypeCustom: true,
}

Expand Down
10 changes: 10 additions & 0 deletions cmd/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ func TestParseAgentType(t *testing.T) {
agentTypeVar: "",
want: AgentTypeGemini,
},
{
firstArg: "cursor",
agentTypeVar: "",
want: AgentTypeCursor,
},
{
firstArg: "amp",
agentTypeVar: "",
Expand Down Expand Up @@ -82,6 +87,11 @@ func TestParseAgentType(t *testing.T) {
agentTypeVar: "gemini",
want: AgentTypeGemini,
},
{
firstArg: "claude",
agentTypeVar: "cursor",
want: AgentTypeCursor,
},
{
firstArg: "aider",
agentTypeVar: "claude",
Expand Down
25 changes: 21 additions & 4 deletions lib/msgfmt/msgfmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ func findUserInputEndIdx(userInputStartIdx int, msg []rune, userInput []rune) in
return msgIdx
}

// skipTrailingInputBoxLine skips the next line if it contains any of the markers.
// In case of Gemini and Cursor, the user input is echoed back in a box
// This function searches for the markers passed by the caller and skips the next line if it contains all of them.
func skipTrailingInputBoxLine(lines []string, lastUserInputLineIdx *int, markers ...string) {
if *lastUserInputLineIdx+1 >= len(lines) {
return
}
line := lines[*lastUserInputLineIdx+1]
for _, m := range markers {
if !strings.Contains(line, m) {
return
}
}
*lastUserInputLineIdx++
}

// RemoveUserInput removes the user input from the message.
// Goose, Aider, and Claude Code echo back the user's input to
// make it visible in the terminal. This function makes a best effort
Expand Down Expand Up @@ -169,10 +185,8 @@ func RemoveUserInput(msgRaw string, userInputRaw string) string {
// that doesn't contain the echoed user input.
lastUserInputLineIdx := msgRuneLineLocations[userInputEndIdx]

// In case of Gemini, the user input echoed back is wrapped in a rounded box, so we remove it.
if lastUserInputLineIdx+1 < len(msgLines) && strings.Contains(msgLines[lastUserInputLineIdx+1], "╯") && strings.Contains(msgLines[lastUserInputLineIdx+1], "╰") {
lastUserInputLineIdx += 1
}
skipTrailingInputBoxLine(msgLines, &lastUserInputLineIdx, "╯", "╰") // Gemini
skipTrailingInputBoxLine(msgLines, &lastUserInputLineIdx, "┘", "└") // Cursor

return strings.Join(msgLines[lastUserInputLineIdx+1:], "\n")
}
Expand Down Expand Up @@ -207,6 +221,7 @@ const (
AgentTypeCodex AgentType = "codex"
AgentTypeGemini AgentType = "gemini"
AgentTypeAmp AgentType = "amp"
AgentTypeCursor AgentType = "cursor"
AgentTypeCustom AgentType = "custom"
)

Expand Down Expand Up @@ -238,6 +253,8 @@ func FormatAgentMessage(agentType AgentType, message string, userInput string) s
return formatGenericMessage(message, userInput)
case AgentTypeAmp:
return formatGenericMessage(message, userInput)
case AgentTypeCursor:
return formatGenericMessage(message, userInput)
case AgentTypeCustom:
return formatGenericMessage(message, userInput)
default:
Expand Down
19 changes: 19 additions & 0 deletions lib/msgfmt/testdata/format/cursor/confirmation_box/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
I'll check the repository's root, name, remotes, and current branch.




┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ $ git rev-parse --show-toplevel in . │
│ $ basename "$(git rev-parse --show-toplevel)" in . │
│ $ git remote -v in . │
│ $ git rev-parse --abbrev-ref HEAD in . │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Run this command? │
│ Not in allowlist: git │
│ → Run (y) (enter) │
│ Reject (esc or p) │
│ Add Shell(git) to allowlist? (tab) │
│ Auto-run all commands (shift+tab) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
26 changes: 26 additions & 0 deletions lib/msgfmt/testdata/format/cursor/confirmation_box/msg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Cursor Agent
~/Documents/work/agentapi · feat-cursor-cli

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Which repo is this ? │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

I'll check the repository's root, name, remotes, and current branch.




┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ $ git rev-parse --show-toplevel in . │
│ $ basename "$(git rev-parse --show-toplevel)" in . │
│ $ git remote -v in . │
│ $ git rev-parse --abbrev-ref HEAD in . │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Run this command? │
│ Not in allowlist: git │
│ → Run (y) (enter) │
│ Reject (esc or p) │
│ Add Shell(git) to allowlist? (tab) │
│ Auto-run all commands (shift+tab) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Which repo is this ?
11 changes: 11 additions & 0 deletions lib/msgfmt/testdata/format/cursor/first_message/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ⬢ Welcome to Cursor Agent Beta │
│ │
│ Cursor Agent CLI is in beta. Security safeguards are still evolving. It can read, modify, and delete files, and execute shell commands you approve. Use at your own risk and only in trusted environments. │
│ │
│ Please read about our security at https://cursor.com/security. │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘


Cursor Agent
~/Documents/work/agentapi · feat-cursor-cli
Loading