cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 410a3a0d8f4109567e171bdf7d550b18582208b5
parent 5c546c2ab5fb964b8b711e3ae9e336122d4694ed
Author: triesap <tyson@radroots.org>
Date:   Sat, 25 Apr 2026 00:15:07 +0000

runtime: use canonical workspace config path

Diffstat:
Msrc/render/mod.rs | 44+++++++++++++++++++++++++++++---------------
Msrc/runtime/config.rs | 24++++++++++++++----------
Msrc/runtime/farm_config.rs | 8++++----
Msrc/runtime/paths.rs | 2+-
Msrc/runtime/provider.rs | 6++++--
Mtests/listing.rs | 2+-
Mtests/market.rs | 2+-
Mtests/myc_status.rs | 2+-
Mtests/order.rs | 2+-
Mtests/relay_net.rs | 2+-
Mtests/runtime_show.rs | 8++++----
Mtests/sync.rs | 6+++---
Mtests/workflow.rs | 2+-
13 files changed, 65 insertions(+), 45 deletions(-)

diff --git a/src/render/mod.rs b/src/render/mod.rs @@ -4,14 +4,14 @@ use crate::domain::runtime::{ AccountClearDefaultView, AccountImportView, AccountListView, AccountRemoveView, AccountSummaryView, CommandOutput, CommandView, DoctorCheckView, DoctorView, FarmConfigSummaryView, FarmGetView, FarmPublishComponentView, FarmPublishView, FarmSetView, - FarmSetupView, FarmStatusView, FindView, JobGetView, JobListView, JobWatchView, - ListingGetView, ListingMutationView, ListingNewView, ListingValidateView, LocalBackupView, - LocalExportView, LocalInitView, LocalStatusView, NetStatusView, OrderCancelView, - OrderDraftItemView, OrderGetView, OrderHistoryView, OrderJobView, OrderListView, OrderNewView, - OrderSubmitView, OrderSubmitWatchView, OrderWatchView, OrderWorkflowView, RelayListView, - RpcSessionsView, RpcStatusView, RuntimeActionView, RuntimeLogsView, RuntimeManagedConfigView, - RuntimeStatusView, SellAddView, SellCheckView, SellDraftMutationView, SellMutationView, - SellShowView, SetupView, StatusView, SyncActionView, SyncStatusView, SyncWatchView, + FarmSetupView, FarmStatusView, FindView, JobGetView, JobListView, JobWatchView, ListingGetView, + ListingMutationView, ListingNewView, ListingValidateView, LocalBackupView, LocalExportView, + LocalInitView, LocalStatusView, NetStatusView, OrderCancelView, OrderDraftItemView, + OrderGetView, OrderHistoryView, OrderJobView, OrderListView, OrderNewView, OrderSubmitView, + OrderSubmitWatchView, OrderWatchView, OrderWorkflowView, RelayListView, RpcSessionsView, + RpcStatusView, RuntimeActionView, RuntimeLogsView, RuntimeManagedConfigView, RuntimeStatusView, + SellAddView, SellCheckView, SellDraftMutationView, SellMutationView, SellShowView, SetupView, + StatusView, SyncActionView, SyncStatusView, SyncWatchView, }; use crate::runtime::RuntimeError; use crate::runtime::config::{OutputConfig, OutputFormat, Verbosity}; @@ -773,14 +773,20 @@ fn verbose_details(output: &CommandOutput) -> Vec<(&'static str, String)> { match output.view() { CommandView::AccountClearDefault(view) => vec![ ("Source", view.source.clone()), - ("Remaining accounts", view.remaining_account_count.to_string()), + ( + "Remaining accounts", + view.remaining_account_count.to_string(), + ), ], CommandView::AccountImport(view) => vec![("Source", view.source.clone())], CommandView::AccountList(view) => vec![("Source", view.source.clone())], CommandView::AccountNew(view) => vec![("Source", view.source.clone())], CommandView::AccountRemove(view) => vec![ ("Source", view.source.clone()), - ("Remaining accounts", view.remaining_account_count.to_string()), + ( + "Remaining accounts", + view.remaining_account_count.to_string(), + ), ], CommandView::AccountUse(view) => vec![("Source", view.source.clone())], CommandView::AccountWhoami(view) => vec![("Source", view.source.clone())], @@ -970,7 +976,10 @@ fn render_account_clear_default( writeln!(stdout)?; render_field_rows( stdout, - &[("Remaining accounts", view.remaining_account_count.to_string())], + &[( + "Remaining accounts", + view.remaining_account_count.to_string(), + )], )?; if !view.actions.is_empty() { writeln!(stdout)?; @@ -997,7 +1006,10 @@ fn render_account_remove( writeln!(stdout)?; render_field_rows( stdout, - &[("Remaining accounts", view.remaining_account_count.to_string())], + &[( + "Remaining accounts", + view.remaining_account_count.to_string(), + )], )?; if !view.actions.is_empty() { writeln!(stdout)?; @@ -4305,7 +4317,8 @@ mod tests { shared_accounts_namespace: "shared/accounts".into(), shared_identities_namespace: "shared/identities".into(), app_config_path: "/home/tester/.radroots/config/apps/cli/config.toml".into(), - workspace_config_path: "/workspace/.radroots/config.toml".into(), + workspace_config_path: "/workspace/infra/local/runtime/radroots/config.toml" + .into(), app_data_root: "/home/tester/.radroots/data/apps/cli".into(), app_logs_root: "/home/tester/.radroots/logs/apps/cli".into(), shared_accounts_data_root: "/home/tester/.radroots/data/shared/accounts".into(), @@ -4385,7 +4398,7 @@ mod tests { assert_eq!(view.paths.shared_accounts_namespace, "shared/accounts"); assert_eq!( view.paths.workspace_config_path, - "/workspace/.radroots/config.toml" + "/workspace/infra/local/runtime/radroots/config.toml" ); assert_eq!(view.account.selector.as_deref(), Some("acct_demo")); assert!( @@ -4464,7 +4477,8 @@ mod tests { shared_identities_namespace: "shared/identities".into(), app_config_path: "/home/tester/.radroots/config/apps/cli/config.toml" .into(), - workspace_config_path: "/workspace/.radroots/config.toml".into(), + workspace_config_path: + "/workspace/infra/local/runtime/radroots/config.toml".into(), app_data_root: "/home/tester/.radroots/data/apps/cli".into(), app_logs_root: "/home/tester/.radroots/logs/apps/cli".into(), shared_accounts_data_root: "/home/tester/.radroots/data/shared/accounts" diff --git a/src/runtime/config.rs b/src/runtime/config.rs @@ -1500,7 +1500,7 @@ mod tests { "/home/tester/.radroots/config/apps/cli/config.toml" ), workspace_config_path: PathBuf::from( - "/workspaces/radroots-cli/.radroots/config.toml" + "/workspaces/radroots-cli/infra/local/runtime/radroots/config.toml" ), app_data_root: PathBuf::from("/home/tester/.radroots/data/apps/cli"), app_logs_root: PathBuf::from("/home/tester/.radroots/logs/apps/cli"), @@ -1848,10 +1848,11 @@ RADROOTS_CLI_LOGGING_STDOUT=false let temp = tempdir().expect("tempdir"); let workspace_root = temp.path().join("workspace"); let user_home = temp.path().join("home"); - fs::create_dir_all(workspace_root.join(".radroots")).expect("workspace config dir"); + fs::create_dir_all(workspace_root.join("infra/local/runtime/radroots")) + .expect("workspace config dir"); fs::create_dir_all(user_home.join(".radroots/config/apps/cli")).expect("app config dir"); fs::write( - workspace_root.join(".radroots/config.toml"), + workspace_root.join("infra/local/runtime/radroots/config.toml"), "[relay]\nurls = [\"wss://relay.workspace\"]\npublish_policy = \"any\"\n", ) .expect("write workspace config"); @@ -1894,10 +1895,11 @@ RADROOTS_CLI_LOGGING_STDOUT=false let temp = tempdir().expect("tempdir"); let workspace_root = temp.path().join("workspace"); let user_home = temp.path().join("home"); - fs::create_dir_all(workspace_root.join(".radroots")).expect("workspace config dir"); + fs::create_dir_all(workspace_root.join("infra/local/runtime/radroots")) + .expect("workspace config dir"); fs::create_dir_all(user_home.join(".radroots/config/apps/cli")).expect("app config dir"); fs::write( - workspace_root.join(".radroots/config.toml"), + workspace_root.join("infra/local/runtime/radroots/config.toml"), "[hyf]\nenabled = false\nexecutable = \"workspace-hyfd\"\n", ) .expect("write workspace config"); @@ -1938,10 +1940,11 @@ RADROOTS_CLI_LOGGING_STDOUT=false let temp = tempdir().expect("tempdir"); let workspace_root = temp.path().join("workspace"); let user_home = temp.path().join("home"); - fs::create_dir_all(workspace_root.join(".radroots")).expect("workspace config dir"); + fs::create_dir_all(workspace_root.join("infra/local/runtime/radroots")) + .expect("workspace config dir"); fs::create_dir_all(user_home.join(".radroots/config/apps/cli")).expect("app config dir"); fs::write( - workspace_root.join(".radroots/config.toml"), + workspace_root.join("infra/local/runtime/radroots/config.toml"), r#" [[capability_binding]] capability = "inference.hyf_stdio" @@ -2001,10 +2004,11 @@ target = "bin/user-hyfd" let temp = tempdir().expect("tempdir"); let workspace_root = temp.path().join("workspace"); let user_home = temp.path().join("home"); - fs::create_dir_all(workspace_root.join(".radroots")).expect("workspace config dir"); + fs::create_dir_all(workspace_root.join("infra/local/runtime/radroots")) + .expect("workspace config dir"); fs::create_dir_all(user_home.join(".radroots/config/apps/cli")).expect("app config dir"); fs::write( - workspace_root.join(".radroots/config.toml"), + workspace_root.join("infra/local/runtime/radroots/config.toml"), r#" [[capability_binding]] capability = "write_plane.trade_jsonrpc" @@ -2081,7 +2085,7 @@ target = "https://rpc.workspace.test/jsonrpc" ); assert_eq!( resolved.paths.workspace_config_path, - PathBuf::from("/workspaces/radroots-cli/.radroots/config.toml") + PathBuf::from("/workspaces/radroots-cli/infra/local/runtime/radroots/config.toml") ); assert_eq!( resolved.paths.app_data_root, diff --git a/src/runtime/farm_config.rs b/src/runtime/farm_config.rs @@ -355,14 +355,14 @@ mod tests { profile_source: "test".to_owned(), allowed_profiles: vec!["interactive_user".to_owned(), "repo_local".to_owned()], root_source: "test".to_owned(), - repo_local_root: Some(root.join(".radroots")), + repo_local_root: Some(root.join("infra/local/runtime/radroots")), repo_local_root_source: Some("test".to_owned()), subordinate_path_override_source: "test".to_owned(), app_namespace: "apps/cli".to_owned(), shared_accounts_namespace: "shared/accounts".to_owned(), shared_identities_namespace: "shared/identities".to_owned(), app_config_path: root.join("home/.radroots/config/apps/cli/config.toml"), - workspace_config_path: root.join("workspace/.radroots/config.toml"), + workspace_config_path: root.join("workspace/infra/local/runtime/radroots/config.toml"), app_data_root: root.join("home/.radroots/data/apps/cli"), app_logs_root: root.join("home/.radroots/logs/apps/cli"), shared_accounts_data_root: root.join("home/.radroots/data/shared/accounts"), @@ -462,8 +462,8 @@ mod tests { let dir = tempdir().expect("tempdir"); let paths = sample_paths("repo_local", dir.path()); let document = sample_document(FarmConfigScope::Workspace); - let expected_path = - PathBuf::from(dir.path()).join("workspace/.radroots/config/apps/cli/farm.toml"); + let expected_path = PathBuf::from(dir.path()) + .join("workspace/infra/local/runtime/radroots/config/apps/cli/farm.toml"); let written_path = write(&paths, FarmConfigScope::Workspace, &document).expect("write workspace config"); diff --git a/src/runtime/paths.rs b/src/runtime/paths.rs @@ -10,7 +10,7 @@ use crate::runtime::{ config::{EnvFileValues, Environment}, }; -const DEFAULT_WORKSPACE_CONFIG_PATH: &str = ".radroots/config.toml"; +const DEFAULT_WORKSPACE_CONFIG_PATH: &str = "infra/local/runtime/radroots/config.toml"; const CLI_DEFAULT_PROFILE: &str = "interactive_user"; const CLI_REPO_LOCAL_PROFILE: &str = "repo_local"; const CLI_APP_NAMESPACE_VALUE: &str = "cli"; diff --git a/src/runtime/provider.rs b/src/runtime/provider.rs @@ -768,7 +768,9 @@ mod tests { shared_accounts_namespace: "shared/accounts".into(), shared_identities_namespace: "shared/identities".into(), app_config_path: PathBuf::from("/tmp/config/apps/cli/config.toml"), - workspace_config_path: PathBuf::from("/tmp/workspace/.radroots/config.toml"), + workspace_config_path: PathBuf::from( + "/tmp/workspace/infra/local/runtime/radroots/config.toml", + ), app_data_root: PathBuf::from("/tmp/data"), app_logs_root: PathBuf::from("/tmp/logs"), shared_accounts_data_root: PathBuf::from("/tmp/shared/accounts"), @@ -865,7 +867,7 @@ mod tests { #[test] fn workflow_reports_ready_for_canonical_repo_local_localhost_posture() { let dir = tempdir().expect("tempdir"); - let repo_local_root = dir.path().join(".radroots"); + let repo_local_root = dir.path().join("infra/local/runtime/radroots"); let base_paths = RadrootsPathResolver::current() .resolve( RadrootsPathProfile::RepoLocal, diff --git a/tests/listing.rs b/tests/listing.rs @@ -57,7 +57,7 @@ fn cli_command_in(workdir: &Path) -> Command { } fn write_workspace_config(workdir: &Path, contents: &str) { - let config_dir = workdir.join(".radroots"); + let config_dir = workdir.join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write(config_dir.join("config.toml"), contents).expect("write workspace config"); } diff --git a/tests/market.rs b/tests/market.rs @@ -185,7 +185,7 @@ fn market_update_stays_honest_about_unavailable_ingest() { .expect("run local init"); assert!(init.status.success()); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), diff --git a/tests/myc_status.rs b/tests/myc_status.rs @@ -43,7 +43,7 @@ fn cli_command_in(workdir: &Path) -> Command { } fn write_workspace_config(workdir: &Path, contents: &str) { - let config_dir = workdir.join(".radroots"); + let config_dir = workdir.join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write(config_dir.join("config.toml"), contents).expect("write workspace config"); } diff --git a/tests/order.rs b/tests/order.rs @@ -56,7 +56,7 @@ fn order_command_in(workdir: &Path) -> Command { } fn write_workspace_config(workdir: &Path, contents: &str) { - let config_dir = workdir.join(".radroots"); + let config_dir = workdir.join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write(config_dir.join("config.toml"), contents).expect("write workspace config"); } diff --git a/tests/relay_net.rs b/tests/relay_net.rs @@ -41,7 +41,7 @@ fn cli_command_in(workdir: &Path) -> Command { #[test] fn relay_ls_json_reports_workspace_configured_relays() { let dir = tempdir().expect("tempdir"); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), diff --git a/tests/runtime_show.rs b/tests/runtime_show.rs @@ -150,7 +150,7 @@ fn config_show_json_reports_default_bootstrap_state() { assert_eq!( json["paths"]["workspace_config_path"], canonical_root - .join(".radroots/config.toml") + .join("infra/local/runtime/radroots/config.toml") .display() .to_string() ); @@ -568,7 +568,7 @@ fn config_show_json_reads_logging_from_default_env_file() { #[test] fn config_show_json_reads_workspace_relay_config() { let dir = tempdir().expect("tempdir"); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), @@ -593,7 +593,7 @@ fn config_show_json_reads_workspace_relay_config() { #[test] fn config_show_reads_workspace_rpc_config() { let dir = tempdir().expect("tempdir"); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), @@ -615,7 +615,7 @@ fn config_show_reads_workspace_rpc_config() { #[test] fn config_show_reports_explicit_capability_bindings() { let dir = tempdir().expect("tempdir"); - let workspace_config_dir = dir.path().join(".radroots"); + let workspace_config_dir = dir.path().join("infra/local/runtime/radroots"); let user_config_dir = config_root(dir.path()).join("apps/cli"); fs::create_dir_all(&workspace_config_dir).expect("workspace config dir"); fs::create_dir_all(&user_config_dir).expect("user config dir"); diff --git a/tests/sync.rs b/tests/sync.rs @@ -88,7 +88,7 @@ fn sync_pull_and_push_are_honestly_narrowed_until_relay_plane_lands() { .output() .expect("run local init"); assert!(init.status.success()); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), @@ -135,7 +135,7 @@ fn sync_watch_ndjson_emits_one_frame_per_poll() { .output() .expect("run local init"); assert!(init.status.success()); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), @@ -174,7 +174,7 @@ fn sync_watch_human_appends_readable_snapshots_without_screen_clear() { .output() .expect("run local init"); assert!(init.status.success()); - let config_dir = dir.path().join(".radroots"); + let config_dir = dir.path().join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write( config_dir.join("config.toml"), diff --git a/tests/workflow.rs b/tests/workflow.rs @@ -49,7 +49,7 @@ fn cli_command_in(workdir: &Path) -> Command { } fn write_workspace_config(workdir: &Path, contents: &str) { - let config_dir = workdir.join(".radroots"); + let config_dir = workdir.join("infra/local/runtime/radroots"); fs::create_dir_all(&config_dir).expect("workspace config dir"); fs::write(config_dir.join("config.toml"), contents).expect("write workspace config"); }