mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
Rename fabro-api crate to fabro-server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
01dd50752e
commit
1c0dcf58b1
21 changed files with 101 additions and 92 deletions
|
|
@ -13,7 +13,7 @@ medium = { max-threads = 4 } # 18-30 MB binaries
|
|||
|
||||
[[profile.default.overrides]]
|
||||
filter = """
|
||||
package(fabro-api)
|
||||
package(fabro-server)
|
||||
| package(fabro-workflows)
|
||||
| package(fabro-agent)
|
||||
| package(fabro-cli)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
### Rust
|
||||
- `cargo build --workspace` — build all crates
|
||||
- `cargo nextest run --workspace` — run all unit tests
|
||||
- `cargo nextest run -p fabro-api` — test a single crate
|
||||
- `cargo nextest run -p fabro-server` — test a single crate
|
||||
- `cargo nextest run -p fabro-workflows -- test_name` — run a single test
|
||||
- `set -a && source .env && set +a && cargo nextest run --workspace --profile e2e --run-ignored only` — run all E2E live tests (requires credentials in `.env`, see `.env.example`)
|
||||
- `set -a && source .env && set +a && cargo nextest run -p fabro-llm --profile e2e --run-ignored only` — run E2E tests for a single crate
|
||||
|
|
@ -41,8 +41,8 @@ The OpenAPI spec at `docs/api-reference/fabro-api.yaml` is the source of truth f
|
|||
|
||||
1. Edit `docs/api-reference/fabro-api.yaml`
|
||||
2. `cargo build -p fabro-api-types` — build.rs regenerates Rust types via typify
|
||||
3. Write/update handler in `lib/crates/fabro-api/src/server.rs`, add route to `build_router()`
|
||||
4. `cargo nextest run -p fabro-api` — conformance test catches spec/router drift
|
||||
3. Write/update handler in `lib/crates/fabro-server/src/server.rs`, add route to `build_router()`
|
||||
4. `cargo nextest run -p fabro-server` — conformance test catches spec/router drift
|
||||
5. `cd lib/packages/fabro-api-client && bun run generate` — regenerates TypeScript Axios client
|
||||
|
||||
## Architecture
|
||||
|
|
@ -53,7 +53,7 @@ Fabro is an AI-powered workflow orchestration platform. Workflows are defined as
|
|||
- **fabro-cli** — CLI entry point. Commands: `run`, `exec`, `serve`, `validate`, `parse`, `cp`, `model`, `doctor`, `init`, `install`, `ps`, `system prune`, `llm`
|
||||
- **fabro-workflows** — Core workflow engine. Parses Graphviz graphs, runs stages, manages checkpoints/resume, hooks, retros, and human-in-the-loop interactions
|
||||
- **fabro-agent** — AI coding agent with tool use (Bash, Read, Write, Edit, Glob, Grep, WebFetch). `Sandbox` trait abstracts execution environments
|
||||
- **fabro-api** — Axum HTTP server. Routes for runs, sessions, models, completions, usage. SSE event streaming. Demo mode via header
|
||||
- **fabro-server** — Axum HTTP server. Routes for runs, sessions, models, completions, usage. SSE event streaming. Demo mode via header
|
||||
- **fabro-exe** — SSH-based sandbox implementation (`ExeSandbox`)
|
||||
- **fabro-sprites** — Sprites VM sandbox implementation via `sprite` CLI
|
||||
- **fabro-llm** — Unified LLM client with providers: Anthropic, OpenAI, Gemini, OpenAI-compatible, plus retry/middleware/streaming
|
||||
|
|
|
|||
118
Cargo.lock
generated
118
Cargo.lock
generated
|
|
@ -1442,64 +1442,6 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-api"
|
||||
version = "0.176.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"base64",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"clap",
|
||||
"dirs",
|
||||
"fabro-agent",
|
||||
"fabro-api-types",
|
||||
"fabro-config",
|
||||
"fabro-db",
|
||||
"fabro-github",
|
||||
"fabro-graphviz",
|
||||
"fabro-hooks",
|
||||
"fabro-interview",
|
||||
"fabro-llm",
|
||||
"fabro-model",
|
||||
"fabro-retro",
|
||||
"fabro-sandbox",
|
||||
"fabro-store",
|
||||
"fabro-types",
|
||||
"fabro-util",
|
||||
"fabro-workflows",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"hmac",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"jsonwebtoken",
|
||||
"object_store",
|
||||
"openapiv3",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-stream",
|
||||
"toml 0.8.23",
|
||||
"tower",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"ulid",
|
||||
"uuid",
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-api-types"
|
||||
version = "0.176.2"
|
||||
|
|
@ -1534,7 +1476,6 @@ dependencies = [
|
|||
"dirs",
|
||||
"dotenvy",
|
||||
"fabro-agent",
|
||||
"fabro-api",
|
||||
"fabro-config",
|
||||
"fabro-devcontainer",
|
||||
"fabro-git-storage",
|
||||
|
|
@ -1549,6 +1490,7 @@ dependencies = [
|
|||
"fabro-proctitle",
|
||||
"fabro-retro",
|
||||
"fabro-sandbox",
|
||||
"fabro-server",
|
||||
"fabro-store",
|
||||
"fabro-telemetry",
|
||||
"fabro-types",
|
||||
|
|
@ -1863,6 +1805,64 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-server"
|
||||
version = "0.176.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"base64",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"clap",
|
||||
"dirs",
|
||||
"fabro-agent",
|
||||
"fabro-api-types",
|
||||
"fabro-config",
|
||||
"fabro-db",
|
||||
"fabro-github",
|
||||
"fabro-graphviz",
|
||||
"fabro-hooks",
|
||||
"fabro-interview",
|
||||
"fabro-llm",
|
||||
"fabro-model",
|
||||
"fabro-retro",
|
||||
"fabro-sandbox",
|
||||
"fabro-store",
|
||||
"fabro-types",
|
||||
"fabro-util",
|
||||
"fabro-workflows",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"hmac",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"jsonwebtoken",
|
||||
"object_store",
|
||||
"openapiv3",
|
||||
"reqwest",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-stream",
|
||||
"toml 0.8.23",
|
||||
"tower",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"ulid",
|
||||
"uuid",
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-slack"
|
||||
version = "0.176.2"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ path = "src/main.rs"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
server = ["dep:fabro-api"]
|
||||
server = ["dep:fabro-server"]
|
||||
exedev = ["fabro-sandbox/exe", "fabro-config/exedev", "fabro-workflows/exedev", "fabro-types/exedev"]
|
||||
sleep_inhibitor = ["dep:core-foundation"]
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ fabro-git-storage = { path = "../fabro-git-storage" }
|
|||
fabro-graphviz = { path = "../fabro-graphviz" }
|
||||
fabro-validate = { path = "../fabro-validate" }
|
||||
fabro-workflows = { path = "../fabro-workflows" }
|
||||
fabro-api = { path = "../fabro-api", optional = true }
|
||||
fabro-server = { path = "../fabro-server", optional = true }
|
||||
fabro-telemetry = { path = "../fabro-telemetry" }
|
||||
fabro-store = { path = "../fabro-store" }
|
||||
fabro-types = { path = "../fabro-types" }
|
||||
|
|
|
|||
|
|
@ -772,7 +772,7 @@ pub(crate) enum Commands {
|
|||
},
|
||||
/// Start the HTTP API server
|
||||
#[cfg(feature = "server")]
|
||||
Serve(fabro_api::serve::ServeArgs),
|
||||
Serve(fabro_server::serve::ServeArgs),
|
||||
/// Check environment and integration health
|
||||
Doctor {
|
||||
/// Show detailed information for each check
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ async fn main_inner() -> (String, Result<()>) {
|
|||
#[cfg(feature = "server")]
|
||||
Commands::Serve(args) => {
|
||||
let styles: &'static Styles = Box::leak(Box::new(Styles::detect_stderr()));
|
||||
fabro_api::serve::serve_command(args, styles).await?;
|
||||
fabro_server::serve::serve_command(args, styles).await?;
|
||||
}
|
||||
Commands::Doctor { verbose, dry_run } => {
|
||||
let cli_settings = cli_config::load_cli_settings(None)?;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
[package]
|
||||
name = "fabro-api"
|
||||
name = "fabro-server"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
description = "HTTP API server for Fabro pipelines"
|
||||
description = "HTTP server for Fabro pipelines"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
|
@ -8,10 +8,10 @@ mod mtls_e2e {
|
|||
use std::path::Path;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
use fabro_api::jwt_auth::{AuthMode, AuthStrategy};
|
||||
use fabro_api::server::{build_router, create_app_state};
|
||||
use fabro_api::server_config::TlsSettings;
|
||||
use fabro_api::tls::{ClientAuth, build_rustls_config};
|
||||
use fabro_server::jwt_auth::{AuthMode, AuthStrategy};
|
||||
use fabro_server::server::{build_router, create_app_state};
|
||||
use fabro_server::server_config::TlsSettings;
|
||||
use fabro_server::tls::{ClientAuth, build_rustls_config};
|
||||
use fabro_workflows::pipeline::LlmSpec;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ mod mtls_e2e {
|
|||
let router = build_router(state, auth_mode);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = fabro_api::tls::serve_tls(listener, tls_acceptor, router).await;
|
||||
let _ = fabro_server::tls::serve_tls(listener, tls_acceptor, router).await;
|
||||
});
|
||||
|
||||
addr
|
||||
|
|
@ -391,7 +391,7 @@ mod mtls_e2e {
|
|||
AuthStrategy::Mtls,
|
||||
AuthStrategy::Jwt {
|
||||
key: Arc::new(decoding_key),
|
||||
validation: Arc::new(fabro_api::jwt_auth::jwt_validation()),
|
||||
validation: Arc::new(fabro_server::jwt_auth::jwt_validation()),
|
||||
allowed_usernames: vec!["brynary".to_string()],
|
||||
},
|
||||
]);
|
||||
|
|
@ -428,8 +428,8 @@ mod server_lifecycle {
|
|||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_api::server::{build_router, create_app_state_with_registry_factory};
|
||||
use fabro_interview::Interviewer;
|
||||
use fabro_server::server::{build_router, create_app_state_with_registry_factory};
|
||||
use fabro_workflows::handler::HandlerRegistry;
|
||||
use fabro_workflows::handler::agent::AgentHandler;
|
||||
use fabro_workflows::handler::exit::ExitHandler;
|
||||
|
|
@ -471,8 +471,11 @@ mod server_lifecycle {
|
|||
async fn full_http_lifecycle_approve_and_complete() {
|
||||
let state =
|
||||
create_app_state_with_registry_factory(test_db().await, test_llm_spec, gate_registry);
|
||||
fabro_api::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(Arc::clone(&state), fabro_api::jwt_auth::AuthMode::Disabled);
|
||||
fabro_server::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(
|
||||
Arc::clone(&state),
|
||||
fabro_server::jwt_auth::AuthMode::Disabled,
|
||||
);
|
||||
|
||||
// 1. Start run
|
||||
let req = Request::builder()
|
||||
|
|
@ -568,8 +571,11 @@ mod server_lifecycle {
|
|||
async fn full_http_lifecycle_cancel() {
|
||||
let state =
|
||||
create_app_state_with_registry_factory(test_db().await, test_llm_spec, gate_registry);
|
||||
fabro_api::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(Arc::clone(&state), fabro_api::jwt_auth::AuthMode::Disabled);
|
||||
fabro_server::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(
|
||||
Arc::clone(&state),
|
||||
fabro_server::jwt_auth::AuthMode::Disabled,
|
||||
);
|
||||
|
||||
// Start a run that will block at the human gate
|
||||
let req = Request::builder()
|
||||
|
|
@ -621,7 +627,7 @@ mod sse_events {
|
|||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_api::server::{build_router, create_app_state};
|
||||
use fabro_server::server::{build_router, create_app_state};
|
||||
use http_body_util::BodyExt;
|
||||
use tower::ServiceExt;
|
||||
|
||||
|
|
@ -636,8 +642,11 @@ mod sse_events {
|
|||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn sse_stream_contains_expected_event_types() {
|
||||
let state = create_app_state(test_db().await, test_llm_spec);
|
||||
fabro_api::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(Arc::clone(&state), fabro_api::jwt_auth::AuthMode::Disabled);
|
||||
fabro_server::server::spawn_scheduler(Arc::clone(&state));
|
||||
let app = build_router(
|
||||
Arc::clone(&state),
|
||||
fabro_server::jwt_auth::AuthMode::Disabled,
|
||||
);
|
||||
|
||||
// Start run
|
||||
let req = Request::builder()
|
||||
|
|
@ -765,7 +774,7 @@ mod serve_dry_run {
|
|||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_api::server::{build_router, create_app_state};
|
||||
use fabro_server::server::{build_router, create_app_state};
|
||||
use tower::ServiceExt;
|
||||
|
||||
const MINIMAL_DOT: &str = r#"digraph Test {
|
||||
|
|
@ -778,8 +787,8 @@ mod serve_dry_run {
|
|||
/// Build the router exactly as `serve_command` does in dry-run mode.
|
||||
async fn dry_run_app() -> axum::Router {
|
||||
let state = create_app_state(test_db().await, test_llm_spec);
|
||||
fabro_api::server::spawn_scheduler(Arc::clone(&state));
|
||||
build_router(state, fabro_api::jwt_auth::AuthMode::Disabled)
|
||||
fabro_server::server::spawn_scheduler(Arc::clone(&state));
|
||||
build_router(state, fabro_server::jwt_auth::AuthMode::Disabled)
|
||||
}
|
||||
|
||||
async fn body_json(body: Body) -> serde_json::Value {
|
||||
|
|
@ -5,13 +5,13 @@ use std::collections::BTreeSet;
|
|||
|
||||
use axum::body::Body;
|
||||
use axum::http::{Method, Request, StatusCode};
|
||||
use fabro_api::jwt_auth::AuthMode;
|
||||
use fabro_api::server::{build_router, create_app_state};
|
||||
use fabro_api::server_config::*;
|
||||
use fabro_config::run::*;
|
||||
use fabro_config::sandbox::SandboxSettings;
|
||||
use fabro_hooks::*;
|
||||
use fabro_sandbox::daytona::*;
|
||||
use fabro_server::jwt_auth::AuthMode;
|
||||
use fabro_server::server::{build_router, create_app_state};
|
||||
use fabro_server::server_config::*;
|
||||
use tower::ServiceExt;
|
||||
|
||||
fn load_spec() -> openapiv3::OpenAPI {
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
use super::helpers::{test_db, test_llm_spec};
|
||||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_api::jwt_auth::AuthMode;
|
||||
use fabro_api::server::{build_router, create_app_state};
|
||||
use fabro_server::jwt_auth::AuthMode;
|
||||
use fabro_server::server::{build_router, create_app_state};
|
||||
use tower::ServiceExt;
|
||||
|
||||
async fn get_json(app: axum::Router, uri: &str) -> serde_json::Value {
|
||||
Loading…
Add table
Reference in a new issue