/** * API-key login for harnesses. * * - Claude Code: the Anthropic key is checked against the Anthropic API (a * 401/403 rejects it; a network problem does not block saving a * well-formed key), stored in the harness credentials store and exported * to agents as `ANTHROPIC_API_KEY`. Claude's config is updated so the key * is pre-approved (claude-config.utils). * - Codex: `codex login --with-api-key` with the key on **stdin** (never in * argv); Codex saves it in its own `auth.json`. * - Antigravity CLI: the Gemini key is checked with a models-list call to * the Gemini API (key in the `x-goog-api-key` header, never in the URL), * stored in the harness credentials store (exported to antigravity-cli * agents as `GEMINI_API_KEY`), and agy's settings are switched to the * Gemini API key provider. This is the only Antigravity login Crewly * offers: Google does not allow third-party tools to use Antigravity * account (OAuth) login. * * The key is never logged, echoed back or put in an error message. * * @module services/harness/harness-api-key.service */ import { type AntigravityProviderResult } from '../../utils/antigravity-settings.utils.js'; import { HarnessCredentialsStore } from './harness-credentials.store.js'; import { type HarnessLogger, type RunCommand } from './harness.types.js'; /** Error codes the REST layer maps to HTTP statuses. */ export type HarnessApiKeyErrorCode = 'unknown_harness' | 'unsupported' | 'invalid_key' | 'not_installed' | 'login_failed'; /** API-key login error. The message never contains the key. */ export declare class HarnessApiKeyError extends Error { readonly code: HarnessApiKeyErrorCode; /** * @param code - Machine-readable code * @param message - Human-readable message */ constructor(code: HarnessApiKeyErrorCode, message: string); } /** Result of checking a key against the provider. */ export type KeyCheckResult = 'valid' | 'invalid' | 'unverified'; /** Minimal fetch signature (injectable for tests). */ export type FetchLike = (url: string, init: { method: string; headers: Record; signal?: AbortSignal; }) => Promise<{ status: number; }>; /** Injectable dependencies. */ export interface HarnessApiKeyDeps { run?: RunCommand; fetchFn?: FetchLike; env?: NodeJS.ProcessEnv; credentials?: HarnessCredentialsStore; resolveCommand?: (command: string) => string | null; prepareClaudeConfig?: (apiKey: string) => void; /** Switches agy to the Gemini API key provider (defaults to the real ~/.gemini/antigravity-cli/settings.json) */ prepareAntigravitySettings?: () => Promise; logger?: HarnessLogger; } /** * Basic shape check shared by every provider. * * @param key - Candidate key (already trimmed) * @returns True when the length is plausible and it has no whitespace */ export declare function isPlausibleApiKey(key: string): boolean; /** Validates and stores harness API keys. */ export declare class HarnessApiKeyService { private readonly run; private readonly fetchFn; private readonly env; private readonly credentials; private readonly resolveCommand; private readonly prepareClaudeConfig; private readonly prepareAntigravitySettings; private readonly logger; /** * @param deps - Injectable dependencies (all optional) */ constructor(deps?: HarnessApiKeyDeps); /** * Validate and store an API key for a harness. * * @param harnessId - Harness id * @param rawKey - The key as pasted * @throws HarnessApiKeyError unknown_harness | unsupported | invalid_key | not_installed | login_failed */ submit(harnessId: string, rawKey: unknown): Promise; /** * Check a Gemini API key with a models-list call. * * @param key - The key (sent in the `x-goog-api-key` header) * @returns valid | invalid (400/401/403) | unverified (network error, other status) */ checkGeminiKey(key: string): Promise; /** * Validate and store the Gemini key Antigravity CLI runs with, then * switch agy to the Gemini API key provider. * * @param key - The key * @throws HarnessApiKeyError invalid_key | login_failed (agy settings file unreadable) */ private submitAntigravityKey; /** * Check an Anthropic key against the API. * * @param key - The key * @returns valid | invalid | unverified (network error, unexpected status) */ checkAnthropicKey(key: string): Promise; /** * Validate and store an Anthropic key. * * @param key - The key * @throws HarnessApiKeyError invalid_key */ private submitAnthropicKey; /** * Log Codex in with an OpenAI key (key on stdin). * * @param key - The key * @throws HarnessApiKeyError not_installed | login_failed */ private submitCodexKey; } //# sourceMappingURL=harness-api-key.service.d.ts.map