use clap::{Parser, Subcommand};
use crate::commands;
pub const EXIT_CODES_HELP: &str = "\
Exit codes:
0 success
1 generic failure (catch-all for non-classified errors)
2 usage error (clap argument-parse failure — unknown flag, bad value)
3 not found (entity / mem / resource missing)
4 hash mismatch (optimistic-locking failure on a mutation)
5 validation / schema / policy refusal
For programmatic branching, prefer `--json` over the exit code:
memstead <subcommand> ... --json | jq -r .code
The JSON envelope's `code` field carries the typed token
(e.g. INVALID_TITLE, HAS_INCOMING_REFS, CROSS_MEM_LINK_NOT_ALLOWED)
with structured recovery details under `.details`.";
#[derive(Parser, Debug)]
#[command(name = "memstead", version = memstead_base::build_info::full_version(), about, long_about = None, after_long_help = EXIT_CODES_HELP)]
pub struct Cli {
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub quiet: bool,
#[arg(long, global = true, value_name = "PATH")]
pub workspace: Option<std::path::PathBuf>,
#[arg(long = "role", global = true)]
pub role: Option<String>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand, Debug)]
pub enum Command {
Status,
Entity(commands::entity::Args),
Relations(commands::relations::Args),
Search(commands::search::Args),
List(commands::list::Args),
Context(commands::context::Args),
Overview(commands::overview::Args),
Type(commands::type_cmd::Args),
Health(commands::health::Args),
Due(commands::due::Args),
Export(commands::export::Args),
Init(commands::init::InitArgs),
Quickstart(commands::quickstart::Args),
#[cfg(feature = "mem-repo")]
Install(commands::install::Args),
#[cfg(feature = "mem-repo")]
Uninstall(commands::uninstall::Args),
#[command(name = "verify-anchors")]
VerifyAnchors(commands::verify_anchors::Args),
Link(commands::link::LinkArgs),
Publish(commands::publish::Args),
Unpublish(commands::unpublish::Args),
Domain {
#[command(subcommand)]
action: commands::domain::DomainAction,
},
Admin {
#[command(subcommand)]
action: commands::admin::AdminAction,
},
Login(commands::login::Args),
Logout(commands::logout::Args),
Create(commands::create::Args),
Update(commands::update::Args),
Relate(commands::relate::Args),
Delete(commands::delete::Args),
Rename(commands::rename::Args),
#[cfg(feature = "mem-repo")]
#[command(name = "batch-update")]
BatchUpdate(commands::batch_update::Args),
#[cfg(feature = "mem-repo")]
#[command(name = "batch-create")]
BatchCreate(commands::batch_create::Args),
#[cfg(feature = "mem-repo")]
#[command(name = "batch-relate")]
BatchRelate(commands::batch_relate::Args),
#[cfg(feature = "mem-repo")]
Recover(commands::recover::Args),
Anchors(commands::anchors::Args),
Changes(commands::changes::Args),
Check(commands::check::Args),
#[command(name = "review-mark")]
ReviewMark(commands::review_mark::Args),
Reload(commands::reload::Args),
#[cfg(feature = "mem-repo")]
Fetch(commands::transport::FetchArgs),
#[cfg(feature = "mem-repo")]
Pull(commands::transport::PullArgs),
#[cfg(feature = "mem-repo")]
Push(commands::transport::PushArgs),
#[cfg(feature = "mem-repo")]
#[command(name = "branch-reset")]
BranchReset(commands::branch_reset::BranchResetArgs),
#[cfg(feature = "mem-repo")]
Mem {
#[command(subcommand)]
action: commands::mem::MemAction,
},
#[cfg(feature = "mem-repo")]
#[command(name = "mem-repo")]
MemRepo {
#[command(subcommand)]
action: commands::mem_repo::MemRepoAction,
},
#[cfg(feature = "mem-repo")]
Workspace {
#[command(subcommand)]
action: commands::workspace::WorkspaceAction,
},
Schema(commands::schema::Args),
Projection(commands::projection::Args),
}
impl Command {
pub fn verb(&self) -> &'static str {
match self {
Command::Status => "status",
Command::Entity(_) => "entity",
Command::Relations(_) => "relations",
Command::Search(_) => "search",
Command::List(_) => "list",
Command::Context(_) => "context",
Command::Overview(_) => "overview",
Command::Type(_) => "type",
Command::Health(_) => "health",
Command::Due(_) => "due",
Command::Export(_) => "export",
Command::Init(_) => "init",
Command::Quickstart(_) => "quickstart",
#[cfg(feature = "mem-repo")]
Command::Install(_) => "install",
#[cfg(feature = "mem-repo")]
Command::Uninstall(_) => "uninstall",
Command::VerifyAnchors(_) => "verify-anchors",
Command::Link(_) => "link",
Command::Publish(_) => "publish",
Command::Unpublish(_) => "unpublish",
Command::Domain { .. } => "domain",
Command::Admin { .. } => "admin",
Command::Login(_) => "login",
Command::Logout(_) => "logout",
Command::Create(_) => "create",
Command::Update(_) => "update",
Command::Relate(_) => "relate",
Command::Delete(_) => "delete",
Command::Rename(_) => "rename",
#[cfg(feature = "mem-repo")]
Command::BatchUpdate(_) => "batch-update",
#[cfg(feature = "mem-repo")]
Command::BatchCreate(_) => "batch-create",
#[cfg(feature = "mem-repo")]
Command::BatchRelate(_) => "batch-relate",
#[cfg(feature = "mem-repo")]
Command::Recover(_) => "recover",
Command::Anchors(_) => "anchors",
Command::Changes(_) => "changes",
Command::Check(_) => "check",
Command::ReviewMark(_) => "review-mark",
Command::Reload(_) => "reload",
#[cfg(feature = "mem-repo")]
Command::Fetch(_) => "fetch",
#[cfg(feature = "mem-repo")]
Command::Pull(_) => "pull",
#[cfg(feature = "mem-repo")]
Command::Push(_) => "push",
#[cfg(feature = "mem-repo")]
Command::BranchReset(_) => "branch-reset",
#[cfg(feature = "mem-repo")]
Command::Mem { .. } => "mem",
#[cfg(feature = "mem-repo")]
Command::MemRepo { .. } => "mem-repo",
#[cfg(feature = "mem-repo")]
Command::Workspace { .. } => "workspace",
Command::Schema(_) => "schema",
Command::Projection(_) => "projection",
}
}
}