/** * Harness status — is each harness installed, which version, is a newer one * published, and is it logged in? * * Detection reads files, env var names and the exit codes of probe commands; * it never prints or returns a secret. Login sources are labels such as * `crewly-subscription` or `macos-keychain`. * * - Claude Code: a credential Crewly stores, `CLAUDE_CODE_OAUTH_TOKEN` / * `ANTHROPIC_API_KEY` in the env, `~/.claude/.credentials.json`, or the macOS * keychain item "Claude Code-credentials" (existence only: `security * find-generic-password -s …` without `-w`/`-g`, so no secret is printed). * - Codex: `codex login status`; falls back to `$CODEX_HOME/auth.json`. * - Antigravity CLI: a Gemini key Crewly stores, else `GEMINI_API_KEY` in the * env. An account login in agy's keyring is deliberately NOT counted: * Crewly never runs agy on it (Google policy), so without a key it is * logged out as far as Crewly is concerned. * - Gemini CLI (detect only): Google-login credentials file or an API key env var. * * Latest versions come from `npm view` for npm-installed harnesses; a * script-installed harness (Antigravity) has no version feed Crewly reads, * so its latest version is null. * * @module services/harness/harness-status.service */ import { HarnessCredentialsStore } from './harness-credentials.store.js'; import { type HarnessDefinition } from './harness-registry.js'; import { type HarnessId, type HarnessLogger, type HarnessStatus, type LoginState, type RunCommand, type SystemToolStatus } from './harness.types.js'; /** * Whether an env value holds something usable as a credential. Empty, * whitespace-only, quote-only (`""`, `''` — copied unparsed from a `.env` * file) and placeholder values (`undefined`, `changeme`, `your-api-key`) do * not count: a harness must never be reported signed in on them. * * @param value - Raw env value * @returns True when the value looks like a real credential * * @example * ```ts * isUsableEnvValue(' '); // false * isUsableEnvValue('""'); // false * isUsableEnvValue('AIzaSy…'); // true * ``` */ export declare function isUsableEnvValue(value: string | undefined | null): boolean; /** Injectable dependencies. */ export interface HarnessStatusDeps { run?: RunCommand; env?: NodeJS.ProcessEnv; homeDir?: string; platform?: NodeJS.Platform; fileExists?: (file: string) => boolean; /** PATH lookup; defaults to {@link resolveExecutable} on the harness PATH */ resolveCommand?: (command: string) => string | null; credentials?: HarnessCredentialsStore; now?: () => number; logger?: HarnessLogger; } /** Installed binary facts. */ export interface InstalledInfo { installed: boolean; /** Absolute path of the binary */ path: string | null; version: string | null; } /** Login facts. */ export interface LoginInfo { loginState: LoginState; loginSource: string | null; } /** * Pull a version number out of `--version` output. * * @param output - Command output, e.g. `2.1.282 (Claude Code)` or `codex-cli 0.156.1` * @returns The version, or null */ export declare function parseVersion(output: string): string | null; /** * Compare two dotted versions numerically (pre-release suffixes ignored). * * @param a - Version * @param b - Version * @returns Positive when a > b, negative when a < b, 0 when equal * * @example * ```ts * compareVersions('2.1.282', '2.1.99'); // > 0 * ``` */ export declare function compareVersions(a: string, b: string): number; /** * Classify `codex login status` output. * * @param output - stdout + stderr (may mention a masked key; never returned) * @returns `chatgpt`, `api_key` or `codex` */ export declare function parseCodexLoginSource(output: string): string; /** Detects install, version and login state of each harness. */ export declare class HarnessStatusService { private readonly run; private readonly env; private readonly homeDir; private readonly platform; private readonly fileExists; private readonly resolveCommand; private readonly credentials; private readonly now; private readonly logger; private readonly latestCache; /** * @param deps - Injectable dependencies (all optional) */ constructor(deps?: HarnessStatusDeps); /** * Environment for probe commands (harness PATH). * * @returns Env copy */ private probeEnv; /** * Whether the binary is on PATH and which version it reports. * * @param def - Harness definition * @returns Installed facts */ getInstalledInfo(def: HarnessDefinition): Promise; /** * Latest published version (`npm view version`), cached. * * @param def - Harness definition * @returns The version, or null when npm could not be asked or the harness is not an npm package */ getLatestVersion(def: HarnessDefinition): Promise; /** Forget cached latest versions. */ clearLatestVersionCache(): void; /** * First env var (by name) that has a value. * * @param names - Candidates * @returns The name, or null */ private firstSetEnv; /** * Claude Code login detection. * * @returns Login facts */ private getClaudeLogin; /** * Whether `~/.claude.json` records an OAuth account or a primary API key. * * @param file - Config path * @returns True when an account is recorded */ private claudeConfigHasAccount; /** * Codex login detection. * * @param binary - Codex binary path, when installed * @returns Login facts */ private getCodexLogin; /** * Antigravity CLI login detection: only a Gemini API key counts. * * @returns Login facts */ private getAntigravityLogin; /** * Gemini CLI login detection (detect only). * * @returns Login facts */ private getGeminiLogin; /** * Login state of a harness. * * @param def - Harness definition * @param binary - Binary path when installed (Codex asks the binary itself) * @returns Login facts */ getLoginInfo(def: HarnessDefinition, binary: string | null): Promise; /** * Full status of one harness. * * @param id - Harness id * @returns The status * @throws Error for an unknown harness id */ getStatus(id: HarnessId): Promise; /** * Status of every harness, in registry order. * * @returns Statuses */ listStatuses(): Promise; /** * Required system tools (jq). * * @returns One entry per tool */ getSystemTools(): SystemToolStatus[]; } //# sourceMappingURL=harness-status.service.d.ts.map