mod commands;
use clap::{Parser, Subcommand};
const QUICKSTART: &str = "\
QUICKSTART
weave setup configure this repo, then `git merge` as normal
# ... conflict? read the `refused_by:` line inside the markers, then:
weave explain <file> per-hunk detail: which lines both sides wrote
# ... edit the file to resolve it, then:
weave check verify the resolution against the merge stages
weave setup --global make weave the default driver for every repo";
#[derive(Parser)]
#[command(
name = "weave",
about = "Entity-level semantic merge for Git",
version,
after_long_help = QUICKSTART
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Setup {
#[arg(long)]
driver: Option<String>,
#[arg(long)]
local: bool,
#[arg(long)]
global: bool,
},
Unsetup,
Apply {
files: Vec<String>,
},
Preview {
branch: String,
#[arg(long)]
file: Option<String>,
},
Status {
#[arg(long)]
file: Option<String>,
#[arg(long)]
agent: Option<String>,
},
Claim {
agent_id: String,
file_path: String,
entity_name: String,
},
Explain {
file: String,
#[arg(long)]
json: bool,
},
Check {
#[arg(long)]
json: bool,
#[arg(long)]
base: Option<String>,
#[arg(long)]
ours: Option<String>,
#[arg(long)]
theirs: Option<String>,
#[arg(long)]
base_dir: Option<String>,
#[arg(long)]
ours_dir: Option<String>,
#[arg(long)]
theirs_dir: Option<String>,
},
Patch {
#[command(subcommand)]
command: PatchCommands,
},
Bench,
BenchRepo {
repo: String,
#[arg(long, default_value_t = 500)]
limit: usize,
#[arg(long)]
show_diff: bool,
#[arg(long)]
save: Option<String>,
},
Stats,
Summary {
file: String,
#[arg(long)]
json: bool,
},
Release {
agent_id: String,
file_path: String,
entity_name: String,
},
}
#[derive(Subcommand)]
enum PatchCommands {
Extract {
base_file: String,
changed_file: String,
#[arg(long)]
path: Option<String>,
#[arg(long)]
embed_base: bool,
#[arg(short, long)]
output: Option<String>,
},
Apply {
ops_file: String,
target_file: String,
#[arg(long)]
base: Option<String>,
#[arg(short, long)]
output: Option<String>,
#[arg(long)]
in_place: bool,
},
}
fn main() {
let cli = Cli::parse();
let host = weave_core::host::Host {
line_merge: Some(weave_core::host::git_line_merge),
..Default::default()
};
let result = match cli.command {
Commands::Setup {
ref driver,
local,
global,
} => commands::setup::run(driver.as_deref(), local, global),
Commands::Unsetup => commands::setup::unsetup(),
Commands::Apply { ref files } => commands::apply::run(files),
Commands::Preview {
ref branch,
ref file,
} => commands::preview::run(branch, file.as_deref(), &host),
Commands::Status {
ref file,
ref agent,
} => commands::status::run(file.as_deref(), agent.as_deref()),
Commands::Explain { ref file, json } => commands::explain::run(file, json, &host),
Commands::Check {
json,
ref base,
ref ours,
ref theirs,
ref base_dir,
ref ours_dir,
ref theirs_dir,
} => commands::check::run(commands::check::Args {
base: base.as_deref(),
ours: ours.as_deref(),
theirs: theirs.as_deref(),
base_dir: base_dir.as_deref(),
ours_dir: ours_dir.as_deref(),
theirs_dir: theirs_dir.as_deref(),
json,
}),
Commands::Patch { ref command } => match command {
PatchCommands::Extract {
ref base_file,
ref changed_file,
ref path,
embed_base,
ref output,
} => commands::patch::extract(
base_file,
changed_file,
path.as_deref(),
*embed_base,
output.as_deref(),
),
PatchCommands::Apply {
ref ops_file,
ref target_file,
ref base,
ref output,
in_place,
} => commands::patch::apply(
ops_file,
target_file,
base.as_deref(),
output.as_deref(),
*in_place,
&host,
),
},
Commands::Bench => commands::bench::run(&host),
Commands::BenchRepo {
ref repo,
limit,
show_diff,
ref save,
} => commands::bench_repo::run(repo, limit, show_diff, save.as_deref(), &host),
Commands::Stats => commands::stats::run(),
Commands::Summary { ref file, json } => commands::summary::run(file, json),
Commands::Claim {
ref agent_id,
ref file_path,
ref entity_name,
} => commands::claim::run(agent_id, file_path, entity_name),
Commands::Release {
ref agent_id,
ref file_path,
ref entity_name,
} => commands::release::run(agent_id, file_path, entity_name),
};
if let Err(e) = result {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}