|
13 | 13 | 'CURSOR_AGENT', |
14 | 14 | 'GEMINI_CLI', |
15 | 15 | 'CODEX_SANDBOX', |
| 16 | + 'CODEX_CI', |
16 | 17 | 'CODEX_THREAD_ID', |
17 | 18 | 'AUGMENT_AGENT', |
18 | 19 | 'OPENCODE_CLIENT', |
19 | 20 | 'OPENCODE', |
20 | 21 | 'AMP_CURRENT_THREAD_ID', |
21 | 22 | 'CLAUDECODE', |
22 | 23 | 'CLAUDE_CODE', |
| 24 | + 'CLAUDE_CODE_IS_COWORK', |
23 | 25 | 'COPILOT_MODEL', |
24 | 26 | 'COPILOT_ALLOW_ALL', |
25 | 27 | 'COPILOT_GITHUB_TOKEN', |
|
41 | 43 | 'CURSOR_AGENT', |
42 | 44 | 'GEMINI_CLI', |
43 | 45 | 'CODEX_SANDBOX', |
| 46 | + 'CODEX_CI', |
44 | 47 | 'CODEX_THREAD_ID', |
45 | 48 | 'AUGMENT_AGENT', |
46 | 49 | 'OPENCODE_CLIENT', |
47 | 50 | 'OPENCODE', |
48 | 51 | 'AMP_CURRENT_THREAD_ID', |
49 | 52 | 'CLAUDECODE', |
50 | 53 | 'CLAUDE_CODE', |
| 54 | + 'CLAUDE_CODE_IS_COWORK', |
51 | 55 | 'COPILOT_MODEL', |
52 | 56 | 'COPILOT_ALLOW_ALL', |
53 | 57 | 'COPILOT_GITHUB_TOKEN', |
|
94 | 98 | ->and($result->knownAgent())->toBe(KnownAgent::Copilot); |
95 | 99 | }); |
96 | 100 |
|
| 101 | +it('detects v0 via AI_AGENT', function (): void { |
| 102 | + putenv('AI_AGENT=v0'); |
| 103 | + |
| 104 | + $result = AgentDetector::detect(); |
| 105 | + |
| 106 | + expect($result->isAgent)->toBeTrue() |
| 107 | + ->and($result->name)->toBe('v0') |
| 108 | + ->and($result->knownAgent())->toBe(KnownAgent::V0); |
| 109 | +}); |
| 110 | + |
97 | 111 | it('does not detect an agent when AI_AGENT is not set', function (): void { |
98 | 112 | $result = AgentDetector::detect(); |
99 | 113 |
|
|
132 | 146 | ->and($result->knownAgent())->toBe(KnownAgent::Codex); |
133 | 147 | }); |
134 | 148 |
|
| 149 | +it('detects codex via CODEX_CI', function (): void { |
| 150 | + putenv('CODEX_CI=true'); |
| 151 | + |
| 152 | + $result = AgentDetector::detect(); |
| 153 | + |
| 154 | + expect($result->isAgent)->toBeTrue() |
| 155 | + ->and($result->name)->toBe('codex') |
| 156 | + ->and($result->knownAgent())->toBe(KnownAgent::Codex); |
| 157 | +}); |
| 158 | + |
135 | 159 | it('detects codex via CODEX_THREAD_ID', function (): void { |
136 | 160 | putenv('CODEX_THREAD_ID=some-thread-id'); |
137 | 161 |
|
|
202 | 226 | ->and($result->knownAgent())->toBe(KnownAgent::Claude); |
203 | 227 | }); |
204 | 228 |
|
| 229 | +it('detects cowork via Claude Code cowork env vars', function (): void { |
| 230 | + putenv('CLAUDE_CODE=1'); |
| 231 | + putenv('CLAUDE_CODE_IS_COWORK=1'); |
| 232 | + |
| 233 | + $result = AgentDetector::detect(); |
| 234 | + |
| 235 | + expect($result->isAgent)->toBeTrue() |
| 236 | + ->and($result->name)->toBe('cowork') |
| 237 | + ->and($result->knownAgent())->toBe(KnownAgent::Cowork); |
| 238 | +}); |
| 239 | + |
| 240 | +it('does not detect cowork without Claude Code', function (): void { |
| 241 | + putenv('CLAUDE_CODE_IS_COWORK=1'); |
| 242 | + |
| 243 | + $GLOBALS['__mock_file_exists'] = fn (string $path): bool => false; |
| 244 | + |
| 245 | + $result = AgentDetector::detect(); |
| 246 | + |
| 247 | + expect($result->isAgent)->toBeFalse() |
| 248 | + ->and($result->name)->toBeNull(); |
| 249 | +}); |
| 250 | + |
205 | 251 | it('detects copilot via COPILOT_MODEL', function (): void { |
206 | 252 | putenv('COPILOT_MODEL=gpt-5.2'); |
207 | 253 |
|
|
303 | 349 | }); |
304 | 350 |
|
305 | 351 | // Priority order |
306 | | -it('prioritizes AI_AGENT over CURSOR_TRACE_ID', function (): void { |
| 352 | +it('prioritizes AI_AGENT over CURSOR_AGENT', function (): void { |
307 | 353 | putenv('AI_AGENT=custom'); |
308 | | - putenv('CURSOR_TRACE_ID=trace'); |
309 | | - |
310 | | - $result = AgentDetector::detect(); |
311 | | - |
312 | | - expect($result->name)->toBe('custom'); |
313 | | -}); |
314 | | - |
315 | | -it('prioritizes CURSOR_TRACE_ID over CURSOR_AGENT', function (): void { |
316 | | - putenv('CURSOR_TRACE_ID=trace'); |
317 | 354 | putenv('CURSOR_AGENT=true'); |
318 | 355 |
|
319 | 356 | $result = AgentDetector::detect(); |
320 | 357 |
|
321 | | - expect($result->name)->toBe('cursor'); |
| 358 | + expect($result->name)->toBe('custom'); |
322 | 359 | }); |
323 | 360 |
|
324 | 361 | it('prioritizes CURSOR_AGENT over CLAUDECODE', function (): void { |
|
390 | 427 | 'cursor' => ['CURSOR_AGENT', '1', KnownAgent::Cursor], |
391 | 428 | 'gemini' => ['GEMINI_CLI', 'true', KnownAgent::Gemini], |
392 | 429 | 'codex' => ['CODEX_SANDBOX', 'true', KnownAgent::Codex], |
| 430 | + 'codex ci' => ['CODEX_CI', 'true', KnownAgent::Codex], |
| 431 | + 'v0' => ['AI_AGENT', 'v0', KnownAgent::V0], |
393 | 432 | 'augment-cli' => ['AUGMENT_AGENT', 'true', KnownAgent::AugmentCli], |
394 | 433 | 'opencode' => ['OPENCODE_CLIENT', 'true', KnownAgent::Opencode], |
395 | 434 | 'amp' => ['AMP_CURRENT_THREAD_ID', 'thread-id', KnownAgent::Amp], |
|
0 commit comments