Skip to content

Commit ac78f9b

Browse files
committed
Add Cursor coding agent to agent search mode
- add support for: [Pasted text] └── apps └── editor └── src └── features └── search-files └── search-modes └── perform-agent-search-mode ├── agents │ ├── antigravity.ts │ ├── claude.ts │ ├── codex.ts │ ├── cursor.ts │ └── opencode.ts ├── index.ts ├── types.ts └── utils.ts
1 parent 8c054e0 commit ac78f9b

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

  • apps/editor/src/features/search-files/search-modes/perform-agent-search-mode
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { agentic_file_search_instructions } from '@/constants/instructions'
2+
import { CodingAgent } from '../types'
3+
import { check_command_exists } from '../utils'
4+
5+
export const cursor_agent: CodingAgent = {
6+
id: 'cursor',
7+
label: 'Cursor',
8+
cmd: 'agent',
9+
is_installed: () => check_command_exists('agent'),
10+
get_documentation_url: () => 'https://cursor.com/docs/cli/headless',
11+
get_args: (query: string) => [
12+
'-p',
13+
`${agentic_file_search_instructions}\n\n${query}`,
14+
'--output-format',
15+
'stream-json',
16+
'--force'
17+
],
18+
parse_stream_line: (parsed, report_progress) => {
19+
if (parsed.type == 'tool_call') {
20+
if (parsed.subtype == 'started' || !parsed.subtype) {
21+
const tool_call = parsed.tool_call
22+
if (tool_call) {
23+
let msg = ''
24+
if (tool_call.readToolCall?.args?.path) {
25+
msg = `Reading: ${tool_call.readToolCall.args.path}`
26+
} else if (tool_call.writeToolCall?.args?.path) {
27+
msg = `Writing: ${tool_call.writeToolCall.args.path}`
28+
} else {
29+
const key = Object.keys(tool_call)[0]
30+
if (key) {
31+
const call = tool_call[key]
32+
const args = call?.args
33+
const raw_name = key.replace(/ToolCall$/, '')
34+
const formatted_name = raw_name
35+
.replace(/([A-Z])/g, '_$1')
36+
.toLowerCase()
37+
.replace(/^_/, '')
38+
39+
if (
40+
(formatted_name.includes('run') ||
41+
formatted_name.includes('command') ||
42+
formatted_name.includes('bash')) &&
43+
(args?.command || args?.cmd || args?.CommandLine)
44+
) {
45+
msg = `Running: ${args.command || args.cmd || args.CommandLine}`
46+
} else if (
47+
(formatted_name.includes('search') ||
48+
formatted_name.includes('grep') ||
49+
formatted_name.includes('find')) &&
50+
(args?.query || args?.pattern)
51+
) {
52+
msg = `Searching: ${args.query || args.pattern}`
53+
} else if (
54+
formatted_name.includes('list') &&
55+
args?.path
56+
) {
57+
msg = `Listing: ${args.path}`
58+
} else if (args?.path) {
59+
msg = `Accessing: ${args.path}`
60+
} else {
61+
msg = `Using ${formatted_name.replace(/_/g, ' ').trim()}...`
62+
}
63+
}
64+
}
65+
66+
if (msg) {
67+
if (msg.length > 60) {
68+
msg = msg.substring(0, 57) + '...'
69+
}
70+
report_progress(msg)
71+
}
72+
}
73+
}
74+
} else if (parsed.type == 'result' && parsed.result) {
75+
return {
76+
output:
77+
typeof parsed.result == 'string'
78+
? parsed.result
79+
: parsed.result.text || parsed.result.response || ''
80+
}
81+
} else if (parsed.result) {
82+
return {
83+
output:
84+
typeof parsed.result == 'string'
85+
? parsed.result
86+
: parsed.result.text || parsed.result.response || ''
87+
}
88+
} else if (parsed.type == 'assistant' && parsed.message) {
89+
const is_delta = parsed.timestamp_ms && !parsed.model_call_id
90+
if (!is_delta) {
91+
if (Array.isArray(parsed.message.content)) {
92+
const text = parsed.message.content
93+
.map((item: any) =>
94+
typeof item === 'string' ? item : item?.text || ''
95+
)
96+
.join('')
97+
if (text) {
98+
return { output: text }
99+
}
100+
} else if (typeof parsed.message.content === 'string') {
101+
return { output: parsed.message.content }
102+
} else if (typeof parsed.message === 'string') {
103+
return { output: parsed.message }
104+
}
105+
}
106+
}
107+
},
108+
parse_final_output: (parsed, current_output) => {
109+
if (parsed.type == 'result' && parsed.result) {
110+
return typeof parsed.result == 'string'
111+
? parsed.result
112+
: parsed.result.text || parsed.result.response || ''
113+
} else if (parsed.result) {
114+
return typeof parsed.result == 'string'
115+
? parsed.result
116+
: parsed.result.text || parsed.result.response || ''
117+
} else if (parsed.type == 'assistant' && parsed.message) {
118+
if (Array.isArray(parsed.message.content)) {
119+
return (
120+
parsed.message.content
121+
.map((item: any) =>
122+
typeof item === 'string' ? item : item?.text || ''
123+
)
124+
.join('') || current_output
125+
)
126+
} else if (typeof parsed.message.content === 'string') {
127+
return parsed.message.content
128+
} else if (typeof parsed.message === 'string') {
129+
return parsed.message
130+
}
131+
} else if (parsed.response) {
132+
return parsed.response
133+
} else if (parsed.text) {
134+
return parsed.text
135+
}
136+
return current_output
137+
}
138+
}

‎apps/editor/src/features/search-files/search-modes/perform-agent-search-mode/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import { prompt_for_search_term } from '../../utils/prompt-for-search-term'
1717
import { antigravity_agent } from './agents/antigravity'
1818
import { claude_agent } from './agents/claude'
1919
import { codex_agent } from './agents/codex'
20+
import { cursor_agent } from './agents/cursor'
2021
import { opencode_agent } from './agents/opencode'
2122
import { CodingAgent } from './types'
2223

2324
const AGENTS: CodingAgent[] = [
2425
antigravity_agent,
2526
codex_agent,
2627
claude_agent,
28+
cursor_agent,
2729
opencode_agent
2830
]
2931

0 commit comments

Comments
 (0)