295 lines
8.4 KiB
Rust
295 lines
8.4 KiB
Rust
//! 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 -- <subcommand> [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<PathBuf>,
|
|
|
|
#[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<String>,
|
|
#[arg(long, value_name = "TYPE")]
|
|
r#type: Option<String>,
|
|
#[arg(long)]
|
|
inhabited: bool,
|
|
#[arg(long)]
|
|
unnamed: bool,
|
|
},
|
|
/// List stations with optional filters
|
|
ListStations {
|
|
#[arg(long)]
|
|
system: Option<String>,
|
|
#[arg(long, value_name = "TYPE")]
|
|
r#type: Option<String>,
|
|
},
|
|
/// 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<i32>,
|
|
#[arg(long)]
|
|
name: Option<String>,
|
|
#[arg(long)]
|
|
parent: Option<String>,
|
|
#[arg(long)]
|
|
mass_class: Option<String>,
|
|
#[arg(long)]
|
|
atmosphere: Option<String>,
|
|
#[arg(long)]
|
|
gravity: Option<f64>,
|
|
#[arg(long)]
|
|
biome: Option<String>,
|
|
#[arg(long)]
|
|
inhabited: bool,
|
|
#[arg(long)]
|
|
population: Option<i64>,
|
|
},
|
|
/// Add a station record
|
|
AddStation {
|
|
#[arg(long)]
|
|
id: String,
|
|
#[arg(long)]
|
|
system: String,
|
|
#[arg(long)]
|
|
orbits: Option<String>,
|
|
#[arg(long, value_name = "TYPE")]
|
|
r#type: String,
|
|
#[arg(long)]
|
|
name: Option<String>,
|
|
#[arg(long)]
|
|
population: Option<i64>,
|
|
#[arg(long)]
|
|
docking: Option<String>,
|
|
#[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<String>,
|
|
/// Filter by hop distance
|
|
#[arg(long)]
|
|
hop: Option<i32>,
|
|
/// 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<String>,
|
|
},
|
|
/// 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<i32>,
|
|
/// Filter by geographic sector
|
|
#[arg(long)]
|
|
sector: Option<String>,
|
|
},
|
|
/// 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<String>,
|
|
/// 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),
|
|
}
|
|
}
|