use clap::{Parser, Subcommand}; use std::path::PathBuf; use super::query::CliDirection; use super::ui::OutputFormat; /// Defines the top-level interface for the Firm CLI with clap. #[derive(Parser, Debug)] #[command(name = "firm")] #[command(version, about = "Firm CLI: Work management in the terminal.")] pub struct FirmCli { /// Path to firm workspace directory. #[arg(short, long, global = true, env = "FIRM_WORKSPACE")] pub workspace: Option, /// Use cached firm graph? #[arg(short, long, global = true, env = "FIRM_CACHED")] pub cached: bool, /// Enable verbose output? #[arg(short, long, global = true, env = "FIRM_VERBOSE")] pub verbose: bool, /// Output format #[arg(short, long, global = true, default_value_t = OutputFormat::default(), env = "FIRM_FORMAT")] pub format: OutputFormat, #[command(subcommand)] pub command: FirmCliCommand, } /// Defines the available subcommands of the Firm CLI. #[derive(Subcommand, Debug, PartialEq)] pub enum FirmCliCommand { /// Initialize a new Firm workspace with default schemas and files. Init, /// Build workspace and entity graph. Build, /// Get an entity or schema. Get { /// Entity type (e.g. person, organization) or "schema" target_type: String, /// Entity ID (e.g. john_doe) or schema name (e.g. project) target_id: String, }, /// List entities of a type, or list all schemas. List { /// Entity type (e.g. person, organization) or "schema" to list schemas target_type: String, }, /// Gets entities related to a given entity. Related { /// Entity type (e.g. person) entity_type: String, /// Entity ID (e.g. john_doe) entity_id: String, /// Direction of relationships (incoming, outgoing, or both if not specified) #[arg(short, long)] direction: Option, }, /// Adds a new entity to a file in the workspace. If type, id or fields are not provided, this is done interactively. Add { /// Target firm file. to_file: Option, /// Entity type for non-interactive mode (e.g., person, organization) #[arg(long)] r#type: Option, /// Entity ID for non-interactive mode (e.g., john_doe) #[arg(long)] id: Option, /// Field for non-interactive mode (can be repeated). Format: --field #[arg(long = "field", num_args = 2, value_names = ["FIELD_NAME", "VALUE"])] fields: Vec, /// List declaration for non-interactive mode (can be repeated). Format: --list #[arg(long = "list", num_args = 2, value_names = ["FIELD_NAME", "ITEM_TYPE"])] lists: Vec, /// List value for non-interactive mode (can be repeated). Format: --list-value #[arg(long = "list-value", num_args = 2, value_names = ["FIELD_NAME", "VALUE"])] list_values: Vec, }, /// Query entities in the workspace using a query language. Query { /// Query string (e.g., "from task | where is_completed == false | limit 5") query: String, }, /// Find the source file for an entity or schema. Source { /// Entity type (e.g. person, organization) or "schema" target_type: String, /// Entity ID (e.g. john_doe) or schema name (e.g. project) target_id: String, }, /// Check workspace files for errors. Optionally check a single file. Check { /// Path to a specific .firm file to check (checks entire workspace if omitted) file: Option, }, /// Start the language server (stdio transport). Lsp, /// Start the MCP server (stdio transport). Mcp, }