Skip to content

Commit efb402b

Browse files
committed
fix(auth): improve CLI installation check reliability
Handle various error cases when checking if CLI is installed by examining exit code and output. This prevents false positives when the command is not actually available.
1 parent b8bb402 commit efb402b

File tree

3 files changed

+21
-6
lines changed

3 files changed

+21
-6
lines changed

src/infra/engines/providers/claude/auth.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ import { metadata } from './metadata.js';
1111
*/
1212
async function isCliInstalled(command: string): Promise<boolean> {
1313
try {
14-
await execa(command, ['--version'], { timeout: 3000, reject: false });
15-
return true;
14+
const result = await execa(command, ['--version'], { timeout: 3000, reject: false });
15+
if (typeof result.exitCode === 'number' && result.exitCode === 0) return true;
16+
const out = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
17+
if (/not recognized as an internal or external command/i.test(out)) return false;
18+
if (/command not found/i.test(out)) return false;
19+
if (/No such file or directory/i.test(out)) return false;
20+
return false;
1621
} catch {
1722
return false;
1823
}

src/infra/engines/providers/codex/auth.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ async function resolveCodexHome(codexHome?: string): Promise<string> {
2121
*/
2222
async function isCliInstalled(command: string): Promise<boolean> {
2323
try {
24-
await execa(command, ['--version'], { timeout: 3000, reject: false });
25-
return true;
24+
const result = await execa(command, ['--version'], { timeout: 3000, reject: false });
25+
if (typeof result.exitCode === 'number' && result.exitCode === 0) return true;
26+
const out = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
27+
if (/not recognized as an internal or external command/i.test(out)) return false;
28+
if (/command not found/i.test(out)) return false;
29+
if (/No such file or directory/i.test(out)) return false;
30+
return false;
2631
} catch {
2732
return false;
2833
}

src/infra/engines/providers/cursor/auth.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ import { metadata } from './metadata.js';
1111
*/
1212
async function isCliInstalled(command: string): Promise<boolean> {
1313
try {
14-
await execa(command, ['--version'], { timeout: 3000, reject: false });
15-
return true;
14+
const result = await execa(command, ['--version'], { timeout: 3000, reject: false });
15+
if (typeof result.exitCode === 'number' && result.exitCode === 0) return true;
16+
const out = `${result.stdout ?? ''}\n${result.stderr ?? ''}`;
17+
if (/not recognized as an internal or external command/i.test(out)) return false;
18+
if (/command not found/i.test(out)) return false;
19+
if (/No such file or directory/i.test(out)) return false;
20+
return false;
1621
} catch {
1722
return false;
1823
}

0 commit comments

Comments
 (0)