()
| 175 | } |
| 176 | |
| 177 | async function runCursorModelProbe(): Promise<ListCursorModelsResponse> { |
| 178 | if (isAgentAcpTransportActive()) { |
| 179 | throw new Error('Cursor ACP transport is active'); |
| 180 | } |
| 181 | |
| 182 | return await new Promise((resolve, reject) => { |
| 183 | const child = spawn('agent', ['--list-models'], { |
| 184 | env: process.env, |
| 185 | stdio: ['ignore', 'pipe', 'pipe'], |
| 186 | shell: process.platform === 'win32', |
| 187 | windowsHide: process.platform === 'win32' |
| 188 | }); |
| 189 | let stdout = ''; |
| 190 | let stderr = ''; |
| 191 | let settled = false; |
| 192 | |
| 193 | const timeout = setTimeout(() => { |
| 194 | if (settled) return; |
| 195 | settled = true; |
| 196 | child.kill('SIGTERM'); |
| 197 | reject(new Error('Cursor model discovery timed out')); |
| 198 | }, PROBE_TIMEOUT_MS); |
| 199 | |
| 200 | child.stdout?.on('data', (chunk) => { |
| 201 | stdout += chunk.toString(); |
| 202 | }); |
| 203 | child.stderr?.on('data', (chunk) => { |
| 204 | stderr += chunk.toString(); |
| 205 | }); |
| 206 | child.on('error', (error) => { |
| 207 | if (settled) return; |
| 208 | settled = true; |
| 209 | clearTimeout(timeout); |
| 210 | reject(error); |
| 211 | }); |
| 212 | child.on('exit', (code) => { |
| 213 | if (settled) return; |
| 214 | settled = true; |
| 215 | clearTimeout(timeout); |
| 216 | if (code !== 0) { |
| 217 | reject(new Error(stderr.trim() || `agent --list-models exited with code ${code}`)); |
| 218 | return; |
| 219 | } |
| 220 | |
| 221 | resolve({ |
| 222 | success: true, |
| 223 | ...parseCursorModelsOutput(stdout) |
| 224 | }); |
| 225 | }); |
| 226 | }); |
| 227 | } |
| 228 | |
| 229 | async function applyInMemoryCache(response: ListCursorModelsResponse): Promise<ListCursorModelsResponse> { |
| 230 | const enriched = await enrichCursorModelsWithCliSkus(response); |
no test coverage detected