|
1 | | -import { describe, expect, it } from 'vitest'; |
| 1 | +import { afterEach, describe, expect, it, vi } from 'vitest'; |
2 | 2 |
|
3 | 3 | import { detectAgent } from './detect-agent'; |
4 | 4 |
|
5 | 5 | describe('detectAgent', () => { |
6 | | - it('detects amp via AGENT=amp (highest precedence)', () => { |
7 | | - expect( |
8 | | - detectAgent({ |
9 | | - stdoutIsTTY: true, |
10 | | - env: { |
11 | | - AGENT: 'amp', |
12 | | - CLAUDECODE: '1', |
13 | | - GEMINI_CLI: '1', |
14 | | - CODEX_SANDBOX: '1', |
15 | | - CURSOR_AGENT: '1', |
16 | | - }, |
17 | | - }) |
18 | | - ).toEqual({ name: 'amp' }); |
| 6 | + afterEach(() => { |
| 7 | + vi.unstubAllEnvs(); |
| 8 | + }); |
19 | 9 |
|
20 | | - expect( |
21 | | - detectAgent({ |
22 | | - stdoutIsTTY: true, |
23 | | - env: { |
24 | | - CLAUDECODE: '1', |
25 | | - GEMINI_CLI: '1', |
26 | | - CODEX_SANDBOX: '1', |
27 | | - CURSOR_AGENT: '1', |
28 | | - AGENT: 'something', |
29 | | - }, |
30 | | - }) |
31 | | - ).toEqual({ name: 'claude-code' }); |
| 10 | + it('detects claude via CLAUDECODE', () => { |
| 11 | + vi.stubEnv('CLAUDECODE', '1'); |
| 12 | + expect(detectAgent()).toEqual({ name: 'claude' }); |
32 | 13 | }); |
33 | 14 |
|
34 | | - it('detects Gemini CLI via GEMINI_CLI', () => { |
35 | | - expect(detectAgent({ stdoutIsTTY: true, env: { GEMINI_CLI: '1' } })).toEqual({ |
36 | | - name: 'gemini-cli', |
37 | | - }); |
| 15 | + it('detects claude via CLAUDE_CODE', () => { |
| 16 | + vi.stubEnv('CLAUDE_CODE', '1'); |
| 17 | + expect(detectAgent()).toEqual({ name: 'claude' }); |
38 | 18 | }); |
39 | 19 |
|
40 | | - it('detects OpenAI Codex via CODEX_SANDBOX', () => { |
41 | | - expect(detectAgent({ stdoutIsTTY: true, env: { CODEX_SANDBOX: '1' } })).toEqual({ |
42 | | - name: 'codex', |
43 | | - }); |
| 20 | + it('detects gemini via GEMINI_CLI', () => { |
| 21 | + vi.stubEnv('GEMINI_CLI', '1'); |
| 22 | + expect(detectAgent()).toEqual({ name: 'gemini' }); |
44 | 23 | }); |
45 | 24 |
|
46 | | - it('detects Cursor Agent via CURSOR_AGENT (even if AGENT is also set)', () => { |
47 | | - expect( |
48 | | - detectAgent({ stdoutIsTTY: true, env: { CURSOR_AGENT: '1', AGENT: 'something' } }) |
49 | | - ).toEqual({ |
50 | | - name: 'cursor', |
51 | | - }); |
| 25 | + it('detects codex via CODEX_SANDBOX', () => { |
| 26 | + vi.stubEnv('CODEX_SANDBOX', '1'); |
| 27 | + expect(detectAgent()).toEqual({ name: 'codex' }); |
52 | 28 | }); |
53 | 29 |
|
54 | | - it('treats generic AGENT as unknown', () => { |
55 | | - expect(detectAgent({ stdoutIsTTY: true, env: { AGENT: 'some-agent' } })).toEqual({ |
56 | | - name: 'unknown', |
57 | | - }); |
| 30 | + it('detects codex via CODEX_THREAD_ID', () => { |
| 31 | + vi.stubEnv('CODEX_THREAD_ID', '1'); |
| 32 | + expect(detectAgent()).toEqual({ name: 'codex' }); |
58 | 33 | }); |
59 | 34 |
|
60 | | - it('does not use heuristics when stdout is a TTY', () => { |
61 | | - expect(detectAgent({ stdoutIsTTY: true, env: { TERM: 'dumb' } })).toEqual(undefined); |
62 | | - expect(detectAgent({ stdoutIsTTY: true, env: { GIT_PAGER: 'cat' } })).toEqual(undefined); |
| 35 | + it('detects cursor via CURSOR_AGENT', () => { |
| 36 | + vi.stubEnv('CURSOR_AGENT', '1'); |
| 37 | + expect(detectAgent()).toEqual({ name: 'cursor' }); |
63 | 38 | }); |
64 | 39 |
|
65 | | - it('detects unknown agent via TERM=dumb when stdout is not a TTY', () => { |
66 | | - expect(detectAgent({ stdoutIsTTY: false, env: { TERM: 'dumb' } })).toEqual({ |
67 | | - name: 'unknown', |
68 | | - }); |
| 40 | + it('detects opencode via OPENCODE', () => { |
| 41 | + vi.stubEnv('OPENCODE', '1'); |
| 42 | + expect(detectAgent()).toEqual({ name: 'opencode' }); |
69 | 43 | }); |
70 | 44 |
|
71 | | - it('detects unknown agent via GIT_PAGER=cat when stdout is not a TTY', () => { |
72 | | - expect(detectAgent({ stdoutIsTTY: false, env: { GIT_PAGER: 'cat' } })).toEqual({ |
73 | | - name: 'unknown', |
74 | | - }); |
| 45 | + it('detects explicit agent via AI_AGENT env var', () => { |
| 46 | + vi.stubEnv('AI_AGENT', 'copilot'); |
| 47 | + expect(detectAgent()).toEqual({ name: 'copilot' }); |
75 | 48 | }); |
76 | 49 |
|
77 | | - it('returns isAgent=false when there are no signals', () => { |
78 | | - expect(detectAgent({ stdoutIsTTY: false, env: {} })).toEqual(undefined); |
| 50 | + it('normalizes AI_AGENT to lowercase', () => { |
| 51 | + vi.stubEnv('AI_AGENT', 'Copilot'); |
| 52 | + expect(detectAgent()).toEqual({ name: 'copilot' }); |
79 | 53 | }); |
80 | 54 |
|
81 | | - it('applies heuristics even when CI is set (no CI special-casing)', () => { |
82 | | - expect( |
83 | | - detectAgent({ |
84 | | - stdoutIsTTY: false, |
85 | | - env: { CI: 'true', TERM: 'dumb' }, |
86 | | - }) |
87 | | - ).toEqual({ name: 'unknown' }); |
| 55 | + it('AI_AGENT takes precedence over other env vars', () => { |
| 56 | + vi.stubEnv('AI_AGENT', 'copilot'); |
| 57 | + vi.stubEnv('CLAUDECODE', '1'); |
| 58 | + vi.stubEnv('GEMINI_CLI', '1'); |
| 59 | + expect(detectAgent()).toEqual({ name: 'copilot' }); |
88 | 60 | }); |
89 | 61 |
|
90 | | - it('still detects explicit agents in CI', () => { |
91 | | - expect(detectAgent({ stdoutIsTTY: false, env: { CI: 'true', CODEX_SANDBOX: '1' } })).toEqual({ |
92 | | - name: 'codex', |
93 | | - }); |
| 62 | + it('returns undefined when there are no signals', () => { |
| 63 | + expect(detectAgent()).toEqual(undefined); |
94 | 64 | }); |
95 | 65 | }); |
0 commit comments