77 lines
3.2 KiB
Rust
77 lines
3.2 KiB
Rust
//! `hive-claude` — a small, reusable async driver for headless
|
|
//! `claude --print` (Claude Code CLI) sessions.
|
|
//!
|
|
//! It spawns the CLI, streams and classifies its `stream-json` output, and
|
|
//! reports the result as a `Result<(), Error>`: a clean turn is `Ok(())`, and
|
|
//! every non-completion state — both recognized sentinels (rate-limit,
|
|
//! prompt-too-long, …) and hard failures (spawn, non-zero exit) — is a variant
|
|
//! of the single [`Error`] enum, so callers branch with one `match`. The crate
|
|
//! also locates and archives on-disk sessions by title ([`SessionStore`]). It
|
|
//! knows only about the Claude Code CLI — no application types, hard-coded
|
|
//! watermarks, or logging. Callers wire streaming output through a [`Sink`].
|
|
//!
|
|
//! Two layers:
|
|
//!
|
|
//! - [`Claude::run`] — the low-level driver: one turn, one [`Attach`] target.
|
|
//! - [`InfiniteSession`] — a durable session (name + [`SessionStore`] +
|
|
//! [`CompactionPolicy`]) that keeps itself alive across the context window by
|
|
//! compacting reactively (on overflow) and proactively (per policy — e.g.
|
|
//! [`PercentPolicy`]). This is the one you usually want.
|
|
//!
|
|
//! # `thiserror` here, `anyhow` in the apps
|
|
//!
|
|
//! This is a **library**, so it exposes a concrete, matchable error enum built
|
|
//! with [`thiserror`](https://docs.rs/thiserror): a caller can distinguish
|
|
//! `Error::Exit { status, .. }` from `Error::Spawn { .. }` and branch on it.
|
|
//! A library should never force its callers to reach into `anyhow`'s
|
|
//! type-erased error to find out what went wrong.
|
|
//!
|
|
//! The **applications** in this workspace (the `hive-*` binaries) use
|
|
//! [`anyhow`](https://docs.rs/anyhow) instead. At the top level you usually
|
|
//! only want to attach context and log or bubble a failure up — not match on
|
|
//! it — and `anyhow::Result` + `?` + `.context()` is the ergonomic fit.
|
|
//! `anyhow::Error` implements `From<E>` for any `std::error::Error`, so a
|
|
//! `hive_claude::Error` converts into an `anyhow::Error` for free at the `?`
|
|
//! boundary. Rule of thumb: **libraries return `thiserror` enums, binaries
|
|
//! consume them with `anyhow`.**
|
|
//!
|
|
//! # Example
|
|
//!
|
|
//! ```no_run
|
|
//! # async fn ex() {
|
|
//! use hive_claude::{Attach, Claude, Config, Error, NoopSink};
|
|
//!
|
|
//! let config = Config {
|
|
//! model: "haiku".into(),
|
|
//! ..Default::default()
|
|
//! };
|
|
//! match Claude::run(&config, &Attach::Resume("my-session".into()), "hello", &NoopSink).await {
|
|
//! Ok(()) => {}
|
|
//! Err(Error::PromptTooLong) => { /* caller compacts + retries */ }
|
|
//! Err(Error::RateLimited) => { /* caller parks + retries */ }
|
|
//! Err(other) => eprintln!("claude: {other}"),
|
|
//! }
|
|
//! # }
|
|
//! ```
|
|
// The crate-level `//!` overview above is the rustdoc entry point — it belongs
|
|
// in source, not docs/, so the comment-block length lint should not flag it.
|
|
// lint:allow-long-comment
|
|
|
|
mod classify;
|
|
mod config;
|
|
mod driver;
|
|
mod error;
|
|
mod policy;
|
|
mod session;
|
|
mod sink;
|
|
mod store;
|
|
mod telemetry;
|
|
|
|
pub use config::{Attach, Config};
|
|
pub use driver::Claude;
|
|
pub use error::{Error, Result};
|
|
pub use policy::{CompactionPolicy, NeverCompact, PercentPolicy};
|
|
pub use session::{InfiniteSession, Progress};
|
|
pub use sink::{NoopSink, Sink};
|
|
pub use store::SessionStore;
|
|
pub use telemetry::{Telemetry, TokenUsage, Usage};
|