Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 5x 4x 4x 3x 3x 2x 1x 3x | import { ExecError, execFileNonInteractive } from '../utils/exec.js';
import { WardenAuthenticationError } from './errors.js';
/**
* Pre-flight auth check: verify that authentication will work before starting analysis.
*
* - If an API key is provided, returns immediately (direct API auth).
* - If no API key, verifies the `claude` binary exists on PATH so the SDK
* can use local Claude Code auth. Throws WardenAuthenticationError
* if the binary is missing.
*
* This catches the most common failure mode (binary not installed) early.
* Subtler failures (binary exists but sandbox blocks IPC) are caught by the
* isSubprocessError() handler in analyzeHunk().
*/
export function verifyAuth({ apiKey }: { apiKey?: string }): void {
// Direct API auth — no subprocess needed
if (apiKey) return;
try {
execFileNonInteractive('claude', ['--version'], { timeout: 5000 });
} catch (error) {
// execFileNonInteractive wraps spawn failures in ExecError.
// The original error message (e.g., "spawn claude ENOENT") is in ExecError.stderr.
const isNotFound =
error instanceof ExecError
? error.stderr.includes('ENOENT')
: (error as NodeJS.ErrnoException).code === 'ENOENT';
if (isNotFound) {
throw new WardenAuthenticationError(
'Claude Code CLI not found on PATH.\n' +
'Either install Claude Code (https://claude.ai/install.sh) or set an API key.',
{ cause: error }
);
}
const detail =
error instanceof ExecError ? error.stderr : (error as Error).message;
throw new WardenAuthenticationError(
`Claude Code CLI found but failed to execute: ${detail}\n` +
'Check that the claude binary has correct permissions and can run in this environment.',
{ cause: error }
);
}
}
|