use std::net::SocketAddr;
use std::path::PathBuf;
use clap::{Parser, Subcommand, ValueEnum};
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum TransportType {
Stdio,
Http,
}
#[derive(Parser)]
#[command(
name = "okc",
version,
about = "Open Knowledge Catalog - index and query markdown knowledge bases"
)]
pub struct Cli {
#[arg(long, global = true)]
pub config: Option<PathBuf>,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
Scan {
#[arg(short, long)]
root: Vec<PathBuf>,
},
Browse {
path: Option<String>,
#[arg(short, long, default_value = "1")]
depth: usize,
#[arg(short, long, default_value = "100")]
limit: usize,
},
Get {
path: String,
#[arg(short, long, value_delimiter = ',')]
include: Vec<String>,
#[arg(long, default_value = "12000")]
max_chars: usize,
},
Section {
path: String,
heading: String,
#[arg(long, default_value = "5000")]
max_chars: usize,
},
Search {
query: String,
#[arg(short = 'p', long)]
path_prefix: Option<String>,
#[arg(short = 'T', long, value_delimiter = ',')]
types: Vec<String>,
#[arg(short = 'g', long, value_delimiter = ',')]
tags: Vec<String>,
#[arg(short, long, default_value = "20")]
limit: usize,
},
Metadata {
#[arg(short, long, value_parser = parse_key_val)]
filter: Vec<(String, String)>,
#[arg(short, long, value_delimiter = ',')]
select: Vec<String>,
#[arg(short, long, default_value = "100")]
limit: usize,
},
Links {
path: String,
},
Backlinks {
path: String,
#[arg(short, long, default_value = "50")]
limit: usize,
},
Traverse {
start: String,
#[arg(short, long, value_delimiter = ',')]
relations: Vec<String>,
#[arg(long, default_value = "3")]
max_depth: usize,
#[arg(long, default_value = "50")]
max_nodes: usize,
},
Validate {
#[arg(long)]
json: bool,
},
Stats,
Serve {
#[arg(short, long)]
root: Vec<PathBuf>,
#[arg(long, value_enum, default_value = "stdio")]
transport: TransportType,
#[arg(long, default_value = "127.0.0.1")]
host: String,
#[arg(long, default_value = "3000")]
port: u16,
},
Watch {
#[arg(short, long)]
root: Vec<PathBuf>,
#[arg(long)]
skip_initial: bool,
#[arg(long, default_value = "500")]
debounce: u64,
#[arg(long, default_value = "600")]
reconcile: u64,
},
}
fn parse_key_val(s: &str) -> Result<(String, String), String> {
let pos = s
.find('=')
.ok_or_else(|| format!("invalid KEY=value: no `=` in `{s}`"))?;
Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
}