cli: proper clap subcommands for daemon + expanded help
Convert daemon from hand-rolled string dispatch to proper clap Subcommand enum with typed args. Add custom top-level help that expands nested subcommands (same pattern as bcachefs-tools), so `poc-memory --help` shows full paths like `agent daemon run`.
This commit is contained in:
parent
bcf13c564a
commit
c22a7a72e1
1 changed files with 87 additions and 33 deletions
|
|
@ -408,15 +408,42 @@ enum GraphCmd {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum DaemonCmd {
|
||||
/// Start the daemon (default)
|
||||
Start,
|
||||
/// Show daemon status
|
||||
Status,
|
||||
/// Show daemon log
|
||||
Log {
|
||||
/// Job name to filter by
|
||||
job: Option<String>,
|
||||
/// Number of lines to show
|
||||
#[arg(long, default_value_t = 20)]
|
||||
lines: usize,
|
||||
},
|
||||
/// Install systemd service
|
||||
Install,
|
||||
/// Trigger consolidation via daemon
|
||||
Consolidate,
|
||||
/// Run an agent via the daemon
|
||||
Run {
|
||||
/// Agent name (e.g. organize, replay, linker)
|
||||
#[arg(default_value = "replay")]
|
||||
agent: String,
|
||||
/// Batch size
|
||||
#[arg(default_value_t = 1)]
|
||||
count: usize,
|
||||
},
|
||||
/// Interactive TUI
|
||||
Tui,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum AgentCmd {
|
||||
/// Background job daemon
|
||||
Daemon {
|
||||
/// Subcommand: status, log, install
|
||||
sub: Option<String>,
|
||||
/// Additional arguments
|
||||
args: Vec<String>,
|
||||
},
|
||||
#[command(subcommand)]
|
||||
Daemon(DaemonCmd),
|
||||
/// Run knowledge agents to convergence
|
||||
#[command(name = "knowledge-loop")]
|
||||
KnowledgeLoop {
|
||||
|
|
@ -596,7 +623,52 @@ enum DigestLevel {
|
|||
Auto,
|
||||
}
|
||||
|
||||
/// Print help with subcommands expanded to show nested commands.
|
||||
fn print_help() {
|
||||
use clap::CommandFactory;
|
||||
let cmd = Cli::command();
|
||||
|
||||
println!("poc-memory - graph-structured memory store");
|
||||
println!("usage: poc-memory <command> [<args>]\n");
|
||||
|
||||
for sub in cmd.get_subcommands() {
|
||||
if sub.get_name() == "help" { continue }
|
||||
let children: Vec<_> = sub.get_subcommands()
|
||||
.filter(|c| c.get_name() != "help")
|
||||
.collect();
|
||||
if !children.is_empty() {
|
||||
for child in &children {
|
||||
let about = child.get_about().map(|s| s.to_string()).unwrap_or_default();
|
||||
let full = format!("{} {}", sub.get_name(), child.get_name());
|
||||
// Recurse one more level for daemon subcommands etc.
|
||||
let grandchildren: Vec<_> = child.get_subcommands()
|
||||
.filter(|c| c.get_name() != "help")
|
||||
.collect();
|
||||
if !grandchildren.is_empty() {
|
||||
for gc in grandchildren {
|
||||
let gc_about = gc.get_about().map(|s| s.to_string()).unwrap_or_default();
|
||||
let gc_full = format!("{} {}", full, gc.get_name());
|
||||
println!(" {:<34}{gc_about}", gc_full);
|
||||
}
|
||||
} else {
|
||||
println!(" {:<34}{about}", full);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let about = sub.get_about().map(|s| s.to_string()).unwrap_or_default();
|
||||
println!(" {:<34}{about}", sub.get_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Handle --help ourselves for expanded subcommand display
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() <= 1 || args.iter().any(|a| a == "--help" || a == "-h") && args.len() == 2 {
|
||||
print_help();
|
||||
return;
|
||||
}
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
let result = match cli.command {
|
||||
|
|
@ -660,7 +732,7 @@ fn main() {
|
|||
|
||||
// Agent
|
||||
Command::Agent(sub) => match sub {
|
||||
AgentCmd::Daemon { sub, args } => cmd_daemon(sub.as_deref(), &args),
|
||||
AgentCmd::Daemon(sub) => cmd_daemon(sub),
|
||||
AgentCmd::KnowledgeLoop { max_cycles, batch_size, window, max_depth }
|
||||
=> cmd_knowledge_loop(max_cycles, batch_size, window, max_depth),
|
||||
AgentCmd::ConsolidateBatch { count, auto, agent }
|
||||
|
|
@ -2681,33 +2753,15 @@ fn cmd_lookups(date: Option<&str>) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn cmd_daemon(sub: Option<&str>, args: &[String]) -> Result<(), String> {
|
||||
fn cmd_daemon(sub: DaemonCmd) -> Result<(), String> {
|
||||
match sub {
|
||||
None => daemon::run_daemon(),
|
||||
Some("status") => daemon::show_status(),
|
||||
Some("log") => {
|
||||
let (job, lines) = match args.first() {
|
||||
None => (None, 20),
|
||||
Some(s) => {
|
||||
if let Ok(n) = s.parse::<usize>() {
|
||||
(None, n)
|
||||
} else {
|
||||
let n = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(20);
|
||||
(Some(s.as_str()), n)
|
||||
}
|
||||
}
|
||||
};
|
||||
daemon::show_log(job, lines)
|
||||
}
|
||||
Some("install") => daemon::install_service(),
|
||||
Some("consolidate") => daemon::rpc_consolidate(),
|
||||
Some("run-agent") | Some("run") => {
|
||||
let agent = args.first().map(|s| s.as_str()).unwrap_or("replay");
|
||||
let count: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(1);
|
||||
daemon::rpc_run_agent(agent, count)
|
||||
}
|
||||
Some("tui") => tui::run_tui(),
|
||||
Some(other) => Err(format!("unknown daemon subcommand: {}", other)),
|
||||
DaemonCmd::Start => daemon::run_daemon(),
|
||||
DaemonCmd::Status => daemon::show_status(),
|
||||
DaemonCmd::Log { job, lines } => daemon::show_log(job.as_deref(), lines),
|
||||
DaemonCmd::Install => daemon::install_service(),
|
||||
DaemonCmd::Consolidate => daemon::rpc_consolidate(),
|
||||
DaemonCmd::Run { agent, count } => daemon::rpc_run_agent(&agent, count),
|
||||
DaemonCmd::Tui => tui::run_tui(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue