feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
use std::env::VarError;
|
|
|
|
|
use std::fmt::{Display, Formatter};
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
use std::time::Duration;
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum ApiError {
|
|
|
|
|
MissingApiKey,
|
|
|
|
|
InvalidApiKeyEnv(VarError),
|
|
|
|
|
Http(reqwest::Error),
|
|
|
|
|
Io(std::io::Error),
|
|
|
|
|
Json(serde_json::Error),
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
Api {
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
status: reqwest::StatusCode,
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
error_type: Option<String>,
|
|
|
|
|
message: Option<String>,
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
body: String,
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
retryable: bool,
|
|
|
|
|
},
|
|
|
|
|
RetriesExhausted {
|
|
|
|
|
attempts: u32,
|
|
|
|
|
last_error: Box<ApiError>,
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
},
|
|
|
|
|
InvalidSseFrame(&'static str),
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
BackoffOverflow {
|
|
|
|
|
attempt: u32,
|
|
|
|
|
base_delay: Duration,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ApiError {
|
|
|
|
|
#[must_use]
|
|
|
|
|
pub fn is_retryable(&self) -> bool {
|
|
|
|
|
match self {
|
|
|
|
|
Self::Http(error) => error.is_connect() || error.is_timeout() || error.is_request(),
|
|
|
|
|
Self::Api { retryable, .. } => *retryable,
|
|
|
|
|
Self::RetriesExhausted { last_error, .. } => last_error.is_retryable(),
|
|
|
|
|
Self::MissingApiKey
|
|
|
|
|
| Self::InvalidApiKeyEnv(_)
|
|
|
|
|
| Self::Io(_)
|
|
|
|
|
| Self::Json(_)
|
|
|
|
|
| Self::InvalidSseFrame(_)
|
|
|
|
|
| Self::BackoffOverflow { .. } => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for ApiError {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
match self {
|
|
|
|
|
Self::MissingApiKey => {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
2026-03-31 18:39:39 +00:00
|
|
|
"ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY is not set; export one before calling the Anthropic API"
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
Self::InvalidApiKeyEnv(error) => {
|
2026-03-31 18:39:39 +00:00
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"failed to read ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY: {error}"
|
|
|
|
|
)
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
Self::Http(error) => write!(f, "http error: {error}"),
|
|
|
|
|
Self::Io(error) => write!(f, "io error: {error}"),
|
|
|
|
|
Self::Json(error) => write!(f, "json error: {error}"),
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
Self::Api {
|
|
|
|
|
status,
|
|
|
|
|
error_type,
|
|
|
|
|
message,
|
|
|
|
|
body,
|
|
|
|
|
..
|
|
|
|
|
} => match (error_type, message) {
|
|
|
|
|
(Some(error_type), Some(message)) => {
|
|
|
|
|
write!(
|
|
|
|
|
f,
|
|
|
|
|
"anthropic api returned {status} ({error_type}): {message}"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
_ => write!(f, "anthropic api returned {status}: {body}"),
|
|
|
|
|
},
|
|
|
|
|
Self::RetriesExhausted {
|
|
|
|
|
attempts,
|
|
|
|
|
last_error,
|
|
|
|
|
} => write!(
|
|
|
|
|
f,
|
|
|
|
|
"anthropic api failed after {attempts} attempts: {last_error}"
|
|
|
|
|
),
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
Self::InvalidSseFrame(message) => write!(f, "invalid sse frame: {message}"),
|
feat: merge 2nd round from all rcc/* sessions
- api: tool_use parsing, message_delta, request_id tracking, retry logic
- tools: extended tool suite (WebSearch, WebFetch, Agent, etc.)
- cli: live streamed conversations, session restore, compact commands
- runtime: config loading, system prompt builder, token usage, compaction
2026-03-31 17:43:25 +00:00
|
|
|
Self::BackoffOverflow {
|
|
|
|
|
attempt,
|
|
|
|
|
base_delay,
|
|
|
|
|
} => write!(
|
|
|
|
|
f,
|
|
|
|
|
"retry backoff overflowed on attempt {attempt} with base delay {base_delay:?}"
|
|
|
|
|
),
|
feat: Rust port of Claude Code CLI
Crates:
- api: Anthropic Messages API client with SSE streaming
- tools: Claude-compatible tool implementations (Bash, Read, Write, Edit, Glob, Grep + extended suite)
- runtime: conversation loop, session persistence, permissions, system prompt builder
- rusty-claude-cli: terminal UI with markdown rendering, syntax highlighting, spinners
- commands: subcommand definitions
- compat-harness: upstream TS parity verification
All crates pass cargo fmt/clippy/test.
2026-03-31 17:43:09 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::error::Error for ApiError {}
|
|
|
|
|
|
|
|
|
|
impl From<reqwest::Error> for ApiError {
|
|
|
|
|
fn from(value: reqwest::Error) -> Self {
|
|
|
|
|
Self::Http(value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<std::io::Error> for ApiError {
|
|
|
|
|
fn from(value: std::io::Error) -> Self {
|
|
|
|
|
Self::Io(value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<serde_json::Error> for ApiError {
|
|
|
|
|
fn from(value: serde_json::Error) -> Self {
|
|
|
|
|
Self::Json(value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<VarError> for ApiError {
|
|
|
|
|
fn from(value: VarError) -> Self {
|
|
|
|
|
Self::InvalidApiKeyEnv(value)
|
|
|
|
|
}
|
|
|
|
|
}
|