use std::net::SocketAddr;
use clap::{Parser, Subcommand};
mod actions;
pub(crate) use actions::*;
pub(crate) use crate::cli_manager::ManagerAction;
#[cfg(test)]
pub(crate) const DEFAULT_URL: &str = trusty_mpm::core::DEFAULT_DAEMON_URL;
pub(crate) const DEFAULT_ADDR: &str = trusty_mpm::core::DEFAULT_DAEMON_ADDR;
#[derive(Debug, Parser)]
#[command(
name = "trusty-mpm",
version,
about = "trusty-mpm — unified binary",
subcommand_required = false,
arg_required_else_help = false,
infer_subcommands = true
)]
pub(crate) struct Cli {
#[arg(long, env = "TRUSTY_MPM_URL", global = true)]
pub(crate) url: Option<String>,
#[command(subcommand)]
pub(crate) command: Option<Command>,
}
#[derive(Debug, Subcommand)]
pub(crate) enum Command {
Status,
Start,
Serve {
#[arg(long)]
stdio: bool,
},
Stop,
Restart,
Project {
#[command(subcommand)]
action: ProjectAction,
},
Sessions {
#[command(subcommand)]
action: SessionAction,
},
#[command(name = "session", hide = true)]
Session {
#[command(subcommand)]
action: SessionAction,
},
#[command(name = "internal-spawn-disclaimed", hide = true)]
InternalSpawnDisclaimed {
#[arg(trailing_var_arg = true, allow_hyphen_values = true, num_args = 1..)]
argv: Vec<String>,
},
Projects {
#[command(subcommand)]
action: ProjectsAction,
},
Manager {
#[command(subcommand)]
action: ManagerAction,
},
Events,
Doctor {
#[command(flatten)]
flags: DoctorFlags,
},
Validate {
#[arg(long)]
path: Option<std::path::PathBuf>,
#[arg(long)]
repair: bool,
},
Hooks {
#[command(subcommand)]
action: HooksAction,
},
Agent {
#[command(subcommand)]
action: AgentAction,
},
Generate {
#[command(subcommand)]
action: GenerateAction,
},
Health,
Tui {
#[arg(long, env = "TRUSTY_MPM_URL")]
url: Option<String>,
#[arg(long, default_value_t = 1000)]
interval_ms: u64,
},
Gui,
Telegram {
#[command(subcommand)]
cmd: TelegramCmd,
},
Slack {
#[command(subcommand)]
cmd: SlackCmd,
},
Install {
#[arg(long)]
force: bool,
#[arg(long, num_args = 0.., value_delimiter = ',')]
reset_agents: Option<Vec<String>>,
#[arg(long, requires = "reset_agents")]
reset_agents_workspaces: bool,
#[arg(long)]
reconcile_skills: bool,
},
Reinstall(ReinstallArgs),
Hook {
#[arg(long)]
pm_guard: bool,
},
Memory {
#[command(subcommand)]
action: MemoryAction,
},
Compress {
#[arg(long)]
tool: String,
},
Daemon {
#[arg(long, env = "TRUSTY_MPM_ADDR", default_value = DEFAULT_ADDR)]
addr: SocketAddr,
#[arg(long, env = "TRUSTY_MPM_TAILSCALE")]
tailscale: bool,
#[arg(long)]
mcp: bool,
#[arg(long)]
force: bool,
},
Supervisor {
#[arg(long, env = "TRUSTY_MPM_SUPERVISOR_ADDR")]
addr: Option<SocketAddr>,
#[arg(long)]
interval: Option<u64>,
#[arg(long)]
auto_resume: bool,
#[arg(long)]
no_classify: bool,
},
Launch {
dir: Option<String>,
#[arg(long)]
style: Option<String>,
#[arg(long)]
worktree: bool,
},
Connect {
dir: Option<String>,
},
Attach {
target: String,
#[arg(long)]
json: bool,
},
Optimizer {
#[command(subcommand)]
action: OptimizerAction,
},
Overseer {
#[command(subcommand)]
action: OverseerAction,
},
#[command(
visible_alias = "sm",
visible_alias = "session-manager",
alias = "coord"
)]
Coordinator {
message: Option<String>,
#[command(subcommand)]
action: Option<CoordinatorAction>,
},
Services {
#[command(subcommand)]
action: ServicesAction,
},
Repair {
#[command(subcommand)]
action: RepairAction,
},
Auth {
#[command(subcommand)]
action: AuthAction,
},
Catalog {
#[command(subcommand)]
action: CatalogAction,
},
Ticket {
issue: String,
#[arg(default_value = "gh", value_enum)]
system: crate::commands::ticket::system::TicketSystemKind,
#[arg(long = "note", short = 'm')]
notes: Vec<String>,
#[arg(long, default_value = "claude-code", value_enum)]
runtime: trusty_mpm::runtime::RuntimeKind,
},
Issue {
#[command(subcommand)]
cmd: IssueCmd,
#[arg(long, default_value = "gh", value_enum, global = true)]
system: crate::commands::ticket::system::TicketSystemKind,
},
Watch {
#[command(subcommand)]
cmd: WatchCmd,
},
Register {
url: String,
alias: Option<String>,
#[arg(long)]
force: bool,
#[arg(long)]
root: Option<String>,
},
#[command(name = "ls")]
Ls {
#[arg(value_name = "SORT|FILTER", num_args = 0..)]
terms: Vec<String>,
#[arg(long, short = 'p')]
projects: bool,
#[arg(long)]
json: bool,
#[arg(long)]
source_id: Option<String>,
#[arg(long, conflicts_with = "source_id")]
current: bool,
#[arg(long)]
all: bool,
#[arg(long)]
root: Option<String>,
},
#[command(name = "f")]
F(FindArgs),
Load {
alias: String,
#[arg(long)]
root: Option<String>,
},
Run {
target: String,
#[arg(long)]
task: Option<String>,
#[arg(long)]
root: Option<String>,
},
Path {
alias: String,
#[arg(long)]
root: Option<String>,
},
ShellInit {
#[arg(value_enum)]
shell: ShellArg,
},
Login {
#[arg(long)]
root: Option<String>,
},
#[command(name = "rm")]
Rm {
alias: String,
#[arg(long)]
root: Option<String>,
},
Update {
alias: Option<String>,
#[arg(long)]
root: Option<String>,
},
#[command(name = "sessctl")]
Sessctl {
#[command(subcommand)]
action: SessctlAction,
},
Meta {
#[command(subcommand)]
action: MetaAction,
},
Statusline,
Banner {
#[arg(long)]
reconnecting: bool,
},
Mcp {
#[command(subcommand)]
cmd: McpCmd,
},
Config(trusty_common::inference::config::ConfigCommand),
}
#[derive(clap::Args, Debug, Clone, PartialEq, Eq)]
#[command(group(
clap::ArgGroup::new("repair")
.args(["fix", "fix_skills"])
.multiple(true)
.required(false)
))]
pub struct DoctorFlags {
#[arg(long, hide = true)]
pub prune_stale_skills: bool,
#[arg(long)]
pub fix_skills: bool,
#[arg(long)]
pub fix: bool,
#[arg(long, requires = "fix")]
pub yes: bool,
#[arg(long, requires = "repair")]
pub include_frozen: bool,
}
#[derive(Debug, Clone, clap::Args)]
pub(crate) struct ReinstallArgs {
#[arg(long)]
pub(crate) force: bool,
#[arg(long)]
pub(crate) binary: bool,
#[arg(long, requires = "binary")]
pub(crate) yes: bool,
}
#[derive(Debug, Clone, clap::Args)]
pub(crate) struct FindArgs {
#[arg(value_name = "PATTERN", num_args = 0..)]
pub(crate) pattern: Vec<String>,
#[arg(long)]
pub(crate) json: bool,
#[arg(long)]
pub(crate) source_id: Option<String>,
#[arg(long, conflicts_with = "source_id")]
pub(crate) current: bool,
#[arg(long)]
pub(crate) all: bool,
}