heddle_cli_args/cli/cli_args/commands_main.rs
1// SPDX-License-Identifier: Apache-2.0
2//! Top-level CLI commands.
3
4use clap::{Args, Subcommand};
5
6#[cfg(feature = "client")]
7use super::AuthCommands;
8#[cfg(feature = "semantic")]
9use super::SemanticCommands;
10use super::{
11 AgentCommands, CompletionSubject, ContextCommands, DiscussCommands, HookCommands,
12 IntegrationCommands, OplogCommands, QueryArgs, RedactCommands, RemoteCommands, ReviewCommands,
13 ShellCommands, ThreadCommands, VisibilityCommands,
14 commands_args::{
15 AdoptArgs, CloneArgs, CollapseArgs, CommitArgs, DiffArgs, DoctorArgs, ExpandArgs, InitArgs,
16 LandArgs, LogArgs, PullArgs, PushArgs, ReadyArgs, ResolveArgs, RetroArgs, RevertArgs,
17 RunArgs, SnapshotArgs, SyncArgs, ThreadStartArgs, TimelineArgs, TryArgs, UndoArgs,
18 WatchArgs,
19 },
20};
21#[cfg(feature = "git-overlay")]
22use super::{ExportCommands, ImportCommands};
23
24#[derive(Clone, Debug, Args)]
25pub struct FsckArgs {
26 /// Full check (includes content verification).
27 #[arg(long)]
28 pub full: bool,
29
30 /// Run slower graph and signature integrity checks.
31 #[arg(long)]
32 pub thorough: bool,
33
34 /// Include Git projection, mapping, notes, and checkout checks.
35 #[arg(long)]
36 pub git: bool,
37
38 #[command(subcommand)]
39 pub command: Option<FsckCommands>,
40}
41
42#[derive(Clone, Debug, Subcommand)]
43pub enum FsckCommands {
44 /// Repair an integrity surface, then verify it.
45 Repair {
46 #[command(subcommand)]
47 target: FsckRepairCommands,
48 },
49}
50
51#[derive(Clone, Debug, Subcommand)]
52pub enum FsckRepairCommands {
53 /// Reconcile Git projection metadata or one projected ref.
54 Git(FsckRepairGitArgs),
55}
56
57#[derive(Clone, Debug, Args)]
58pub struct FsckRepairGitArgs {
59 /// Git ref to reconcile. Required for native repositories.
60 #[arg(long = "ref", value_name = "BRANCH")]
61 pub ref_name: Option<String>,
62
63 /// Assert the intended authority direction.
64 #[arg(long, value_parser = ["git", "heddle"])]
65 pub prefer: Option<String>,
66
67 /// Show the authority-valid repair without changing refs.
68 #[arg(long)]
69 pub preview: bool,
70}
71
72#[derive(Subcommand)]
73pub enum Commands {
74 /// Initialize Heddle in a directory or existing Git checkout.
75 Init(InitArgs),
76
77 /// Adopt Git history into Heddle-native source authority.
78 ///
79 /// Git Overlay is the normal existing-Git mode: Git keeps source objects,
80 /// refs, index, and worktree state while Heddle stores metadata in
81 /// `.heddle`. `adopt` imports history and moves source authority to Heddle.
82 Adopt(AdoptArgs),
83
84 /// Curated, progressive-disclosure help.
85 ///
86 /// `heddle help` prints the curated everyday verbs and points at
87 /// `heddle help advanced` for everything else. `heddle help
88 /// <topic>` prints the topic page (e.g. `daemon`, `signals`,
89 /// `bridge`). `heddle help <command path>` falls through to that
90 /// command's `--help` so the printer never duplicates clap's
91 /// per-verb derivation.
92 Help {
93 /// Topic name (`advanced`, `daemon`, `signals`, …) or command
94 /// path. When omitted, prints the curated default.
95 #[arg(value_name = "TOPIC_OR_COMMAND")]
96 topics: Vec<String>,
97 },
98
99 /// Show what needs attention and the next safe Heddle action.
100 #[command(after_help = "\
101Examples:
102 heddle status # current thread, dirty paths, recommended next step
103 heddle status --short # one-line summary for shell prompts
104 heddle status --watch # live dashboard that refreshes in place
105")]
106 Status {
107 /// Short format.
108 #[arg(short, long)]
109 short: bool,
110
111 /// Continuously refresh status.
112 #[arg(long)]
113 watch: bool,
114
115 /// Internal helper for tests: stop after N watch updates.
116 #[arg(long, hide = true)]
117 watch_iterations: Option<usize>,
118
119 /// Internal helper for tests: polling interval in milliseconds.
120 #[arg(long, hide = true)]
121 watch_interval_ms: Option<u64>,
122 },
123
124 /// Stream live oplog activity.
125 ///
126 /// Tails the repository's append-only oplog file like `tail -f`,
127 /// emitting snapshots, merges, and thread events as they happen.
128 /// Exits on Ctrl-C.
129 Watch(WatchArgs),
130
131 /// Verify this workspace; exits nonzero until every check is clean.
132 #[command(after_help = "\
133Checks: Git mapping, worktree, remote, operation, clone verification, machine contract.
134
135Examples:
136 heddle verify # strict verification gate and next recovery step
137 heddle verify --verbose # full proof rows and machine-contract details
138 heddle verify --output json # proof JSON when clean; error envelope when blocked
139")]
140 Verify,
141
142 /// Explain repository health, or run targeted doctor checks.
143 ///
144 /// `heddle doctor` (no subcommand) reports repository health and
145 /// the next recovery step. `heddle doctor docs` diff-checks markdown
146 /// documentation against
147 /// the actual CLI surface and exits non-zero on drift — wire it
148 /// into CI to stop docs from going stale.
149 Doctor(DoctorArgs),
150
151 /// Print the JSON Schema for a `--output json`-emitting verb.
152 ///
153 /// Contract-table introspection over CLI output shapes —
154 /// useful when wiring tools that consume `heddle <verb>
155 /// --output json` and want to validate or generate types. The schemas
156 /// live in `crates/cli-contract/src/cli/commands/schemas.rs`; the
157 /// command contract table registers available and documented
158 /// schema verbs for `heddle doctor schemas` drift detection
159 /// against `docs/json-schemas.md`.
160 ///
161 /// With no `<verb>`, prints the registered schema verbs. `<verb>`
162 /// is the joined subcommand path — e.g. `status`, `log`,
163 /// `fsck repair git`, `marker list`.
164 #[command(visible_alias = "schema")]
165 Schemas {
166 /// The verb whose schema to emit. Run `heddle schemas --help`
167 /// or look at `docs/json-schemas.md` for the registered list.
168 ///
169 /// `trailing_var_arg = true` lets the verb spec carry literal
170 /// `--flag` tokens (e.g. `heddle schemas log --reflog`,
171 /// `heddle schemas marker delete --prefix`) without clap
172 /// parsing them as options on `schemas` itself.
173 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
174 verb: Vec<String>,
175 },
176
177 /// Create or resume an isolated thread for focused work.
178 Start(ThreadStartArgs),
179
180 /// Run a command in a sandboxed ephemeral thread.
181 ///
182 /// Heddle creates a fresh thread with an isolated checkout, runs
183 /// `<cmd>` inside it, and then either captures the result on a
184 /// zero exit or drops the thread on a non-zero exit. The parent
185 /// thread's working tree is never touched — the ephemeral thread
186 /// is the sandbox. Implements item 3.1 from the heddle 6→8 plan.
187 ///
188 /// `try` is the **new-sandbox** sibling to `run`. Reach for `run`
189 /// when you already have a thread and just want to exec a command
190 /// inside its checkout (no thread creation, no capture, no
191 /// rollback).
192 Try(TryArgs),
193
194 /// Automation/workflow command: run a command inside an existing
195 /// thread's execution root.
196 ///
197 /// `run` is the **existing-thread** sibling to `try`. It looks up
198 /// the named (or current) thread, sets the child's cwd to that
199 /// thread's checkout, exports `HEDDLE_THREAD_*`, and runs `<cmd>`.
200 /// It does NOT create a thread, capture
201 /// state on success, or roll back on failure — those are `try`'s
202 /// job. Reach for `try` when you want the sandbox lifecycle; reach
203 /// for `run` when you already have a thread and just need to exec
204 /// inside it.
205 Run(RunArgs),
206
207 /// Automation/workflow command: refresh the current thread onto its target when safe.
208 Sync(SyncArgs),
209
210 /// Continue the active operation without remembering the specific subcommand.
211 Continue,
212
213 /// Abort the active operation without remembering the specific subcommand.
214 Abort,
215
216 /// Integrate a ready thread into its local target.
217 ///
218 /// `land` is the local integration verb: capture outstanding work if needed,
219 /// refresh against the target when safe, and land the thread. It fails
220 /// closed when conflicts or other blockers exist. Pair it with `ready`
221 /// when you want the verdict and next action before landing anything.
222 Land(LandArgs),
223
224 /// Prepare this thread for review or merge.
225 ///
226 /// `ready` captures outstanding work if needed, checks conflicts,
227 /// blockers, freshness, and semantic risk, then marks the thread
228 /// ready or blocked and prints the next action. It never lands,
229 /// checkpoints, or pushes; use it when you want Heddle's verdict
230 /// before integrating the work.
231 Ready(ReadyArgs),
232
233 /// Capture a recoverable Heddle step for undo, provenance, and review.
234 Capture(SnapshotArgs),
235
236 /// Commit the current captured state to the authoritative Git checkout.
237 Commit(CommitArgs),
238
239 /// Show state history.
240 ///
241 /// By default, when a thread name is given (e.g. `heddle log master`),
242 /// the walk is *first-parent only* — equivalent to `git log
243 /// --first-parent <branch>`. To see every ancestor reachable through
244 /// merge commits, pass `--graph` (which renders the full DAG) or
245 /// `--all` (which lists every state regardless of ancestry).
246 #[command(visible_alias = "history")]
247 Log(LogArgs),
248
249 /// Navigate, fork, reset, and recover agent tool-call timelines.
250 #[command(after_help = "\
251Examples:
252 heddle log --timeline
253 heddle timeline fork --tool-call call_123 --branch tlb-alt
254 heddle timeline reset --step tls-abc --materialize
255 heddle timeline recover
256")]
257 Timeline(TimelineArgs),
258
259 /// Show state details.
260 Show {
261 /// State by physical state ID, logical change ID, or unambiguous prefix.
262 /// Defaults to HEAD.
263 state: Option<String>,
264 },
265
266 /// Summarize a working session.
267 ///
268 /// Combines oplog, agent registry, marker, and context-annotation
269 /// reads into one structured payload — agent-readable retro of
270 /// captures, signals, and notable events since `--since`. Replaces
271 /// the reconstruct-from-`heddle log` boilerplate.
272 Retro(RetroArgs),
273
274 /// Show what changed in the worktree, a thread, or two states.
275 Diff(DiffArgs),
276
277 /// Open or resolve discussions anchored to symbols.
278 ///
279 /// Open a discussion against a symbol; append turns;
280 /// resolve by edit or dismiss. Anchors
281 /// travel across renames and cross-file moves on subsequent
282 /// state mutations.
283 #[command(after_help = "\
284Examples:
285 heddle discuss open src/auth.rs verify 'Should this reject expired tokens?' # anchor a discussion
286 heddle discuss append <id> 'switched to argon2' # add a turn
287 heddle discuss resolve <id> --mode by-edit --state HEAD
288")]
289 Discuss {
290 #[command(subcommand)]
291 command: DiscussCommands,
292 },
293
294 /// Structured query over the operation log. Filter by
295 /// actor, time window, signal kind, symbol, thread, verbs. Returns
296 /// structured results consumable by agents.
297 Query(QueryArgs),
298
299 /// Review a state — render the payload, sign, see signal health.
300 ///
301 /// `heddle review show` renders the review payload (summary,
302 /// agent narrative, in-budget signals, anchored discussions).
303 /// `heddle review sign` submits a `read` / `agent_preview` /
304 /// `agent_co_review` signature on the state. `heddle review
305 /// health` reports per-module signal fire rates over a rolling
306 /// window.
307 #[command(after_help = "\
308Examples:
309 heddle review show HEAD # render the review payload for HEAD
310 heddle review sign HEAD --kind read --public-key <hex> --signature <hex> --signed-at-unix <ts>
311 heddle review health --window 7 # signal fire-rates over recent states
312")]
313 Review {
314 #[command(subcommand)]
315 command: ReviewCommands,
316 },
317
318 /// Redact a sensitive blob in a state so reads return a stub
319 /// instead of the content.
320 ///
321 /// `heddle redact apply` declares a redaction; the blob bytes stay
322 /// on disk and reads return the operator-supplied stub. `heddle
323 /// purge` afterward physically removes the bytes. Both are signed,
324 /// attributed, oplog-audited operations. See
325 /// `docs/PRINCIPLES.md` (the honesty principle) for context.
326 Redact {
327 #[command(subcommand)]
328 command: RedactCommands,
329 },
330
331 /// Declare and inspect a state's audience visibility tier.
332 ///
333 /// `heddle visibility set` binds a tier to a state; `promote` lifts it to
334 /// a less-restrictive tier via a superseding record; `show` reports the
335 /// effective tier; `list` enumerates non-public states. Capture binds the
336 /// inherited `[review.discussion] default_visibility` automatically
337 /// (Invariant A) — these verbs are the explicit operator overrides.
338 Visibility {
339 #[command(subcommand)]
340 command: VisibilityCommands,
341 },
342
343 /// Revert changes from a state.
344 Revert(RevertArgs),
345
346 /// Undo the last Heddle operation.
347 Undo(UndoArgs),
348
349 /// Collapse (squash) multiple states into one.
350 Collapse(CollapseArgs),
351
352 /// Expand a squashed land into the captures it collapsed.
353 Expand(ExpandArgs),
354
355 /// Manage threads.
356 Thread {
357 #[command(subcommand)]
358 command: ThreadCommands,
359 },
360
361 /// Shell integration helpers (auto-cd on thread start/switch/cd).
362 Shell {
363 #[command(subcommand)]
364 command: ShellCommands,
365 },
366
367 /// Internal shell-completion candidate helper.
368 #[command(name = "complete", alias = "__complete", hide = true)]
369 Complete {
370 /// Candidate set to print, one candidate per line.
371 #[arg(value_enum)]
372 subject: CompletionSubject,
373 },
374
375 /// Resolve merge conflicts.
376 Resolve(ResolveArgs),
377
378 /// Verify repository integrity or explicitly repair one surface.
379 Fsck(FsckArgs),
380
381 /// Inspect and repair the operation log.
382 ///
383 /// `heddle oplog recover` explicitly salvages a truncated or torn oplog,
384 /// reporting what was recovered — the operator-facing entrypoint over the
385 /// same recovery the everyday read path runs automatically.
386 Oplog {
387 #[command(subcommand)]
388 command: OplogCommands,
389 },
390
391 /// Import from another version control system.
392 #[cfg(feature = "git-overlay")]
393 Import {
394 #[command(subcommand)]
395 command: ImportCommands,
396 },
397
398 /// Export to another version control system.
399 #[cfg(feature = "git-overlay")]
400 Export {
401 #[command(subcommand)]
402 command: ExportCommands,
403 },
404
405 /// Push the source-authoritative history to a remote.
406 Push(PushArgs),
407
408 /// Pull source-authoritative history from a remote.
409 Pull(PullArgs),
410
411 /// Manage remote repositories.
412 Remote {
413 #[command(subcommand)]
414 command: RemoteCommands,
415 },
416
417 /// Authenticate with a Heddle server.
418 #[cfg(feature = "client")]
419 Auth {
420 #[command(subcommand)]
421 command: AuthCommands,
422 },
423
424 /// Report the acting identity (principal, token kind, scopes, operation
425 /// ceiling, TTL, signing status, server reachability).
426 #[cfg(feature = "client")]
427 #[command(after_help = "\
428Examples:
429 heddle whoami # human-readable identity summary
430 heddle whoami --output json # machine-readable, stable output_kind shape
431 heddle whoami --server grpc.heddle.sh")]
432 Whoami {
433 /// Heddle server address (defaults to the configured server).
434 #[arg(long)]
435 server: Option<String>,
436 },
437
438 /// Manage code context annotations.
439 #[command(after_help = "\
440Examples:
441 heddle context set --path src/auth.rs --scope symbol:verify --kind invariant -m 'returns false on timing mismatch'
442 heddle context get --path src/auth.rs --scope symbol:verify
443 heddle context list --prefix src/auth # everything attached under a path
444 heddle context check --path src/auth.rs # surface annotations for editor tooling
445")]
446 Context {
447 #[command(subcommand)]
448 command: ContextCommands,
449 },
450
451 /// Manage ambient harness integrations.
452 Integration {
453 #[command(subcommand)]
454 command: IntegrationCommands,
455 },
456
457 /// Semantic analysis queries (call-graph hot-spots, churn,
458 /// signature-stability surfaces).
459 #[cfg(feature = "semantic")]
460 Semantic {
461 #[command(subcommand)]
462 command: SemanticCommands,
463 },
464
465 /// FUSE mount-daemon control plane — distinct from `agent`.
466 ///
467 /// `heddle daemon serve` runs a foreground mount daemon that
468 /// owns FUSE sessions for `--workspace virtualized --daemon`
469 /// threads. It is normally spawned on demand by the per-thread
470 /// CLI; running it interactively is for debugging.
471 /// `status` reports liveness/uptime/mount count without spawning;
472 /// `stop` asks a running daemon to drain mounts and exit.
473 Daemon {
474 #[command(subcommand)]
475 command: DaemonCommands,
476 },
477
478 /// Agent control surface — daemon lifecycle and reservation API.
479 ///
480 /// `heddle agent serve|status|stop` controls the local gRPC
481 /// daemon (Unix socket inside the repo). `heddle agent
482 /// reserve|capture|ready|release|list|heartbeat` is the stable
483 /// JSON contract orchestrators use to coordinate parallel
484 /// writers. Distinct from `heddle daemon` (FUSE mount control
485 /// plane) — different subsystem.
486 Agent {
487 #[command(subcommand)]
488 command: AgentCommands,
489 },
490
491 /// Inspect and refresh rebuildable performance sidecars.
492 Maintenance {
493 #[command(subcommand)]
494 command: MaintenanceCommands,
495 },
496
497 /// Clone from remote.
498 Clone(CloneArgs),
499
500 /// Manage repository hooks.
501 Hook {
502 #[command(subcommand)]
503 command: HookCommands,
504 },
505}
506
507/// Maintenance subcommands.
508#[derive(Clone, Debug, clap::Subcommand)]
509pub enum MaintenanceCommands {
510 /// Inspect repository performance sidecars and repo shape.
511 Inspect,
512
513 /// Refresh repository performance sidecars without changing repository meaning.
514 Refresh,
515
516 /// Garbage collect unreachable objects.
517 Gc {
518 /// Prune unreachable objects.
519 #[arg(long)]
520 prune: bool,
521
522 /// Aggressive garbage collection.
523 #[arg(long)]
524 aggressive: bool,
525
526 /// Show what would be removed without removing.
527 #[arg(long)]
528 dry_run: bool,
529 },
530}
531
532/// Daemon control plane subcommands. See `Commands::Daemon`.
533#[derive(Clone, Debug, clap::Subcommand)]
534pub enum DaemonCommands {
535 /// Run a foreground mount daemon for this repository.
536 ///
537 /// Normally spawned on demand by the per-thread CLI when
538 /// `--daemon` is passed. Running interactively is for
539 /// debugging the daemon protocol.
540 Serve,
541
542 /// Report daemon liveness, version, uptime, and active mount
543 /// count. No-op success when the daemon isn't running.
544 Status,
545
546 /// Ask the running daemon to drain its mounts and exit. Sweeps
547 /// any leftover registry entries with `fusermount -u` as a
548 /// safety net before returning.
549 Stop,
550}