oxipage 0.7.0

Oxipage CLI — 블로그/프로젝트/링크/사이트 관리 커맨드라인 도구 (doc/04)
//! Oxipage CLI — 모든 명령은 인증된 HTTP 호출 (doc/04 §4.1).
//!
//! 유일한 예외: `oxipage console`이 관리 콘솔을 띄운다.

mod client;
mod commands;
mod output;
mod sites;

use clap::{Parser, Subcommand};
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(
    name = "oxipage",
    version,
    about = "Oxipage personal-site CLI — every command is an authenticated HTTP call",
    long_about = "doc/04 §4.1: CLI는 API의 레퍼런스 클라이언트. 모든 쓰기/읽기는 인증된 HTTP 호출이다.\n유일한 예외는 serve 자체가 서버 프로세스를 기동하는 것뿐이다."
)]
pub struct Cli {
    #[arg(long, global = true, env = "OXIPAGE_ENDPOINT")]
    pub endpoint: Option<String>,
    #[arg(long, global = true, env = "OXIPAGE_SITE")]
    pub site: Option<String>,
    #[arg(long, global = true, env = "OXIPAGE_TOKEN")]
    pub token: Option<String>,

    #[arg(long, global = true)]
    pub json: bool,

    #[arg(long, global = true, env = "OXIPAGE_CONFIG")]
    pub config: Option<PathBuf>,

    #[arg(long, global = true, env = "OXIPAGE_TLS_INSECURE")]
    pub insecure: bool,

    #[command(subcommand)]
    pub command: Command,
}

#[derive(Subcommand, Debug, Clone)]
pub enum Command {
    /// oxipage.toml 스캐폴딩
    Init {
        #[arg(long)]
        /// init 후 serve + 브라우저 오픈 (한 줄 시작)
        wizard: bool,
    },
    /// 초안/최근 게시물/서버 상태 요약
    Status,
    /// 로컬 개발 서버 기동 (유일하게 HTTP를 거치지 않는 예외)
    Console {
        #[arg(long)]
        port: Option<u16>,
        /// Preview mode: serve out/ directory as static files
        #[arg(long)]
        preview: bool,
    },
    /// 브라우저로 사이트 오픈 (doc/13 §13.4.2)
    Open {
        #[arg(long)]
        port: Option<u16>,
    },
    /// 블로그 (doc/02 §2.6)
    #[command(subcommand)]
    Blog(commands::BlogCommand),
    /// 프로젝트 포트폴리오 (doc/02 §2.4)
    #[command(subcommand)]
    Project(commands::ProjectCommand),
    /// 생태계 링크 (doc/02 §2.11)
    #[command(subcommand)]
    Link(commands::LinkCommand),
    /// 로비 표시 설정 (doc/03 §3.6)
    #[command(subcommand)]
    Lobby(commands::LobbyCommand),
    /// 확장 탑재/제거 (doc/02 §2.13, doc/04 §4.3)
    #[command(subcommand)]
    Extension(commands::ExtensionCommand),
    /// 백업 (doc/05 §5.4) — SQLite VACUUM INTO 스냅샷
    #[command(subcommand)]
    Backup(commands::BackupCommand),
    /// Build the static site (v2 SSG) — sources the SPA from the embedded binary.
    Build(commands::BuildCommand),
    /// 외부 캐시 갱신 (GitHub, TMDB, 알라딘 등)
    Cache(commands::CacheArgs),
    /// 정적 사이트 배포 (GitHub Pages 등)
    Deploy(commands::DeployArgs),
    /// 직접 SQL 질의 (읽기 전용, 로컬 DB)
    Query(commands::QueryCommand),
    /// DB 스키마 조회
    Schema(commands::SchemaCommand),
    /// 사이트 프로필 관리 (doc/09) — 접속 대상 서버 등록/전환
    #[command(subcommand)]
    Site(commands::SiteCommand),

    /// 확장이 등록한 동적 명령 (doc/11 §11.2.2).
    /// clap derive가 매칭하지 못한 서브커맨드를 raw args 배열로 잡는다.
    #[clap(external_subcommand)]
    Dynamic(Vec<String>),
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let cli = Cli::parse();
    commands::dispatch(cli).await
}