logicaffeine_cli/cli.rs
1//! LOGOS CLI (largo) — argument parsing and dispatch.
2//!
3//! This module defines the `largo` command-line surface: the [`Cli`] parser,
4//! the [`Commands`] enum, and [`run_cli`], which dispatches each subcommand
5//! to its handler in [`crate::commands`].
6//!
7//! # Architecture
8//!
9//! The CLI is built on [`clap`] for argument parsing with derive macros.
10//! Each command variant in [`Commands`] maps to a handler function in a
11//! dedicated module under `commands/` that performs the actual work.
12//!
13//! # Examples
14//!
15//! ```bash
16//! # Create a new project
17//! largo new my_project
18//!
19//! # Build and run
20//! cd my_project
21//! largo run
22//!
23//! # Publish to registry
24//! largo login
25//! largo publish
26//! ```
27
28use clap::{Parser, Subcommand};
29use std::path::PathBuf;
30
31use crate::commands;
32use crate::ui::{self, ColorMode};
33
34/// Command-line interface for the LOGOS build tool.
35///
36/// The `Cli` struct is the top-level argument parser for `largo`. It delegates
37/// to the [`Commands`] enum for subcommand handling.
38///
39/// # Usage
40///
41/// Typically invoked via [`run_cli`] which parses arguments and dispatches
42/// to the appropriate handler:
43///
44/// ```no_run
45/// use logicaffeine_cli::cli::run_cli;
46///
47/// if let Err(e) = run_cli() {
48/// eprintln!("Error: {}", e);
49/// std::process::exit(1);
50/// }
51/// ```
52/// The version string, flavor-stamped: the full build (Z3 verification
53/// statically linked) reports `X.Y.Z (full)` so installs are diagnosable.
54#[cfg(feature = "verification")]
55const LARGO_VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (full)");
56/// The lean build reports the bare version.
57#[cfg(not(feature = "verification"))]
58const LARGO_VERSION: &str = env!("CARGO_PKG_VERSION");
59
60#[derive(Parser)]
61#[command(name = "largo")]
62#[command(about = "The LOGOS build tool", long_about = None)]
63#[command(version = LARGO_VERSION)]
64#[command(arg_required_else_help = true)]
65#[command(styles = ui::CLAP_STYLES)]
66pub struct Cli {
67 /// The subcommand to execute.
68 #[command(subcommand)]
69 pub command: Commands,
70
71 /// Suppress informational output (errors still print).
72 #[arg(long, short, global = true)]
73 pub quiet: bool,
74
75 /// Increase output verbosity (repeatable).
76 #[arg(long, short, global = true, action = clap::ArgAction::Count)]
77 pub verbose: u8,
78
79 /// When to use terminal colors.
80 #[arg(long, global = true, value_enum, default_value = "auto", value_name = "WHEN")]
81 pub color: ColorMode,
82}
83
84/// Available CLI subcommands.
85///
86/// Each variant represents a distinct operation that `largo` can perform.
87/// Commands are grouped into three categories:
88///
89/// ## Project Management
90/// - [`New`][Commands::New] - Create a new project in a new directory
91/// - [`Init`][Commands::Init] - Initialize a project in the current directory
92///
93/// ## Build & Run
94/// - [`Build`][Commands::Build] - Compile the project
95/// - [`Run`][Commands::Run] - Build and execute
96/// - [`Check`][Commands::Check] - Type-check without building
97/// - [`Verify`][Commands::Verify] - Run Z3 static verification
98///
99/// ## Package Registry
100/// - [`Publish`][Commands::Publish] - Upload package to registry
101/// - [`Login`][Commands::Login] - Authenticate with registry
102/// - [`Logout`][Commands::Logout] - Remove stored credentials
103#[derive(Subcommand)]
104pub enum Commands {
105 /// Create a new LOGOS project in a new directory.
106 ///
107 /// Scaffolds a complete project structure including:
108 /// - `Largo.toml` manifest file
109 /// - `src/main.lg` entry point with a "Hello, world!" example
110 /// - `.gitignore` configured for LOGOS projects
111 ///
112 /// # Example
113 ///
114 /// ```bash
115 /// largo new my_project
116 /// cd my_project
117 /// largo run
118 /// ```
119 #[command(after_help = "Examples:\n largo new hello\n cd hello\n largo run")]
120 New {
121 /// The project name, used for the directory and package name.
122 name: String,
123 },
124
125 /// Initialize a LOGOS project in the current directory.
126 ///
127 /// Similar to [`New`][Commands::New] but works in an existing directory.
128 /// Creates the manifest and source structure without creating a new folder.
129 ///
130 /// # Example
131 ///
132 /// ```bash
133 /// mkdir my_project && cd my_project
134 /// largo init
135 /// ```
136 #[command(after_help = "Examples:\n mkdir app && cd app\n largo init\n largo init --name my_app")]
137 Init {
138 /// Project name. If omitted, uses the current directory name.
139 #[arg(long)]
140 name: Option<String>,
141 },
142
143 /// Build the current project.
144 ///
145 /// Compiles the LOGOS source to Rust, then invokes `cargo build` on the
146 /// generated code. The resulting binary is placed in `target/debug/` or
147 /// `target/release/` depending on the mode.
148 ///
149 /// # Verification
150 ///
151 /// When `--verify` is passed, the build process includes Z3 static
152 /// verification of logical constraints. This requires:
153 /// - A Pro+ license (via `--license` or `LOGOS_LICENSE` env var)
154 /// - The `verification` feature enabled at build time
155 ///
156 /// # Example
157 ///
158 /// ```bash
159 /// largo build # Debug build
160 /// largo build --release # Release build with optimizations
161 /// largo build --verify # Build with Z3 verification
162 /// ```
163 #[command(after_help = "Examples:\n largo build\n largo build --release\n largo build --emit wasm\n largo build --lib --target aarch64-unknown-linux-gnu")]
164 Build {
165 /// Build with optimizations enabled.
166 #[arg(long, short)]
167 release: bool,
168
169 /// Run Z3 static verification after compilation.
170 /// Requires a Pro+ license.
171 #[arg(long)]
172 verify: bool,
173
174 /// License key for verification.
175 /// Can also be set via the `LOGOS_LICENSE` environment variable.
176 #[arg(long)]
177 license: Option<String>,
178
179 /// Build as a library instead of an executable.
180 /// Generates `lib.rs` with `crate-type = ["cdylib"]` instead of a binary.
181 #[arg(long)]
182 lib: bool,
183
184 /// Target triple for cross-compilation.
185 /// Use "wasm" as shorthand for "wasm32-unknown-unknown".
186 #[arg(long)]
187 target: Option<String>,
188
189 /// Pre-build every `is exported for native` function into the AOT-native
190 /// tier bundle (a cached cdylib per function) under `.logos-native/`.
191 #[arg(long)]
192 native_functions: bool,
193
194 /// Emit target. `wasm` compiles the project DIRECTLY to a self-contained `.wasm` module via the
195 /// built-in backend (no rustc / cargo / wasm-bindgen — milliseconds), written to
196 /// `target/<name>.wasm`. `wasm-linked` additionally links the real `logicaffeine_base::BigInt`
197 /// runtime (via `rust-lld`) so overflowing integer arithmetic computes the exact big number
198 /// instead of wrapping — needs the Rust toolchain + a wasm32 `base` build. Omit for the default
199 /// rustc-based Rust build.
200 #[arg(long)]
201 emit: Option<String>,
202 },
203
204 /// Run Z3 static verification without building.
205 ///
206 /// Performs formal verification of logical constraints in the project
207 /// using the Z3 SMT solver. This catches logical errors that would be
208 /// impossible to detect through testing alone.
209 ///
210 /// Requires a Pro+ license.
211 ///
212 /// # Example
213 ///
214 /// ```bash
215 /// largo verify --license sub_xxxxx
216 /// # Or with environment variable:
217 /// export LOGOS_LICENSE=sub_xxxxx
218 /// largo verify
219 /// ```
220 #[command(after_help = "Examples:\n largo verify --license sub_xxxxx\n LOGOS_LICENSE=sub_xxxxx largo verify")]
221 Verify {
222 /// License key for verification.
223 /// Can also be set via the `LOGOS_LICENSE` environment variable.
224 #[arg(long)]
225 license: Option<String>,
226 },
227
228 /// Build and run the current project.
229 ///
230 /// Equivalent to `largo build` followed by executing the resulting binary.
231 /// The exit code of the built program is propagated.
232 ///
233 /// With `--interpret`, skips Rust compilation and uses the tree-walking
234 /// interpreter for sub-second feedback during development.
235 ///
236 /// # Example
237 ///
238 /// ```bash
239 /// largo run # Debug mode (compile to Rust)
240 /// largo run --release # Release mode
241 /// largo run --interpret # Interpret directly (no compilation)
242 /// ```
243 #[command(after_help = "Examples:\n largo run\n largo run --release\n largo run --interpret\n largo run --emit wasm\n largo run -- input.txt --program-flag")]
244 Run {
245 /// Build with optimizations enabled.
246 #[arg(long, short)]
247 release: bool,
248
249 /// Run using the interpreter instead of compiling to Rust.
250 /// Provides sub-second feedback but lacks full Rust performance.
251 #[arg(long, short)]
252 interpret: bool,
253
254 /// `wasm` compiles DIRECTLY to a `.wasm` (built-in backend, no rustc) and runs it via the
255 /// emitted host shim (node). `wasm-linked` links the real `BigInt` runtime first (exact
256 /// arbitrary-precision integers; needs the Rust toolchain). Compile-and-run in one step.
257 #[arg(long, conflicts_with = "interpret")]
258 emit: Option<String>,
259
260 /// Arguments to pass to the program.
261 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
262 args: Vec<String>,
263 },
264
265 /// Check the project for errors without producing a binary.
266 ///
267 /// Parses and type-checks the LOGOS source without invoking the full
268 /// build pipeline. Useful for quick validation during development.
269 ///
270 /// # Example
271 ///
272 /// ```bash
273 /// largo check
274 /// ```
275 #[command(after_help = "Examples:\n largo check\n largo check --quiet")]
276 Check {
277 /// Also run rustc's analysis over the generated code (the same deep
278 /// pass the IDE's flycheck uses) and translate its findings to LOGOS.
279 #[arg(long)]
280 deep: bool,
281 },
282
283 /// Report which optimizations actually FIRE when compiling a LOGOS file.
284 ///
285 /// Compiles the file on the AOT, run-path, and VM-compile paths with the
286 /// firing trace on, and lists the optimizations that genuinely changed the
287 /// program (not merely the ones that are enabled). Useful for understanding
288 /// and auditing what the compiler did to a given program.
289 ///
290 /// # Example
291 ///
292 /// ```bash
293 /// largo opts src/main.lg
294 /// largo opts src/main.lg --json
295 /// ```
296 #[command(after_help = "Examples:\n largo opts src/main.lg\n largo opts src/main.lg --json")]
297 Opts {
298 /// The `.lg` source file to analyze.
299 file: PathBuf,
300
301 /// Emit the fired optimizations as JSON (keyword list).
302 #[arg(long)]
303 json: bool,
304 },
305
306 /// Publish the package to the LOGOS registry.
307 ///
308 /// Packages the project as a tarball and uploads it to the specified
309 /// registry. Requires authentication via `largo login`.
310 ///
311 /// # Pre-flight Checks
312 ///
313 /// Before publishing, the command verifies:
314 /// - The entry point exists
315 /// - No uncommitted git changes (unless `--allow-dirty`)
316 /// - Valid authentication token
317 ///
318 /// # Example
319 ///
320 /// ```bash
321 /// largo publish # Publish to default registry
322 /// largo publish --dry-run # Validate without uploading
323 /// ```
324 #[command(after_help = "Examples:\n largo publish --dry-run\n largo publish\n largo publish --allow-dirty")]
325 Publish {
326 /// Registry URL. Defaults to `registry.logicaffeine.com`.
327 #[arg(long)]
328 registry: Option<String>,
329
330 /// Perform all validation without actually uploading.
331 /// Useful for testing the publish process.
332 #[arg(long)]
333 dry_run: bool,
334
335 /// Allow publishing with uncommitted git changes.
336 /// By default, publishing requires a clean working directory.
337 #[arg(long)]
338 allow_dirty: bool,
339 },
340
341 /// Authenticate with the package registry.
342 ///
343 /// Stores an API token for the specified registry. The token is saved
344 /// in `~/.config/logos/credentials.toml` with restricted permissions.
345 ///
346 /// # Token Acquisition
347 ///
348 /// Tokens can be obtained from the registry's web interface:
349 /// 1. Visit `{registry}/auth/github` to authenticate
350 /// 2. Generate an API token from your profile
351 /// 3. Provide it via `--token` or interactive prompt
352 ///
353 /// # Example
354 ///
355 /// ```bash
356 /// largo login # Interactive prompt
357 /// largo login --token tok_xxxxx # Non-interactive
358 /// ```
359 #[command(after_help = "Examples:\n largo login\n largo login --token lgr_xxxxx")]
360 Login {
361 /// Registry URL. Defaults to `registry.logicaffeine.com`.
362 #[arg(long)]
363 registry: Option<String>,
364
365 /// API token. If omitted, prompts for input on stdin.
366 #[arg(long)]
367 token: Option<String>,
368 },
369
370 /// Remove stored credentials for a registry.
371 ///
372 /// Deletes the authentication token from the local credentials file.
373 ///
374 /// # Example
375 ///
376 /// ```bash
377 /// largo logout
378 /// ```
379 #[command(after_help = "Examples:\n largo logout\n largo logout --registry https://registry.example.com")]
380 Logout {
381 /// Registry URL. Defaults to `registry.logicaffeine.com`.
382 #[arg(long)]
383 registry: Option<String>,
384 },
385
386 /// Diagnose the environment largo runs in.
387 ///
388 /// Checks the Rust toolchain (needed by `build`/`run`), the wasm32
389 /// target, node (for `--emit wasm`), the verification flavor, registry
390 /// reachability and credentials, update freshness, and — inside a
391 /// project — manifest health. Degradations are warnings; only a broken
392 /// project fails. Works offline.
393 #[command(after_help = "Examples:\n largo doctor\n largo doctor --registry https://registry.example.com")]
394 Doctor {
395 /// Registry URL to probe (defaults to the LOGOS registry).
396 #[arg(long)]
397 registry: Option<String>,
398 },
399
400 /// Start the interactive LOGOS REPL.
401 ///
402 /// Two modes in one session: imperative statements against a
403 /// persistent interpreter session (`logos>`), and English→FOL logic
404 /// mode with discourse-aware anaphora (`logic>`). Type `:help` inside
405 /// for the meta-commands (`:mode`, `:format`, `:readings`, `:vars`,
406 /// `:save`, …). Works on a pipe too — no terminal required.
407 #[command(after_help = "Examples:\n largo repl\n largo repl --logic\n largo repl --logic --format latex\n largo repl --load session.lg\n printf 'Let x be 5.\\nShow x.\\n' | largo repl")]
408 Repl {
409 /// Start in logic mode (English → FOL).
410 #[arg(long)]
411 logic: bool,
412
413 /// Initial logic output format.
414 #[arg(long, value_enum)]
415 format: Option<crate::commands::logic::LogicFormat>,
416
417 /// Load a saved session/program on startup.
418 #[arg(long)]
419 load: Option<PathBuf>,
420 },
421
422 /// Solve a DIMACS CNF with the certified SAT engine.
423 ///
424 /// The SAT Competition interface as a largo verb: prints
425 /// `s SATISFIABLE` with a `v` model or `s UNSATISFIABLE`, optionally
426 /// exporting a DRAT/DPR/SR refutation for external checkers
427 /// (drat-trim). Exit codes follow the competition convention:
428 /// 10 = SAT, 20 = UNSAT, 1 = error.
429 #[command(after_help = "Examples:\n largo sat instance.cnf\n largo sat instance.cnf --proof refutation.drat\n largo sat instance.cnf --stats")]
430 Sat {
431 /// The DIMACS CNF file to solve.
432 file: PathBuf,
433
434 /// Write the UNSAT certificate here (DRAT; DPR/SR for symmetry routes).
435 #[arg(long)]
436 proof: Option<PathBuf>,
437
438 /// Print solver statistics to stderr.
439 #[arg(long)]
440 stats: bool,
441 },
442
443 /// Prove the theorems in a LOGOS source file (kernel-certified).
444 ///
445 /// Runs `## Theory` developments (formal Axiom/Theorem declarations,
446 /// proved in citation order) and English `## Theorem` blocks
447 /// (Given/Prove/Proof) through the proof engine. Every ✓ is certified
448 /// by the type-theory kernel — a mere derivation never counts.
449 #[command(after_help = "Examples:\n largo prove # prove the project entry\n largo prove geometry.lg\n largo prove socrates.lg --trace\n largo prove tarski.lg --json")]
450 Prove {
451 /// The source file (defaults to the project entry).
452 file: Option<PathBuf>,
453
454 /// Show the rendered derivation tree under each proved theorem.
455 #[arg(long)]
456 trace: bool,
457
458 /// Emit machine-readable JSON results.
459 #[arg(long, conflicts_with = "trace")]
460 json: bool,
461 },
462
463 /// Translate English to First-Order Logic.
464 ///
465 /// Compiles a natural-language sentence to formal logic — the LOGOS
466 /// logic mode from the terminal. Reads the sentence inline, from
467 /// `--file`, or from piped stdin. Prints bare FOL on stdout, so output
468 /// pipes cleanly into other tools.
469 #[command(after_help = "Examples:\n largo logic \"Every woman loves a man.\"\n largo logic \"Every woman loves a man.\" --all-readings\n largo logic \"It might rain.\" --format kripke\n echo \"Socrates is mortal.\" | largo logic\n printf 'A farmer owns a donkey.\\nHe feeds it.' | largo logic --discourse")]
470 Logic {
471 /// The English sentence to translate.
472 sentence: Option<String>,
473
474 /// Read the sentence (or discourse) from a file.
475 #[arg(long, short, conflicts_with = "sentence")]
476 file: Option<PathBuf>,
477
478 /// Output format for the logical form.
479 #[arg(long, value_enum, default_value = "unicode")]
480 format: crate::commands::logic::LogicFormat,
481
482 /// Show every reading (quantifier scopes + parse forest), numbered.
483 #[arg(long, conflicts_with = "discourse")]
484 all_readings: bool,
485
486 /// Enrich with scalar implicature (pragmatic strengthening).
487 #[arg(long)]
488 pragmatic: bool,
489
490 /// Treat each input line as one sentence of a discourse with
491 /// shared anaphora context.
492 #[arg(long)]
493 discourse: bool,
494 },
495
496 /// Generate documentation from the project's `##` blocks.
497 ///
498 /// Renders a markdown reference from the literate structure of the
499 /// entry file: `## To` signatures, type definitions, notes, examples,
500 /// and formal blocks — in source order. `## Main` is omitted.
501 #[command(after_help = "Examples:\n largo doc\n largo doc --out book")]
502 Doc {
503 /// Output directory (defaults to `target/doc`).
504 #[arg(long)]
505 out: Option<PathBuf>,
506 },
507
508 /// Add a dependency to Largo.toml.
509 ///
510 /// Accepts `name` (any version), `name@version`, or `logos:name` (the
511 /// registry URI form). `--path` and `--git` record local and git
512 /// dependencies. Edits preserve the manifest's comments and formatting.
513 #[command(after_help = "Examples:\n largo add math_utils\n largo add [email protected]\n largo add logos:std\n largo add local_lib --path ../local_lib\n largo add remote --git https://example.com/remote.git")]
514 Add {
515 /// The dependency: `name`, `name@version`, or `logos:name`.
516 spec: String,
517
518 /// Use a local path dependency.
519 #[arg(long, conflicts_with = "git")]
520 path: Option<String>,
521
522 /// Use a git dependency.
523 #[arg(long, conflicts_with = "path")]
524 git: Option<String>,
525 },
526
527 /// Remove a dependency from Largo.toml.
528 ///
529 /// Deletes the named entry from `[dependencies]`, leaving the rest of
530 /// the manifest byte-identical.
531 #[command(after_help = "Examples:\n largo remove math_utils")]
532 Remove {
533 /// The dependency name to remove.
534 name: String,
535 },
536
537 /// Format LOGOS source files.
538 ///
539 /// Applies the canonical style (4-space indentation, no tabs, no
540 /// trailing whitespace) — the same rules the language server uses.
541 /// Without paths, formats the whole project; with paths, exactly those
542 /// files. `--check` writes nothing and exits 1 if anything would change.
543 #[command(after_help = "Examples:\n largo fmt\n largo fmt src/main.lg\n largo fmt --check # CI gate, writes nothing")]
544 Fmt {
545 /// Specific files to format (defaults to all project sources).
546 paths: Vec<PathBuf>,
547
548 /// Check only: list files that need formatting, exit 1 if any.
549 #[arg(long)]
550 check: bool,
551 },
552
553 /// Emit compiled code without building a binary.
554 ///
555 /// Prints the generated Rust or C translation of the program, or writes
556 /// a self-contained `.wasm` module (built-in backend, no rustc) with its
557 /// Node.js host shim. Without FILE, uses the current project's entry;
558 /// with FILE, works on any standalone `.lg`/`.md` source.
559 #[command(after_help = "Examples:\n largo emit rust\n largo emit rust -o generated.rs\n largo emit c standalone.lg\n largo emit wasm\n largo emit wasm-linked -o dist/app.wasm")]
560 Emit {
561 /// What to emit.
562 #[arg(value_enum)]
563 target: crate::commands::emit::EmitTarget,
564
565 /// A standalone source file (defaults to the project entry).
566 file: Option<PathBuf>,
567
568 /// Write to this path instead of stdout (rust/c) or the default
569 /// module path (wasm).
570 #[arg(long, short)]
571 output: Option<PathBuf>,
572 },
573
574 /// Remove build artifacts.
575 ///
576 /// Deletes the project's `target/` directory. With `--all`, also removes
577 /// the `.logos-native/` compiled-function bundle cache produced by
578 /// `largo build --native-functions`.
579 #[command(after_help = "Examples:\n largo clean\n largo clean --all")]
580 Clean {
581 /// Also remove the `.logos-native/` bundle cache.
582 #[arg(long)]
583 all: bool,
584 },
585
586 /// Generate shell completions for largo.
587 ///
588 /// Writes a completion script for the given shell to stdout. Source it
589 /// from your shell's configuration to get tab completion for every
590 /// largo command and flag.
591 #[command(after_help = "Examples:\n largo completions bash > ~/.local/share/bash-completion/completions/largo\n largo completions zsh > ~/.zfunc/_largo\n largo completions fish > ~/.config/fish/completions/largo.fish")]
592 Completions {
593 /// The shell to generate completions for.
594 #[arg(value_enum)]
595 shell: clap_complete::Shell,
596 },
597
598 /// Reserved for the LOGOS test framework (coming in a future release).
599 #[command(hide = true)]
600 Test {
601 /// Ignored; the verb is reserved.
602 #[arg(trailing_var_arg = true, allow_hyphen_values = true, hide = true)]
603 args: Vec<String>,
604 },
605}
606
607/// Parse CLI arguments and execute the corresponding command.
608///
609/// This is the main entry point for the `largo` CLI. It parses command-line
610/// arguments using [`clap`], then dispatches to the appropriate handler
611/// function based on the subcommand.
612///
613/// # Errors
614///
615/// Returns an error if:
616/// - The project structure is invalid (missing `Largo.toml`)
617/// - File system operations fail
618/// - Build or compilation fails
619/// - Registry operations fail (authentication, network, etc.)
620///
621/// # Example
622///
623/// ```no_run
624/// use logicaffeine_cli::cli::run_cli;
625///
626/// fn main() {
627/// if let Err(e) = run_cli() {
628/// eprintln!("Error: {}", e);
629/// std::process::exit(1);
630/// }
631/// }
632/// ```
633pub fn run_cli() -> Result<(), Box<dyn std::error::Error>> {
634 let cli = Cli::parse();
635 ui::init(cli.color, cli.quiet, cli.verbose);
636
637 match cli.command {
638 Commands::New { name } => commands::new::cmd_new(&name),
639 Commands::Init { name } => commands::new::cmd_init(name.as_deref()),
640 Commands::Build { release, verify, license, lib, target, native_functions, emit } => {
641 commands::build::cmd_build(release, verify, license, lib, target, native_functions, emit)
642 }
643 Commands::Run { emit: Some(e), args, .. } if e == "wasm" => commands::run::cmd_run_wasm(&args, false),
644 Commands::Run { emit: Some(e), args, .. } if e == "wasm-linked" => commands::run::cmd_run_wasm(&args, true),
645 Commands::Run { emit: Some(e), .. } => {
646 Err(format!("unknown --emit target '{e}' (expected 'wasm' or 'wasm-linked')").into())
647 }
648 Commands::Run { interpret, args, .. } if interpret => commands::run::cmd_run_interpret(&args),
649 Commands::Run { release, args, .. } => commands::run::cmd_run(release, &args),
650 Commands::Check { deep } => commands::check::cmd_check(deep),
651 Commands::Opts { file, json } => commands::opts::cmd_opts(&file, json),
652 Commands::Verify { license } => commands::verify::cmd_verify(license),
653 Commands::Publish { registry, dry_run, allow_dirty } => {
654 commands::publish::cmd_publish(registry.as_deref(), dry_run, allow_dirty)
655 }
656 Commands::Login { registry, token } => commands::publish::cmd_login(registry.as_deref(), token),
657 Commands::Logout { registry } => commands::publish::cmd_logout(registry.as_deref()),
658 Commands::Doctor { registry } => commands::doctor::cmd_doctor(registry),
659 Commands::Repl { logic, format, load } => crate::repl::cmd_repl(logic, format, load),
660 Commands::Sat { file, proof, stats } => commands::sat::cmd_sat(file, proof, stats),
661 Commands::Prove { file, trace, json } => commands::prove::cmd_prove(file, trace, json),
662 Commands::Logic { sentence, file, format, all_readings, pragmatic, discourse } => {
663 commands::logic::cmd_logic(sentence, file, format, all_readings, pragmatic, discourse)
664 }
665 Commands::Doc { out } => commands::doc::cmd_doc(out),
666 Commands::Add { spec, path, git } => commands::deps::cmd_add(spec, path, git),
667 Commands::Remove { name } => commands::deps::cmd_remove(name),
668 Commands::Fmt { paths, check } => commands::fmt::cmd_fmt(paths, check),
669 Commands::Emit { target, file, output } => commands::emit::cmd_emit(target, file, output),
670 Commands::Clean { all } => commands::clean::cmd_clean(all),
671 Commands::Completions { shell } => commands::completions::cmd_completions(shell),
672 Commands::Test { .. } => Err(ui::CliError::with_hint(
673 "`largo test` is reserved for the LOGOS test framework (coming in a future release)",
674 "run `largo check` to validate your project today",
675 )
676 .exit_code(ui::EXIT_USAGE)
677 .into()),
678 }
679}