/** * ProviderHealthLive - Startup-time provider health checks. * * Performs one-time provider readiness probes when the server starts and * keeps the resulting snapshot in memory for `server.getConfig`. * * Uses the shared process runner to run CLI probes natively. * * @module ProviderHealthLive */ import type { ServerProviderAuthStatus, ServerProviderStatus, ServerProviderStatusState, } from "@t3tools/contracts"; import { Data, Effect, Layer, Result } from "effect"; import { runProcess } from "../../processRunner"; import { ProviderHealth, type ProviderHealthShape } from "../Services/ProviderHealth"; const DEFAULT_TIMEOUT_MS = 4_000; const CODEX_PROVIDER = "codex" as const; class ProviderHealthCommandError extends Data.TaggedError("ProviderHealthCommandError")<{ readonly message: string; readonly cause?: unknown; }> {} // ── Pure helpers ──────────────────────────────────────────────────── export interface CommandResult { readonly stdout: string; readonly stderr: string; readonly code: number | null; readonly timedOut?: boolean; } function errorMessage(error: unknown): string { if (error instanceof Error) { return error.message; } if ( error && typeof error === "object" && "message" in error && typeof (error as { message?: unknown }).message === "string" ) { return (error as { message: string }).message; } return String(error); } function nonEmptyTrimmed(value: string | undefined): string | undefined { if (!value) return undefined; const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : undefined; } function isCommandMissingCause(error: unknown): boolean { const lower = errorMessage(error).toLowerCase(); return ( lower.includes("command not found: codex") || lower.includes("spawn codex enoent") || lower.includes("enoent") || lower.includes("notfound") ); } function detailFromResult( result: CommandResult & { readonly timedOut?: boolean }, ): string | undefined { if (result.timedOut) return "Timed out while running command."; const stderr = nonEmptyTrimmed(result.stderr); if (stderr) return stderr; const stdout = nonEmptyTrimmed(result.stdout); if (stdout) return stdout; if (result.code === null) { return "Command was terminated before reporting an exit code."; } if (result.code !== 0) { return `Command exited with code ${result.code}.`; } return undefined; } function extractAuthBoolean(value: unknown): boolean | undefined { if (Array.isArray(value)) { for (const entry of value) { const nested = extractAuthBoolean(entry); if (nested !== undefined) return nested; } return undefined; } if (!value || typeof value !== "object") return undefined; const record = value as Record; for (const key of ["authenticated", "isAuthenticated", "loggedIn", "isLoggedIn"] as const) { if (typeof record[key] === "boolean") return record[key]; } for (const key of ["auth", "status", "session", "account"] as const) { const nested = extractAuthBoolean(record[key]); if (nested !== undefined) return nested; } return undefined; } export function parseAuthStatusFromOutput(result: CommandResult): { readonly status: ServerProviderStatusState; readonly authStatus: ServerProviderAuthStatus; readonly message?: string; } { if (result.timedOut) { return { status: "warning", authStatus: "unknown", message: "Timed out while checking Codex authentication status.", }; } const lowerOutput = `${result.stdout}\n${result.stderr}`.toLowerCase(); if ( lowerOutput.includes("unknown command") || lowerOutput.includes("unrecognized command") || lowerOutput.includes("unexpected argument") ) { return { status: "warning", authStatus: "unknown", message: "Codex CLI authentication status command is unavailable in this Codex version.", }; } if ( lowerOutput.includes("not logged in") || lowerOutput.includes("login required") || lowerOutput.includes("authentication required") || lowerOutput.includes("run `codex login`") || lowerOutput.includes("run codex login") ) { return { status: "error", authStatus: "unauthenticated", message: "Codex CLI is not authenticated. Run `codex login` and try again.", }; } const parsedAuth = (() => { const trimmed = result.stdout.trim(); if (!trimmed || (!trimmed.startsWith("{") && !trimmed.startsWith("["))) { return { attemptedJsonParse: false as const, auth: undefined as boolean | undefined }; } try { return { attemptedJsonParse: true as const, auth: extractAuthBoolean(JSON.parse(trimmed)), }; } catch { return { attemptedJsonParse: false as const, auth: undefined as boolean | undefined }; } })(); if (parsedAuth.auth === true) { return { status: "ready", authStatus: "authenticated" }; } if (parsedAuth.auth === false) { return { status: "error", authStatus: "unauthenticated", message: "Codex CLI is not authenticated. Run `codex login` and try again.", }; } if (parsedAuth.attemptedJsonParse) { return { status: "warning", authStatus: "unknown", message: "Could not verify Codex authentication status from JSON output (missing auth marker).", }; } if (result.code === 0) { return { status: "ready", authStatus: "authenticated" }; } const detail = detailFromResult(result); return { status: "warning", authStatus: "unknown", message: detail ? `Could not verify Codex authentication status. ${detail}` : "Could not verify Codex authentication status.", }; } export type RunProviderHealthCommand = ( args: ReadonlyArray, ) => Promise; const defaultRunCodexCommand: RunProviderHealthCommand = async (args) => { const result = await runProcess("codex", [...args], { allowNonZeroExit: true, timeoutMs: DEFAULT_TIMEOUT_MS, maxBufferBytes: 262_144, outputMode: "truncate", }); return { stdout: result.stdout, stderr: result.stderr, code: result.code, timedOut: result.timedOut, } satisfies CommandResult; }; // ── Health check ──────────────────────────────────────────────────── export const checkCodexProviderStatus = ( runCodexCommand: RunProviderHealthCommand = defaultRunCodexCommand, ): Effect.Effect => Effect.gen(function* () { const checkedAt = new Date().toISOString(); // Probe 1: `codex --version` — is the CLI reachable? const versionProbe = yield* Effect.tryPromise({ try: () => runCodexCommand(["--version"]), catch: (error) => new ProviderHealthCommandError({ message: errorMessage(error), ...(error !== undefined ? { cause: error } : {}), }), }).pipe(Effect.result); if (Result.isFailure(versionProbe)) { const error = versionProbe.failure; return { provider: CODEX_PROVIDER, status: "error" as const, available: false, authStatus: "unknown" as const, checkedAt, message: isCommandMissingCause(error) ? "Codex CLI (`codex`) is not installed or not on PATH." : `Failed to execute Codex CLI health check: ${errorMessage(error)}.`, }; } const version = versionProbe.success; if (version.timedOut || version.code !== 0) { const detail = detailFromResult(version); return { provider: CODEX_PROVIDER, status: "error" as const, available: false, authStatus: "unknown" as const, checkedAt, message: detail ? `Codex CLI is installed but failed to run. ${detail}` : "Codex CLI is installed but failed to run.", }; } // Probe 2: `codex login status` — is the user authenticated? const authProbe = yield* Effect.tryPromise({ try: () => runCodexCommand(["login", "status"]), catch: (error) => new ProviderHealthCommandError({ message: errorMessage(error), ...(error !== undefined ? { cause: error } : {}), }), }).pipe(Effect.result); if (Result.isFailure(authProbe)) { const error = authProbe.failure; return { provider: CODEX_PROVIDER, status: "warning" as const, available: true, authStatus: "unknown" as const, checkedAt, message: errorMessage(error).length > 0 ? `Could not verify Codex authentication status: ${errorMessage(error)}.` : "Could not verify Codex authentication status.", }; } const parsed = parseAuthStatusFromOutput(authProbe.success); return { provider: CODEX_PROVIDER, status: parsed.status, available: true, authStatus: parsed.authStatus, checkedAt, ...(parsed.message ? { message: parsed.message } : {}), } satisfies ServerProviderStatus; }); // ── Layer ─────────────────────────────────────────────────────────── export const ProviderHealthLive = Layer.effect( ProviderHealth, Effect.gen(function* () { const codexStatus = yield* checkCodexProviderStatus(); return { getStatuses: Effect.succeed([codexStatus]), } satisfies ProviderHealthShape; }), );