//! Typed errors for the driver. See the crate-level docs for why this is a //! `thiserror` enum rather than `anyhow`. use std::process::ExitStatus; use thiserror::Error; /// Why a claude run did not complete cleanly. A normal, finished turn is /// `Ok(())`; everything else is one of these variants. /// /// Two families share the enum on purpose, so a caller can handle them with a /// single `match` on the `Result`: /// /// - **Recognized sentinels** — [`Error::PromptTooLong`], /// [`Error::RateLimited`], [`Error::AuthFailed`], [`Error::SessionNotFound`]. /// These are *expected* non-completion states parsed from claude's output, /// not crashes; callers typically compact, park-and-retry, re-auth, or /// create-a-session in response. /// - **Hard failures** — [`Error::Spawn`], [`Error::Stdin`], [`Error::Wait`], /// [`Error::Exit`], [`Error::Io`]. The process couldn't run, or died with no /// recognizable reason. #[derive(Debug, Error)] pub enum Error { /// `Prompt is too long` — the session is past the model's context window. #[error("prompt is too long for the model's context window")] PromptTooLong, /// The API refused for rate-limit / usage-cap / credit-balance reasons. #[error("request was rate-limited or hit a usage/credit cap")] RateLimited, /// The API rejected the request with 401 (auth/session expired or revoked). #[error("authentication failed (HTTP 401)")] AuthFailed, /// `--resume` matched no session for the given id or title (e.g. the title /// was never created, or its backing file was moved away). #[error("no session matched the requested id or title")] SessionNotFound, /// The `claude` binary could not be spawned (not on `PATH`, not /// executable, …). #[error("failed to spawn `{program}`: {source}")] Spawn { /// The program name we tried to run. program: String, /// The underlying spawn error. #[source] source: std::io::Error, }, /// Writing the prompt to claude's stdin failed. #[error("writing prompt to claude stdin failed: {0}")] Stdin(#[source] std::io::Error), /// Awaiting the child process failed. #[error("waiting on claude failed: {0}")] Wait(#[source] std::io::Error), /// The child produced no stdout for longer than the configured idle /// window (`Config::idle_timeout`) and was killed. Indicative of an /// Anthropic API stall (e.g. a multi-retry connection storm that goes /// silent for minutes). Callers typically park briefly and retry, like /// the rate-limit path. #[error("claude idle timeout: no output for the configured window")] IdleTimeout, /// claude exited non-zero and raised none of the recognized sentinels. /// `stderr_tail` is the last handful of stderr lines (empty if there were /// none), included so the caller can surface a real diagnostic. #[error("claude exited {status}\n{stderr_tail}")] Exit { /// The child's exit status. status: ExitStatus, /// Tail of stderr, newline-joined; empty when claude wrote nothing. stderr_tail: String, }, /// A filesystem operation (session lookup / archive) failed. #[error("session store i/o failed: {0}")] Io(#[from] std::io::Error), } /// Convenience alias for results from this crate. pub type Result = std::result::Result;