simplify: migrate exec/parse/workflow/upgrade/uninstall to CommandContext

These top-level commands still took `&CliNamespace` + `Printer`
separately. Thread `&CommandContext` through the public entry points
and pull what's needed (`user_settings().cli`, `printer()`,
`json_output()`) from the context:

- parse: both args were unused — drop entirely.
- workflow list/create: use `ctx.json_output()` / `ctx.printer()`.
- exec: bind `cli = &ctx.user_settings().cli` at the top; drop unused
  printer param.
- upgrade: extract cli/printer inside run_upgrade; leave the private
  run_upgrade_brew helper with its existing signature (unit tests use
  `CliNamespace::default()` directly).
- uninstall: use `ctx.json_output()` / `ctx.printer()`.

Install remains on the old signature — its nested callback structure
makes a larger refactor than this simplification pass warrants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-23 08:06:46 -04:00
parent 4a696e0706
commit d51c6dfb76
No known key found for this signature in database
8 changed files with 38 additions and 50 deletions

View file

@ -13,15 +13,15 @@ use fabro_llm::types::{
FinishReason, Message, Request, Response as LlmResponse, StreamEvent, TokenCounts,
};
use fabro_mcp::config::{McpServerSettings, McpTransport};
use fabro_types::settings::InterpString;
use fabro_types::settings::cli::OutputFormat as SettingsOutputFormat;
use fabro_types::settings::run::McpEntryLayer;
use fabro_types::settings::{CliNamespace, InterpString};
use fabro_util::exit::{ErrorExt, ExitClass};
use fabro_util::printer::Printer;
use futures::stream;
use serde::Deserialize;
use crate::args::ExecArgs;
use crate::command_context::CommandContext;
use crate::{server_client, user_config};
fn runtime_mcp_server(name: &str, entry: &McpEntryLayer) -> McpServerSettings {
@ -356,14 +356,11 @@ impl ProviderAdapter for AuthenticatedFabroServerAdapter {
}
}
pub(crate) async fn execute(
mut args: ExecArgs,
cli: &CliNamespace,
_printer: Printer,
) -> AnyResult<()> {
pub(crate) async fn execute(mut args: ExecArgs, ctx: &CommandContext) -> AnyResult<()> {
use fabro_agent::cli::PermissionLevel as AgentPermissionLevel;
use fabro_types::settings::run::AgentPermissions;
let cli = &ctx.user_settings().cli;
let raw_settings = user_config::load_settings()?;
#[cfg(feature = "sleep_inhibitor")]
let _sleep_guard = crate::sleep_inhibitor::guard(cli.exec.prevent_idle_sleep);

View file

@ -11,13 +11,11 @@ use std::io::Write;
use fabro_config::project::resolve_workflow;
use fabro_graphviz::parser::parse_ast;
use fabro_types::settings::CliNamespace;
use fabro_util::printer::Printer;
use crate::args::ParseArgs;
use crate::shared::read_workflow_file;
pub(crate) fn run(args: &ParseArgs, _cli: &CliNamespace, _printer: Printer) -> anyhow::Result<()> {
pub(crate) fn run(args: &ParseArgs) -> anyhow::Result<()> {
let stdout = std::io::stdout();
run_to(args, stdout.lock())
}

View file

@ -15,14 +15,13 @@ use std::time::Duration;
use anyhow::{Context, Result};
use fabro_config::Storage;
use fabro_config::daemon::ServerDaemon;
use fabro_types::settings::CliNamespace;
use fabro_types::settings::cli::OutputFormat;
use fabro_util::Home;
use fabro_util::printer::Printer;
use serde::Serialize;
use tracing::warn;
use crate::args::UninstallArgs;
use crate::command_context::CommandContext;
use crate::commands::server::stop;
use crate::shared::{format_size, print_json_pretty, tilde_path};
use crate::{local_server, user_config};
@ -43,12 +42,9 @@ struct Inventory {
clippy::unused_async,
reason = "The shared command dispatch path expects an async handler."
)]
pub(crate) async fn run_uninstall(
args: &UninstallArgs,
cli: &CliNamespace,
printer: Printer,
) -> Result<()> {
let json = cli.output.format == OutputFormat::Json;
pub(crate) async fn run_uninstall(args: &UninstallArgs, ctx: &CommandContext) -> Result<()> {
let json = ctx.json_output();
let printer = ctx.printer();
let home = Home::from_env();
let home_root = home.root().to_path_buf();

View file

@ -23,6 +23,7 @@ use tokio::task::JoinHandle;
use tracing::debug;
use crate::args::UpgradeArgs;
use crate::command_context::CommandContext;
use crate::shared::print_json_pretty;
// ── Download backend abstraction ───────────────────────────────────────────
@ -434,11 +435,9 @@ impl UpgradeCheckState {
// ── Main upgrade command ───────────────────────────────────────────────────
pub(crate) async fn run_upgrade(
args: UpgradeArgs,
cli: &CliNamespace,
printer: Printer,
) -> Result<()> {
pub(crate) async fn run_upgrade(args: UpgradeArgs, ctx: &CommandContext) -> Result<()> {
let cli = &ctx.user_settings().cli;
let printer = ctx.printer();
let current_exe = std::env::current_exe()
.context("resolving current fabro executable path")?
.canonicalize()

View file

@ -7,18 +7,13 @@ use std::path::Path;
use anyhow::{Context, Result, bail};
use fabro_config::project::{discover_project_config, resolve_fabro_root};
use fabro_types::settings::CliNamespace;
use fabro_types::settings::cli::OutputFormat;
use fabro_util::printer::Printer;
use crate::args::WorkflowCreateArgs;
use crate::command_context::CommandContext;
use crate::shared::{print_json_pretty, relative_path};
pub(super) fn create_command(
args: &WorkflowCreateArgs,
cli: &CliNamespace,
printer: Printer,
) -> Result<()> {
pub(super) fn create_command(args: &WorkflowCreateArgs, base_ctx: &CommandContext) -> Result<()> {
let printer = base_ctx.printer();
let cwd = std::env::current_dir()?;
let Some((config_path, config)) = discover_project_config(&cwd)? else {
@ -31,7 +26,7 @@ pub(super) fn create_command(
let fabro_root = resolve_fabro_root(&config_path, &config);
let created = write_workflow_scaffold(args, &fabro_root)?;
if cli.output.format == OutputFormat::Json {
if base_ctx.json_output() {
let created: Vec<_> = created.iter().map(|path| relative_path(path)).collect();
print_json_pretty(&serde_json::json!({
"name": args.name,

View file

@ -5,21 +5,17 @@ use fabro_config::project::{
WorkflowInfo, WorkflowSource, discover_project_config, list_workflows_detailed,
resolve_fabro_root,
};
use fabro_types::settings::CliNamespace;
use fabro_types::settings::cli::OutputFormat;
use fabro_util::printer::Printer;
use fabro_util::terminal::Styles;
use crate::args::WorkflowListArgs;
use crate::command_context::CommandContext;
use crate::shared::{color_if, print_json_pretty, relative_path};
const GOAL_MAX_LEN: usize = 60;
pub(super) fn list_command(
_args: &WorkflowListArgs,
cli: &CliNamespace,
printer: Printer,
) -> Result<()> {
pub(super) fn list_command(_args: &WorkflowListArgs, base_ctx: &CommandContext) -> Result<()> {
let printer = base_ctx.printer();
let styles = Styles::detect_stderr();
let cwd = std::env::current_dir()?;
@ -36,7 +32,7 @@ pub(super) fn list_command(
let workflows = list_workflows_detailed(Some(&project_wf_dir), user_wf_dir.as_deref());
if cli.output.format == OutputFormat::Json {
if base_ctx.json_output() {
print_json_pretty(&workflows)?;
return Ok(());
}

View file

@ -2,14 +2,13 @@ mod create;
mod list;
use anyhow::Result;
use fabro_types::settings::CliNamespace;
use fabro_util::printer::Printer;
use crate::args::{WorkflowCommand, WorkflowNamespace};
use crate::command_context::CommandContext;
pub(crate) fn dispatch(ns: WorkflowNamespace, cli: &CliNamespace, printer: Printer) -> Result<()> {
pub(crate) fn dispatch(ns: WorkflowNamespace, base_ctx: &CommandContext) -> Result<()> {
match ns.command {
WorkflowCommand::List(args) => list::list_command(&args, cli, printer),
WorkflowCommand::Create(args) => create::create_command(&args, cli, printer),
WorkflowCommand::List(args) => list::list_command(&args, base_ctx),
WorkflowCommand::Create(args) => create::create_command(&args, base_ctx),
}
}

View file

@ -208,7 +208,10 @@ async fn main_inner() -> (String, Result<()>) {
let build_base_ctx = || resolved_base.to_context();
match *command {
Commands::Exec(args) => commands::exec::execute(args, cli_settings, printer).await?,
Commands::Exec(args) => {
let base_ctx = build_base_ctx()?;
commands::exec::execute(args, &base_ctx).await?;
}
Commands::RunCmd(cmd) => {
let base_ctx = build_base_ctx()?;
Box::pin(commands::run::dispatch(cmd, &base_ctx)).await?;
@ -228,7 +231,7 @@ async fn main_inner() -> (String, Result<()>) {
commands::graph::run(&args, &styles, &base_ctx).await?;
}
Commands::Parse(args) => {
commands::parse::run(&args, cli_settings, printer)?;
commands::parse::run(&args)?;
}
Commands::Artifact(ns) => {
let base_ctx = build_base_ctx()?;
@ -298,7 +301,8 @@ async fn main_inner() -> (String, Result<()>) {
.await?;
}
Commands::Uninstall(args) => {
commands::uninstall::run_uninstall(&args, cli_settings, printer).await?;
let base_ctx = build_base_ctx()?;
commands::uninstall::run_uninstall(&args, &base_ctx).await?;
}
Commands::Auth(ns) => {
let base_ctx = build_base_ctx()?;
@ -316,9 +320,13 @@ async fn main_inner() -> (String, Result<()>) {
let base_ctx = build_base_ctx()?;
Box::pin(commands::config::execute(&args, &base_ctx)).await?;
}
Commands::Workflow(ns) => commands::workflow::dispatch(ns, cli_settings, printer)?,
Commands::Workflow(ns) => {
let base_ctx = build_base_ctx()?;
commands::workflow::dispatch(ns, &base_ctx)?;
}
Commands::Upgrade(args) => {
commands::upgrade::run_upgrade(args, cli_settings, printer).await?;
let base_ctx = build_base_ctx()?;
commands::upgrade::run_upgrade(args, &base_ctx).await?;
}
Commands::Provider(ns) => {
let base_ctx = build_base_ctx()?;