1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Worktree CLI binary — open GitHub issues as git worktree workspaces.
#![allow(missing_docs)] // binary crate; public API lives in the library
use anyhow::Result;
use clap::{Parser, Subcommand};
mod commands;
use commands::config::{cmd_config, ConfigAction};
use commands::list::cmd_list;
use commands::open::cmd_open;
use commands::open_multi::cmd_open_multi;
use commands::prune::cmd_prune;
use commands::restore::cmd_restore;
use commands::scheme::{cmd_scheme, SchemeAction};
use commands::setup::cmd_setup;
#[derive(Parser)]
#[command(
name = "worktree",
about = "Open GitHub issues as git worktree workspaces",
version
)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
/// Parse an issue reference, create a worktree, and open it
Open {
/// Issue reference (omit to detect from current repo's origin remote)
#[arg(value_name = "REF")]
issue_ref: Option<String>,
/// Force open in editor
#[arg(long)]
editor: bool,
/// Skip pre/post-open hooks
#[arg(long)]
no_hooks: bool,
/// Skip opening editor/terminal (hooks still run); useful for programmatic invocation
#[arg(long)]
headless: bool,
},
/// Open multiple repos as a unified workspace under ~/workspaces/<name>/
#[command(name = "open-multi")]
OpenMulti {
/// Issue references (owner/repo#N or full GitHub URL), at least two
#[arg(value_name = "REF", num_args = 1..)]
refs: Vec<String>,
/// Skip pre/post-open hooks
#[arg(long)]
no_hooks: bool,
},
/// Manage worktree configuration
Config {
#[command(subcommand)]
action: ConfigAction,
},
/// Manage the worktree:// URL scheme handler
Scheme {
#[command(subcommand)]
action: SchemeAction,
},
/// List all registered workspaces with their TTL status
List {
/// Emit a JSON report to stdout instead of human-readable output
#[arg(long)]
json: bool,
},
/// Remove expired worktrees based on workspace.ttl config
Prune {
/// Emit a JSON report to stdout instead of human-readable output
#[arg(long)]
json: bool,
},
/// Restore worktrees whose directories were manually deleted
Restore,
/// Run first-time setup: detect editor, write config, register URL scheme
Setup,
/// Print the current version
Version,
}
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::Open {
issue_ref,
editor,
no_hooks,
headless,
} => cmd_open(issue_ref.as_deref(), editor, no_hooks, headless)?,
Commands::OpenMulti { refs, no_hooks } => cmd_open_multi(&refs, no_hooks)?,
Commands::Config { action } => cmd_config(action)?,
Commands::List { json } => cmd_list(json)?,
Commands::Prune { json } => cmd_prune(json)?,
Commands::Restore => cmd_restore()?,
Commands::Scheme { action } => cmd_scheme(action)?,
Commands::Setup => cmd_setup()?,
Commands::Version => println!("{}", env!("CARGO_PKG_VERSION")),
}
Ok(())
}