//! Atlas CLI — query and manage celestial bodies and stations in systems.db. //! //! # Usage //! //! ```sh //! # Via wrapper script (recommended): //! tooling/atlas list-bodies --system "GJ 15A" //! tooling/atlas list-bodies --type planet --inhabited //! tooling/atlas show-system "GJ 15A" //! tooling/atlas show-body "GJ 15Ab" //! tooling/atlas add-body --system "GJ 15A" --type planet --orbit 1 --id "GJ 15Ab" //! tooling/atlas stats //! tooling/atlas corridor-status # remaining systems by corridor/hop //! tooling/atlas populate # bulk classifier pass //! //! # Direct: //! cargo run --bin atlas -- [args] //! ``` use std::path::PathBuf; use clap::{Parser, Subcommand}; mod author; mod common; mod mutate; mod show; mod stats; mod sync_wiki; mod systems; use common::{open_db, resolve_db_path}; // --------------------------------------------------------------------------- // CLI structure // --------------------------------------------------------------------------- #[derive(Parser)] #[command( name = "atlas", about = "Query and manage celestial bodies and stations in systems.db" )] struct Cli { /// Path to the SQLite database (default: auto-detect from worktree) #[arg(long, global = true)] db: Option, #[command(subcommand)] command: Commands, } #[derive(Subcommand)] enum Commands { /// Show full system hierarchy (star → bodies → stations) ShowSystem { /// System ID (e.g., "GJ 15A") system_id: String, }, /// Show a single body's details ShowBody { /// Body ID (e.g., "GJ 15Ab") body_id: String, }, /// Show a single station's details ShowStation { /// Station ID (e.g., "GJ 15Ab-S1") station_id: String, }, /// List bodies with optional filters ListBodies { #[arg(long)] system: Option, #[arg(long, value_name = "TYPE")] r#type: Option, #[arg(long)] inhabited: bool, #[arg(long)] unnamed: bool, }, /// List stations with optional filters ListStations { #[arg(long)] system: Option, #[arg(long, value_name = "TYPE")] r#type: Option, }, /// Add a body record AddBody { #[arg(long)] id: String, #[arg(long)] system: String, #[arg(long, value_name = "TYPE")] r#type: String, #[arg(long)] orbit: Option, #[arg(long)] name: Option, #[arg(long)] parent: Option, #[arg(long)] mass_class: Option, #[arg(long)] atmosphere: Option, #[arg(long)] gravity: Option, #[arg(long)] biome: Option, #[arg(long)] inhabited: bool, #[arg(long)] population: Option, }, /// Add a station record AddStation { #[arg(long)] id: String, #[arg(long)] system: String, #[arg(long)] orbits: Option, #[arg(long, value_name = "TYPE")] r#type: String, #[arg(long)] name: Option, #[arg(long)] population: Option, #[arg(long)] docking: Option, #[arg(long)] gate: bool, }, /// Database statistics Stats, /// Generate a body/station proposal for a single system (writes JSON file for review) Author { /// System ID (e.g., "GJ 71") system_id: String, /// Output directory for proposal JSON (default: docs/atlas/proposals/) #[arg(long, default_value = "docs/atlas/proposals")] outdir: String, /// Path to wiki directory (default: wiki/star-systems/) #[arg(long, default_value = "wiki/star-systems")] wiki: String, }, /// Commit an approved proposal JSON to the database CommitSystem { /// Path to the proposal JSON file path: String, }, /// Wipe all bodies and stations for a single system WipeSystem { /// System ID system_id: String, }, /// List systems with optional filters ListSystems { /// Filter by geographic sector (e.g., "west_reach", "east_reach") #[arg(long)] sector: Option, /// Filter by hop distance #[arg(long)] hop: Option, /// Only show systems that have bodies authored #[arg(long)] finished: bool, /// Only show systems that have NO bodies yet #[arg(long)] unfinished: bool, }, /// List systems that have no bodies yet Unfinished { /// Filter by geographic sector #[arg(long)] sector: Option, }, /// List unfinished systems at a specific hop distance (or next available hop) Next { /// Hop distance (omit to find the lowest hop with unfinished systems) hop: Option, /// Filter by geographic sector #[arg(long)] sector: Option, }, /// Sync body/station data into wiki page for a system (or all systems) SyncWiki { /// System ID (omit for all systems with bodies) system_id: Option, /// Path to wiki directory (default: wiki/star-systems/) #[arg(long, default_value = "wiki/star-systems")] wiki: String, }, /// Show remaining unfinished systems grouped by geographic sector and hop distance CorridorStatus, } // --------------------------------------------------------------------------- // Main // --------------------------------------------------------------------------- fn main() { let cli = Cli::parse(); let db_path = resolve_db_path(cli.db); let conn = open_db(&db_path); match &cli.command { Commands::ShowSystem { system_id } => show::cmd_show_system(&conn, system_id), Commands::ShowBody { body_id } => show::cmd_show_body(&conn, body_id), Commands::ShowStation { station_id } => show::cmd_show_station(&conn, station_id), Commands::ListBodies { system, r#type, inhabited, unnamed, } => systems::cmd_list_bodies( &conn, system.as_deref(), r#type.as_deref(), *inhabited, *unnamed, ), Commands::ListStations { system, r#type } => { systems::cmd_list_stations(&conn, system.as_deref(), r#type.as_deref()) } Commands::AddBody { id, system, r#type, orbit, name, parent, mass_class, atmosphere, gravity, biome, inhabited, population, } => mutate::cmd_add_body( &conn, id, system, r#type, *orbit, name, parent, mass_class, atmosphere, *gravity, biome, *inhabited, *population, ), Commands::AddStation { id, system, orbits, r#type, name, population, docking, gate, } => mutate::cmd_add_station( &conn, id, system, orbits, r#type, name, *population, docking, *gate, ), Commands::Stats => stats::cmd_stats(&conn), Commands::Author { system_id, outdir, wiki, } => author::cmd_author(&conn, system_id, outdir, wiki), Commands::CommitSystem { path } => author::cmd_commit_system(&conn, path), Commands::WipeSystem { system_id } => mutate::cmd_wipe_system(&conn, system_id), Commands::ListSystems { sector, hop, finished, unfinished, } => systems::cmd_list_systems(&conn, sector.as_deref(), *hop, *finished, *unfinished), Commands::Unfinished { sector } => systems::cmd_unfinished(&conn, sector.as_deref()), Commands::Next { hop, sector } => systems::cmd_next(&conn, *hop, sector.as_deref()), Commands::SyncWiki { system_id, wiki } => { sync_wiki::cmd_sync_wiki(&conn, system_id.as_deref(), wiki) } Commands::CorridorStatus => systems::cmd_corridor_status(&conn), } }