mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-22 00:31:12 +00:00
- Rename 20 crate directories lib/crates/arc-* → fabro-* - Update all Cargo.toml: crate names, dep paths, feature flags, bin name - Rename arc_server module → fabro_server in fabro-llm - ArcError → FabroError across 30+ files - ARC_VERSION/ARC_GIT_SHA/ARC_BUILD_DATE → FABRO_* constants - All use/qualified paths: arc_agent:: → fabro_agent::, etc. (~1500 occurrences) - Env vars ARC_* → FABRO_* in string literals and shell scripts - String literals: X-Arc-Demo, arc-bot, arc@local, arc-web, arc-mcp, etc. - Path strings: .arc/ → .fabro/, arc.toml → fabro.toml, refs/arc/ → refs/fabro/ - arc-api.yaml → fabro-api.yaml (OpenAPI spec) - skills/arc-create-workflow → fabro-create-workflow - trycmd fixtures: $ arc → $ fabro - Inline snapshots (insta) updated - CI, Docker, install.sh, scripts, CLAUDE.md, AGENTS.md - TypeScript app: env vars, headers, JWT issuer - Docs: page slugs, git refs, config paths, sandbox names, repo URLs - Repo references: brynary/arc → fabro-sh/fabro Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
4.6 KiB
Rust
154 lines
4.6 KiB
Rust
pub use fabro_config::cli::*;
|
|
|
|
#[cfg(feature = "server")]
|
|
use tracing::debug;
|
|
|
|
#[cfg(feature = "server")]
|
|
#[derive(Debug, PartialEq)]
|
|
pub struct ResolvedMode {
|
|
pub mode: ExecutionMode,
|
|
pub server_base_url: String,
|
|
pub tls: Option<ClientTlsConfig>,
|
|
}
|
|
|
|
#[cfg(feature = "server")]
|
|
const DEFAULT_SERVER_URL: &str = "http://localhost:3000";
|
|
|
|
#[cfg(feature = "server")]
|
|
pub fn resolve_mode(
|
|
cli_mode: Option<ExecutionMode>,
|
|
cli_server_url: Option<&str>,
|
|
config: &CliConfig,
|
|
) -> ResolvedMode {
|
|
let mode = cli_mode.or_else(|| config.mode.clone()).unwrap_or_default();
|
|
|
|
let server_defaults = config.server.as_ref();
|
|
|
|
let server_base_url = cli_server_url
|
|
.map(String::from)
|
|
.or_else(|| server_defaults.and_then(|s| s.base_url.clone()))
|
|
.unwrap_or_else(|| DEFAULT_SERVER_URL.to_string());
|
|
|
|
let tls = server_defaults.and_then(|s| s.tls.clone());
|
|
|
|
debug!(mode = ?mode, base_url = %server_base_url, tls = tls.is_some(), "CLI mode resolved");
|
|
|
|
ResolvedMode {
|
|
mode,
|
|
server_base_url,
|
|
tls,
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "server")]
|
|
pub fn build_server_client(tls: Option<&ClientTlsConfig>) -> anyhow::Result<reqwest::Client> {
|
|
let Some(tls) = tls else {
|
|
return Ok(reqwest::Client::new());
|
|
};
|
|
|
|
let cert_path = fabro_config::expand_tilde(&tls.cert);
|
|
let key_path = fabro_config::expand_tilde(&tls.key);
|
|
let ca_path = fabro_config::expand_tilde(&tls.ca);
|
|
|
|
let cert_pem = std::fs::read(&cert_path)?;
|
|
let key_pem = std::fs::read(&key_path)?;
|
|
let ca_pem = std::fs::read(&ca_path)?;
|
|
|
|
let mut identity_pem = cert_pem;
|
|
identity_pem.push(b'\n');
|
|
identity_pem.extend_from_slice(&key_pem);
|
|
|
|
let identity = reqwest::Identity::from_pem(&identity_pem)?;
|
|
let ca_cert = reqwest::Certificate::from_pem(&ca_pem)?;
|
|
|
|
let client = reqwest::Client::builder()
|
|
.use_rustls_tls()
|
|
.identity(identity)
|
|
.add_root_certificate(ca_cert)
|
|
.build()?;
|
|
|
|
Ok(client)
|
|
}
|
|
|
|
#[cfg(all(test, feature = "server"))]
|
|
mod tests {
|
|
use std::path::PathBuf;
|
|
|
|
use super::*;
|
|
|
|
// --- resolve_mode precedence ---
|
|
|
|
#[test]
|
|
fn resolve_mode_defaults_to_standalone() {
|
|
let config = CliConfig::default();
|
|
let resolved = resolve_mode(None, None, &config);
|
|
assert_eq!(resolved.mode, ExecutionMode::Standalone);
|
|
assert_eq!(resolved.server_base_url, DEFAULT_SERVER_URL);
|
|
assert_eq!(resolved.tls, None);
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_mode_config_overrides_default() {
|
|
let config = CliConfig {
|
|
mode: Some(ExecutionMode::Server),
|
|
server: Some(ServerDefaults {
|
|
base_url: Some("https://config.example.com".to_string()),
|
|
tls: None,
|
|
}),
|
|
..CliConfig::default()
|
|
};
|
|
let resolved = resolve_mode(None, None, &config);
|
|
assert_eq!(resolved.mode, ExecutionMode::Server);
|
|
assert_eq!(resolved.server_base_url, "https://config.example.com");
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_mode_cli_overrides_config() {
|
|
let config = CliConfig {
|
|
mode: Some(ExecutionMode::Standalone),
|
|
server: Some(ServerDefaults {
|
|
base_url: Some("https://config.example.com".to_string()),
|
|
tls: None,
|
|
}),
|
|
..CliConfig::default()
|
|
};
|
|
let resolved = resolve_mode(
|
|
Some(ExecutionMode::Server),
|
|
Some("https://cli.example.com"),
|
|
&config,
|
|
);
|
|
assert_eq!(resolved.mode, ExecutionMode::Server);
|
|
assert_eq!(resolved.server_base_url, "https://cli.example.com");
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_mode_cli_url_overrides_config_url() {
|
|
let config = CliConfig {
|
|
server: Some(ServerDefaults {
|
|
base_url: Some("https://config.example.com".to_string()),
|
|
tls: None,
|
|
}),
|
|
..CliConfig::default()
|
|
};
|
|
let resolved = resolve_mode(None, Some("https://cli.example.com"), &config);
|
|
assert_eq!(resolved.server_base_url, "https://cli.example.com");
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_mode_tls_from_config() {
|
|
let tls = ClientTlsConfig {
|
|
cert: PathBuf::from("cert.pem"),
|
|
key: PathBuf::from("key.pem"),
|
|
ca: PathBuf::from("ca.pem"),
|
|
};
|
|
let config = CliConfig {
|
|
server: Some(ServerDefaults {
|
|
base_url: None,
|
|
tls: Some(tls.clone()),
|
|
}),
|
|
..CliConfig::default()
|
|
};
|
|
let resolved = resolve_mode(None, None, &config);
|
|
assert_eq!(resolved.tls, Some(tls));
|
|
}
|
|
}
|