#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle init # initialize the current directory
heddle init my-project # initialize a subdirectory
heddle init --principal-name 'Ada Lovelace' # set attribution at init time
")]
pub struct InitArgs {
pub path: Option<std::path::PathBuf>,
#[arg(long)]
pub principal_name: Option<String>,
#[arg(long)]
pub principal_email: Option<String>,
#[arg(long)]
pub install_harnesses: Option<String>,
#[arg(long)]
pub no_harness_install: bool,
#[arg(long, visible_alias = "scope", default_value = "repo")]
pub harness_install_scope: String,
#[arg(long)]
pub harness_install_force: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct DiagnoseArgs {
#[arg(long)]
pub profile: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct DoctorArgs {
#[arg(long, global = false)]
pub profile: bool,
#[command(subcommand)]
pub command: Option<DoctorCommands>,
}
#[derive(Clone, Debug, clap::Subcommand)]
pub enum DoctorCommands {
Docs(DoctorDocsArgs),
Schemas,
}
#[derive(Clone, Debug, clap::Args)]
pub struct DoctorDocsArgs {
#[arg(long, value_name = "PATH")]
pub path: Vec<std::path::PathBuf>,
#[arg(long)]
pub all: bool,
}
#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle capture -m 'add login route' # capture the worktree with intent
heddle capture -m 'wip' --confidence 0.6 # honest confidence on a draft step
heddle capture --split --into auth -- src/ # move dirty paths into a sibling thread
")]
pub struct SnapshotArgs {
#[arg(short = 'm', long)]
pub intent: Option<String>,
#[arg(long)]
pub confidence: Option<f32>,
#[arg(short, long)]
pub force: bool,
#[arg(long)]
pub agent_provider: Option<String>,
#[arg(long)]
pub agent_model: Option<String>,
#[arg(long)]
pub agent_session: Option<String>,
#[arg(long)]
pub agent_segment: Option<String>,
#[arg(long)]
pub policy: Option<String>,
#[arg(long)]
pub no_policy: bool,
#[arg(long)]
pub no_agent: bool,
#[arg(long)]
pub split: bool,
#[arg(long, requires = "split")]
pub into: Option<String>,
#[arg(long = "path", requires = "split", value_name = "PATH")]
pub paths: Vec<String>,
}
#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle log # walk the current thread
heddle log --oneline -n 20 # 20 most recent states in compact form
heddle log --reflog # include re-attributed history
heddle log --paths src/auth.rs # restrict to states touching a path
")]
pub struct LogArgs {
pub state: Option<String>,
#[arg(short = 'n', long, default_value = "20")]
pub limit: usize,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub graph: bool,
#[arg(long)]
pub oneline: bool,
#[arg(long)]
pub reflog: bool,
#[arg(long)]
pub agent: Option<String>,
#[arg(long = "path", value_name = "PATH")]
pub paths: Vec<String>,
#[arg(long, value_name = "STATE")]
pub since: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct RetroArgs {
#[arg(long)]
pub since: Option<String>,
#[arg(long)]
pub include_merges: bool,
#[arg(long)]
pub include_undos: bool,
#[arg(long = "full", alias = "expand")]
pub full: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct DiffArgs {
pub from: Option<String>,
pub to: Option<String>,
#[arg(long)]
pub semantic: bool,
#[arg(long)]
pub stat: bool,
#[arg(long)]
pub name_only: bool,
#[arg(short = 'U', long = "unified", default_value_t = 3)]
pub unified: usize,
#[arg(long)]
pub context: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct RevertArgs {
pub state: String,
#[arg(short = 'm', long)]
pub message: Option<String>,
#[arg(long)]
pub no_commit: bool,
}
#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle undo # roll back the most recent operation
heddle undo -n 3 # roll back the last three operations
heddle undo --list # preview undoable operations on this thread
heddle undo --preview # show what would change without applying
")]
pub struct UndoArgs {
#[arg(short = 'n', long, default_value = "1")]
pub steps: usize,
#[arg(long)]
pub list: bool,
#[arg(long, default_value = "20")]
pub depth: usize,
#[arg(long)]
pub preview: bool,
}
#[derive(Clone, Copy, Debug, clap::ValueEnum, PartialEq, Eq)]
pub enum WorkspaceModeArg {
#[value(alias = "private")]
Auto,
#[value(alias = "visible")]
Heavy,
Light,
}
#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle start feature/auth # create or resume a thread
heddle start feature/auth --workspace heavy # real checkout on disk
heddle start scratch --path ../scratch # place the checkout explicitly
heddle start fix-flake --task 'fix CI flake' # attach a task description
")]
pub struct ThreadStartArgs {
pub name: String,
#[arg(long)]
pub from: Option<String>,
#[arg(long)]
pub path: Option<std::path::PathBuf>,
#[arg(long, value_enum, default_value_t = WorkspaceModeArg::Auto)]
pub workspace: WorkspaceModeArg,
#[arg(long)]
pub agent_provider: Option<String>,
#[arg(long)]
pub agent_model: Option<String>,
#[arg(long)]
pub task: Option<String>,
#[arg(long, hide = true)]
pub parent_thread: Option<String>,
#[arg(long, hide = true)]
pub automated: bool,
#[arg(long, conflicts_with_all = ["agent_provider", "agent_model"])]
pub print_cd_path: bool,
#[arg(
long,
overrides_with = "no_daemon",
action = clap::ArgAction::SetTrue,
default_value_t = true,
)]
pub daemon: bool,
#[arg(
long,
overrides_with = "daemon",
action = clap::ArgAction::SetTrue,
)]
pub no_daemon: bool,
#[arg(long)]
pub shared_target: bool,
}
#[derive(Clone, Debug, clap::Args)]
#[command(after_help = "\
Examples:
heddle merge feature/auth --preview # structured blockers + recommendation
heddle merge feature/auth -m 'land auth' # integrate with a commit message
heddle merge feature/auth --with-diff # preview with the resulting diff
heddle merge feature/auth --semantic # use semantic merge for code edits
")]
pub struct MergeArgs {
pub thread: String,
#[arg(short = 'm', long)]
pub message: Option<String>,
#[arg(long)]
pub no_commit: bool,
#[arg(long)]
pub preview: bool,
#[arg(long = "with-diff")]
pub with_diff: bool,
#[arg(long)]
pub semantic: bool,
#[arg(long = "git-commit")]
pub git_commit: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct TryArgs {
#[arg(long)]
pub name: Option<String>,
#[arg(long, value_enum, default_value_t = WorkspaceModeArg::Heavy)]
pub workspace: WorkspaceModeArg,
#[arg(long = "auto-merge")]
pub auto_merge: bool,
#[arg(long = "keep-on-success")]
pub keep_on_success: bool,
#[arg(required = true, trailing_var_arg = true, allow_hyphen_values = true)]
pub command: Vec<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AttemptArgs {
pub n: u32,
#[arg(long, value_enum, default_value_t = WorkspaceModeArg::Heavy)]
pub workspace: WorkspaceModeArg,
#[arg(long = "shared-target", overrides_with = "no_shared_target")]
pub shared_target: bool,
#[arg(long = "no-shared-target", overrides_with = "shared_target")]
pub no_shared_target: bool,
#[arg(long = "name-prefix")]
pub name_prefix: Option<String>,
#[arg(long)]
pub evaluate: Option<String>,
#[arg(required = true, trailing_var_arg = true, allow_hyphen_values = true)]
pub command: Vec<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct RunArgs {
#[arg(long = "thread")]
pub thread: Option<String>,
#[arg(required = true, trailing_var_arg = true, allow_hyphen_values = true)]
pub command: Vec<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ReadyArgs {
#[arg(long = "thread")]
pub thread: Option<String>,
#[arg(short = 'm', long)]
pub message: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SyncArgs {
#[arg(long = "thread")]
pub thread: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ShipArgs {
#[arg(long = "thread")]
pub thread: Option<String>,
#[arg(short = 'm', long)]
pub message: Option<String>,
#[arg(long)]
pub push: bool,
#[arg(long)]
pub no_push: bool,
#[arg(long)]
pub remote: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DelegatedTaskSpec {
pub task: String,
pub provider: Option<String>,
pub model: Option<String>,
}
pub fn parse_delegated_task(s: &str) -> Result<DelegatedTaskSpec, String> {
let mut parts = s.splitn(3, ':');
let task = parts
.next()
.ok_or_else(|| "empty task spec".to_string())?
.to_string();
if task.is_empty() {
return Err("delegated task label may not be empty".to_string());
}
let provider = parts
.next()
.map(|s| s.to_string())
.filter(|s| !s.is_empty());
let model = parts
.next()
.map(|s| s.to_string())
.filter(|s| !s.is_empty());
if model.is_some() && provider.is_none() {
return Err(format!(
"delegated task spec {s:?} has a model but no provider; \
expected `task:provider:model` or `task:provider` or `task`"
));
}
Ok(DelegatedTaskSpec {
task,
provider,
model,
})
}
#[derive(Clone, Debug, clap::Args)]
pub struct DelegateArgs {
#[arg(required = true, value_parser = parse_delegated_task)]
pub tasks: Vec<DelegatedTaskSpec>,
#[arg(long)]
pub parent: Option<String>,
#[arg(long, value_enum)]
pub workspace: Option<WorkspaceModeArg>,
#[arg(long)]
pub path_prefix: Option<std::path::PathBuf>,
#[arg(long)]
pub agent_provider: Option<String>,
#[arg(long)]
pub agent_model: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadShowArgs {
pub thread: Option<String>,
#[arg(long)]
pub watch: bool,
#[arg(long, hide = true)]
pub watch_iterations: Option<usize>,
#[arg(long, hide = true)]
pub watch_interval_ms: Option<u64>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadCapturesArgs {
pub thread: Option<String>,
#[arg(long, default_value_t = 20)]
pub limit: usize,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadNameArgs {
pub thread: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadRenameArgs {
pub old: String,
pub new: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadPromoteArgs {
pub thread: String,
#[arg(long)]
pub path: Option<std::path::PathBuf>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadMoveArgs {
pub from: String,
pub to: String,
#[arg(long = "path", required = true, value_name = "PATH")]
pub paths: Vec<String>,
#[arg(short = 'm', long)]
pub message: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadAbsorbArgs {
pub thread: String,
#[arg(long)]
pub into: Option<String>,
#[arg(short = 'm', long)]
pub message: Option<String>,
#[arg(long)]
pub preview: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadResolveArgs {
pub thread: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadDropArgs {
pub thread: String,
#[arg(long)]
pub delete_thread: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadApproveArgs {
pub source: String,
pub target: String,
#[arg(long)]
pub note: Option<String>,
#[arg(long, default_value = "origin")]
pub remote: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadApprovalsArgs {
pub source: String,
pub target: String,
#[arg(long, default_value = "origin")]
pub remote: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadRevokeApprovalArgs {
pub id: String,
#[arg(long, default_value = "origin")]
pub remote: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ThreadCheckMergeArgs {
pub source: String,
pub target: String,
#[arg(long, default_value = "merge")]
pub gated_action: String,
#[arg(long = "path", value_delimiter = ',')]
pub changed_paths: Vec<String>,
#[arg(long, default_value = "origin")]
pub remote: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct CollapseArgs {
#[arg(required = true)]
pub states: Vec<String>,
#[arg(long)]
pub into: String,
#[arg(long)]
pub confidence: Option<f32>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ResolveArgs {
pub path: Option<String>,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub list: bool,
#[arg(long, conflicts_with = "theirs")]
pub ours: bool,
#[arg(long, conflicts_with = "ours")]
pub theirs: bool,
#[arg(long)]
pub abort: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct RemoteOperationArgs {
pub remote: Option<String>,
#[arg(short, long)]
pub thread: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct PushArgs {
#[command(flatten)]
pub remote_op: RemoteOperationArgs,
#[arg(short, long)]
pub state: Option<String>,
#[arg(short, long)]
pub force: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct PullArgs {
#[command(flatten)]
pub remote_op: RemoteOperationArgs,
#[arg(short, long)]
pub local_thread: Option<String>,
#[arg(long)]
pub lazy: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct CloneArgs {
pub remote: String,
pub local: String,
#[arg(long)]
pub thread: Option<String>,
#[arg(long)]
pub depth: Option<u32>,
#[arg(long)]
pub lazy: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SessionStartArgs {
#[arg(long)]
pub provider: String,
#[arg(long)]
pub model: String,
#[arg(long)]
pub policy: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SessionSegmentArgs {
#[arg(long)]
pub provider: String,
#[arg(long)]
pub model: String,
#[arg(long)]
pub policy: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SessionEndArgs {
pub session_id: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SessionShowArgs {
pub session_id: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct SessionListArgs {
#[arg(long)]
pub active: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct WorktreeAddArgs {
pub path: std::path::PathBuf,
#[arg(long)]
pub thread: Option<String>,
#[arg(long)]
pub from: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct WorktreeRemoveArgs {
pub path: std::path::PathBuf,
#[arg(long)]
pub delete_thread: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ActorSpawnArgs {
#[arg(long)]
pub thread: Option<String>,
#[arg(long)]
pub provider: Option<String>,
#[arg(long)]
pub model: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ActorListArgs {
#[arg(long)]
pub active: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ActorShowArgs {
pub session: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ActorExplainArgs {
pub session: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct ActorDoneArgs {
#[arg(long)]
pub session: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentReserveArgs {
#[arg(long)]
pub thread: String,
#[arg(long)]
pub anchor: Option<String>,
#[arg(long)]
pub task: Option<String>,
#[arg(long, value_name = "PID")]
pub hold_for_pid: Option<u32>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentHeartbeatArgs {
#[arg(long)]
pub session: String,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentReleaseArgs {
#[arg(long)]
pub session: String,
#[arg(long, default_value = "complete")]
pub status: AgentReleaseStatusArg,
}
#[derive(Clone, Debug, clap::ValueEnum)]
pub enum AgentReleaseStatusArg {
Complete,
Abandoned,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentApiListArgs {
#[arg(long)]
pub thread: Option<String>,
#[arg(long)]
pub alive_only: bool,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentCaptureArgs {
#[arg(long)]
pub session: String,
#[arg(long, short = 'm', alias = "intent")]
pub message: Option<String>,
#[arg(long)]
pub confidence: Option<f32>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct AgentReadyArgs {
#[arg(long)]
pub session: String,
#[arg(long, short = 'm')]
pub message: Option<String>,
}
#[derive(Clone, Debug, clap::Args)]
pub struct WatchArgs {
#[arg(long, value_name = "DURATION")]
pub since: Option<String>,
#[arg(long, value_name = "KINDS")]
pub filter: Option<String>,
#[arg(long)]
pub json: bool,
#[arg(long, hide = true)]
pub max_iterations: Option<usize>,
#[arg(long, hide = true)]
pub poll_interval_ms: Option<u64>,
}