refactor: rename sandbox-daemon to sandbox-agent

This commit is contained in:
Nathan Flurry 2026-01-25 02:30:12 -08:00
parent f92ecd9b9a
commit a49ea094f3
41 changed files with 808 additions and 134 deletions

View file

@ -1,7 +1,9 @@
[package]
name = "sandbox-daemon-agent-credentials"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-agent-credentials"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[dependencies]
serde = { version = "1.0", features = ["derive"] }

View file

@ -1,13 +1,15 @@
[package]
name = "sandbox-daemon-agent-management"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-agent-management"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[dependencies]
thiserror = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sandbox-daemon-agent-credentials = { path = "../agent-credentials" }
sandbox-agent-agent-credentials = { path = "../agent-credentials" }
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"] }
flate2 = "1.0"
tar = "0.4"

View file

@ -1 +1 @@
pub use sandbox_daemon_agent_credentials::*;
pub use sandbox_agent_agent_credentials::*;

View file

@ -1,7 +1,9 @@
[package]
name = "sandbox-daemon-agent-schema"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-agent-schema"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[dependencies]
serde = { version = "1.0", features = ["derive"] }

View file

@ -1,4 +1,5 @@
use std::fs;
use std::io::{self, Write};
use std::path::Path;
fn main() {
@ -16,10 +17,16 @@ fn main() {
let schema_path = schema_dir.join(file);
// Tell cargo to rerun if schema changes
println!("cargo:rerun-if-changed={}", schema_path.display());
emit_stdout(&format!(
"cargo:rerun-if-changed={}",
schema_path.display()
));
if !schema_path.exists() {
eprintln!("Warning: Schema file not found: {}", schema_path.display());
emit_stdout(&format!(
"cargo:warning=Schema file not found: {}",
schema_path.display()
));
// Write empty module
let out_path = Path::new(&out_dir).join(format!("{}.rs", name));
fs::write(&out_path, "// Schema not found\n").unwrap();
@ -49,6 +56,16 @@ fn main() {
fs::write(&out_path, formatted)
.unwrap_or_else(|e| panic!("Failed to write {}: {}", out_path.display(), e));
println!("cargo:warning=Generated {} types from {}", name, file);
emit_stdout(&format!(
"cargo:warning=Generated {} types from {}",
name, file
));
}
}
fn emit_stdout(message: &str) {
let mut out = io::stdout();
let _ = out.write_all(message.as_bytes());
let _ = out.write_all(b"\n");
let _ = out.flush();
}

View file

@ -1,7 +1,9 @@
[package]
name = "sandbox-daemon-error"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-error"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[dependencies]
serde = { version = "1.0", features = ["derive"] }

View file

@ -24,18 +24,18 @@ pub enum ErrorType {
impl ErrorType {
pub fn as_urn(&self) -> &'static str {
match self {
Self::InvalidRequest => "urn:sandbox-daemon:error:invalid_request",
Self::UnsupportedAgent => "urn:sandbox-daemon:error:unsupported_agent",
Self::AgentNotInstalled => "urn:sandbox-daemon:error:agent_not_installed",
Self::InstallFailed => "urn:sandbox-daemon:error:install_failed",
Self::AgentProcessExited => "urn:sandbox-daemon:error:agent_process_exited",
Self::TokenInvalid => "urn:sandbox-daemon:error:token_invalid",
Self::PermissionDenied => "urn:sandbox-daemon:error:permission_denied",
Self::SessionNotFound => "urn:sandbox-daemon:error:session_not_found",
Self::SessionAlreadyExists => "urn:sandbox-daemon:error:session_already_exists",
Self::ModeNotSupported => "urn:sandbox-daemon:error:mode_not_supported",
Self::StreamError => "urn:sandbox-daemon:error:stream_error",
Self::Timeout => "urn:sandbox-daemon:error:timeout",
Self::InvalidRequest => "urn:sandbox-agent:error:invalid_request",
Self::UnsupportedAgent => "urn:sandbox-agent:error:unsupported_agent",
Self::AgentNotInstalled => "urn:sandbox-agent:error:agent_not_installed",
Self::InstallFailed => "urn:sandbox-agent:error:install_failed",
Self::AgentProcessExited => "urn:sandbox-agent:error:agent_process_exited",
Self::TokenInvalid => "urn:sandbox-agent:error:token_invalid",
Self::PermissionDenied => "urn:sandbox-agent:error:permission_denied",
Self::SessionNotFound => "urn:sandbox-agent:error:session_not_found",
Self::SessionAlreadyExists => "urn:sandbox-agent:error:session_already_exists",
Self::ModeNotSupported => "urn:sandbox-agent:error:mode_not_supported",
Self::StreamError => "urn:sandbox-agent:error:stream_error",
Self::Timeout => "urn:sandbox-agent:error:timeout",
}
}

View file

@ -1,12 +1,17 @@
[package]
name = "sandbox-daemon-openapi-gen"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-openapi-gen"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
build = "build.rs"
[dependencies]
tracing = "0.1"
tracing-logfmt = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[build-dependencies]
sandbox-daemon-core = { path = "../sandbox-daemon" }
sandbox-agent-core = { path = "../sandbox-agent" }
serde_json = "1.0"
utoipa = "4.2"

View file

@ -1,12 +1,13 @@
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use sandbox_daemon_core::router::ApiDoc;
use sandbox_agent_core::router::ApiDoc;
use utoipa::OpenApi;
fn main() {
println!("cargo:rerun-if-changed=../sandbox-daemon/src/router.rs");
println!("cargo:rerun-if-changed=../sandbox-daemon/src/lib.rs");
emit_stdout("cargo:rerun-if-changed=../sandbox-agent/src/router.rs");
emit_stdout("cargo:rerun-if-changed=../sandbox-agent/src/lib.rs");
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
let out_path = Path::new(&out_dir).join("openapi.json");
@ -16,5 +17,15 @@ fn main() {
.expect("Failed to serialize OpenAPI spec");
fs::write(&out_path, json).expect("Failed to write OpenAPI spec");
println!("cargo:warning=Generated OpenAPI spec at {}", out_path.display());
emit_stdout(&format!(
"cargo:warning=Generated OpenAPI spec at {}",
out_path.display()
));
}
fn emit_stdout(message: &str) {
let mut out = io::stdout();
let _ = out.write_all(message.as_bytes());
let _ = out.write_all(b"\n");
let _ = out.flush();
}

View file

@ -1,8 +1,12 @@
use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
fn main() {
init_logging();
let mut out: Option<PathBuf> = None;
let mut stdout = false;
let mut args = env::args().skip(1).peekable();
@ -26,15 +30,30 @@ fn main() {
}
}
let schema = sandbox_daemon_openapi_gen::OPENAPI_JSON;
let schema = sandbox_agent_openapi_gen::OPENAPI_JSON;
if stdout {
println!("{schema}");
write_stdout(schema);
return;
}
let out = out.unwrap_or_else(|| PathBuf::from("openapi.json"));
if let Err(err) = fs::write(&out, schema) {
eprintln!("failed to write {}: {err}", out.display());
tracing::error!(path = %out.display(), error = %err, "failed to write openapi schema");
std::process::exit(1);
}
}
fn init_logging() {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::registry()
.with(filter)
.with(tracing_logfmt::builder().layer().with_writer(std::io::stderr))
.init();
}
fn write_stdout(text: &str) {
let mut out = std::io::stdout();
let _ = out.write_all(text.as_bytes());
let _ = out.write_all(b"\n");
let _ = out.flush();
}

View file

@ -1,10 +1,12 @@
[package]
name = "sandbox-daemon-core"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-core"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[[bin]]
name = "sandbox-daemon"
name = "sandbox-agent"
path = "src/main.rs"
[dependencies]
@ -14,10 +16,10 @@ serde_json = "1.0"
axum = "0.7"
clap = { version = "4.5", features = ["derive"] }
futures = "0.3"
sandbox-daemon-error = { path = "../error" }
sandbox-daemon-agent-management = { path = "../agent-management" }
sandbox-daemon-agent-credentials = { path = "../agent-credentials" }
sandbox-daemon-universal-agent-schema = { path = "../universal-agent-schema" }
sandbox-agent-error = { path = "../error" }
sandbox-agent-agent-management = { path = "../agent-management" }
sandbox-agent-agent-credentials = { path = "../agent-credentials" }
sandbox-agent-universal-agent-schema = { path = "../universal-agent-schema" }
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls", "stream"] }
dirs = "5.0"
time = { version = "0.3", features = ["parsing", "formatting"] }
@ -26,6 +28,9 @@ tokio-stream = { version = "0.1", features = ["sync"] }
tower-http = { version = "0.5", features = ["cors"] }
utoipa = { version = "4.2", features = ["axum_extras"] }
schemars = "0.8"
tracing = "0.1"
tracing-logfmt = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[dev-dependencies]
tempfile = "3.10"

View file

@ -0,0 +1 @@
pub use sandbox_agent_agent_credentials::*;

View file

@ -4,23 +4,24 @@ use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
use reqwest::blocking::Client as HttpClient;
use reqwest::Method;
use sandbox_daemon_agent_management::agents::AgentManager;
use sandbox_daemon_core::router::{
use sandbox_agent_agent_management::agents::AgentManager;
use sandbox_agent_core::router::{
AgentInstallRequest, AppState, AuthConfig, CreateSessionRequest, MessageRequest,
PermissionReply, PermissionReplyRequest, QuestionReplyRequest,
};
use sandbox_daemon_core::router::{AgentListResponse, AgentModesResponse, CreateSessionResponse, EventsResponse};
use sandbox_daemon_core::router::build_router;
use sandbox_agent_core::router::{AgentListResponse, AgentModesResponse, CreateSessionResponse, EventsResponse};
use sandbox_agent_core::router::build_router;
use serde::Serialize;
use serde_json::Value;
use thiserror::Error;
use tower_http::cors::{Any, CorsLayer};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
const API_PREFIX: &str = "/v1";
#[derive(Parser, Debug)]
#[command(name = "sandbox-daemon")]
#[command(about = "Sandbox daemon for managing coding agents", version)]
#[command(name = "sandbox-agent")]
#[command(about = "Sandbox agent for managing coding agents", version)]
struct Cli {
#[command(subcommand)]
command: Option<Command>,
@ -215,6 +216,7 @@ enum CliError {
}
fn main() {
init_logging();
let cli = Cli::parse();
let result = match &cli.command {
@ -223,11 +225,19 @@ fn main() {
};
if let Err(err) = result {
eprintln!("{err}");
tracing::error!(error = %err, "sandbox-agent failed");
std::process::exit(1);
}
}
fn init_logging() {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::registry()
.with(filter)
.with(tracing_logfmt::builder().layer().with_writer(std::io::stderr))
.init();
}
fn run_server(cli: &Cli) -> Result<(), CliError> {
let auth = if cli.no_token {
AuthConfig::disabled()
@ -262,8 +272,8 @@ fn run_server(cli: &Cli) -> Result<(), CliError> {
fn default_install_dir() -> PathBuf {
dirs::data_dir()
.map(|dir| dir.join("sandbox-daemon").join("bin"))
.unwrap_or_else(|| PathBuf::from(".").join(".sandbox-daemon").join("bin"))
.map(|dir| dir.join("sandbox-agent").join("bin"))
.unwrap_or_else(|| PathBuf::from(".").join(".sandbox-agent").join("bin"))
}
fn run_client(command: &Command, cli: &Cli) -> Result<(), CliError> {
@ -502,7 +512,7 @@ fn print_json_response<T: serde::de::DeserializeOwned + Serialize>(
let parsed: T = serde_json::from_str(&text)?;
let pretty = serde_json::to_string_pretty(&parsed)?;
println!("{pretty}");
write_stdout_line(&pretty)?;
Ok(())
}
@ -515,8 +525,7 @@ fn print_text_response(response: reqwest::blocking::Response) -> Result<(), CliE
return Err(CliError::HttpStatus(status));
}
print!("{text}");
std::io::stdout().flush()?;
write_stdout(&text)?;
Ok(())
}
@ -533,9 +542,32 @@ fn print_empty_response(response: reqwest::blocking::Response) -> Result<(), Cli
fn print_error_body(text: &str) -> Result<(), CliError> {
if let Ok(json) = serde_json::from_str::<Value>(text) {
let pretty = serde_json::to_string_pretty(&json)?;
eprintln!("{pretty}");
write_stderr_line(&pretty)?;
} else {
eprintln!("{text}");
write_stderr_line(text)?;
}
Ok(())
}
fn write_stdout(text: &str) -> Result<(), CliError> {
let mut out = std::io::stdout();
out.write_all(text.as_bytes())?;
out.flush()?;
Ok(())
}
fn write_stdout_line(text: &str) -> Result<(), CliError> {
let mut out = std::io::stdout();
out.write_all(text.as_bytes())?;
out.write_all(b"\n")?;
out.flush()?;
Ok(())
}
fn write_stderr_line(text: &str) -> Result<(), CliError> {
let mut out = std::io::stderr();
out.write_all(text.as_bytes())?;
out.write_all(b"\n")?;
out.flush()?;
Ok(())
}

View file

@ -16,8 +16,8 @@ use axum::Json;
use axum::Router;
use futures::{stream, StreamExt};
use reqwest::Client;
use sandbox_daemon_error::{AgentError, ErrorType, ProblemDetails, SandboxError};
use sandbox_daemon_universal_agent_schema::{
use sandbox_agent_error::{AgentError, ErrorType, ProblemDetails, SandboxError};
use sandbox_agent_universal_agent_schema::{
convert_amp, convert_claude, convert_codex, convert_opencode, AttachmentSource, CrashInfo,
EventConversion, PermissionRequest, PermissionToolRef, QuestionInfo, QuestionOption,
QuestionRequest, QuestionToolRef, Started, UniversalEvent, UniversalEventData,
@ -31,10 +31,10 @@ use tokio_stream::wrappers::BroadcastStream;
use tokio::time::sleep;
use utoipa::{OpenApi, ToSchema};
use sandbox_daemon_agent_management::agents::{
use sandbox_agent_agent_management::agents::{
AgentError as ManagerError, AgentId, AgentManager, InstallOptions, SpawnOptions, StreamingSpawn,
};
use sandbox_daemon_agent_management::credentials::{
use sandbox_agent_agent_management::credentials::{
extract_all_credentials, CredentialExtractionOptions, ExtractedCredentials,
};

View file

@ -1,9 +1,9 @@
use std::collections::HashMap;
use sandbox_daemon_agent_management::agents::{
use sandbox_agent_agent_management::agents::{
AgentError, AgentId, AgentManager, InstallOptions, SpawnOptions,
};
use sandbox_daemon_agent_management::credentials::{
use sandbox_agent_agent_management::credentials::{
extract_all_credentials, CredentialExtractionOptions,
};

View file

@ -1 +0,0 @@
pub use sandbox_daemon_agent_credentials::*;

View file

@ -1,10 +1,12 @@
[package]
name = "sandbox-daemon-universal-agent-schema"
version = "0.1.0"
edition = "2021"
name = "sandbox-agent-universal-agent-schema"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
[dependencies]
sandbox-daemon-agent-schema = { path = "../agent-schema" }
sandbox-agent-agent-schema = { path = "../agent-schema" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
schemars = "0.8"

View file

@ -4,7 +4,7 @@ use schemars::JsonSchema;
use thiserror::Error;
use utoipa::ToSchema;
pub use sandbox_daemon_agent_schema::{amp, claude, codex, opencode};
pub use sandbox_agent_agent_schema::{amp, claude, codex, opencode};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
#[serde(rename_all = "camelCase")]