/** * Live sign-in probe — is a harness's login actually usable right now? * * The status checks in {@link HarnessStatusService} only see whether a * credential is *stored*. For Claude Code that is not enough: an expired or * revoked login stays in the macOS keychain (and `claude auth status` keeps * saying `loggedIn: true`), so a machine whose every agent sits at * "Login expired · Please run /login" still looks logged in. The re-login * coordinator therefore confirms a suspected expiry with this probe before * telling the owner, and runs it now and then for harnesses in use so an * expiry is noticed even when no agent is running (the Air, 2026-09-30). * * - Claude Code: one tiny print-mode turn (`claude -p … --model haiku * --no-session-persistence`) in a scratch directory, with the env agents * get (a token Crewly stores is used, exactly as an agent would). Exit 0 → * `logged_in`; output that matches a login-expiry rule → `logged_out`; * anything else (network, rate limit, timeout) → `unknown`. * - Codex: `codex login status` (what the status check already asks). * * The probe never logs in or out and never prints a secret. * * @module services/harness/harness-login-probe */ import { type HarnessCredentialsStore } from './harness-credentials.store.js'; import type { HarnessId, LoginState, RunCommand } from './harness.types.js'; /** Injectable dependencies. */ export interface HarnessLoginProbeDeps { run?: RunCommand; /** Base env (default process.env) */ env?: NodeJS.ProcessEnv; homeDir?: string; /** PATH lookup of the harness binary */ resolveCommand?: (command: string) => string | null; /** Stored credentials exported to agents (Claude token / key) */ credentials?: Pick; /** Scratch directory the Claude probe runs in */ scratchDir?: string; timeoutMs?: number; } /** Result of one probe. */ export type HarnessLoginProbe = (harnessId: HarnessId) => Promise; /** * Classify the output of a Claude probe turn. * * @param result - Exit code and output * @returns The login state it proves * * @example * ```ts * classifyClaudeProbe({ code: 1, stdout: 'Not logged in · Please run /login', stderr: '' }); // 'logged_out' * ``` */ export declare function classifyClaudeProbe(result: { code: number | null; stdout: string; stderr: string; }): LoginState; /** * Build the probe. * * @param deps - Dependencies (defaults: the real CLI and stored credentials) * @returns `probe(harnessId)` → `logged_in` / `logged_out` / `unknown`; never rejects */ export declare function createHarnessLoginProbe(deps?: HarnessLoginProbeDeps): HarnessLoginProbe; //# sourceMappingURL=harness-login-probe.d.ts.map