cli

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

commit 354c1d06c55eff80f1a24e666ba231667f7e1059
parent d49ba4f3d7bf43f4a33d57d6393b520d6f410e2a
Author: triesap <tyson@radroots.org>
Date:   Mon, 27 Apr 2026 09:18:09 +0000

cli: fix action command guidance

- remove incomplete market basket item action suggestions
- replace runtime install guidance with public status inspection
- expand removed-command output scans
- align documented seller flow with required farm fields

Diffstat:
Msrc/operation_market.rs | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/runtime/management.rs | 8++++----
Mtests/support/mod.rs | 7+++++++
Mtests/target_cli.rs | 1+
4 files changed, 119 insertions(+), 15 deletions(-)

diff --git a/src/operation_market.rs b/src/operation_market.rs @@ -117,7 +117,6 @@ fn market_product_search_view(mut view: FindView) -> FindView { )]; if listing_addr_can_back_basket(result.listing_addr.as_deref()) { actions.push("radroots basket create".to_owned()); - actions.push(format!("radroots basket item add {}", result.product_key)); } actions }) @@ -138,16 +137,8 @@ fn market_product_search_view(mut view: FindView) -> FindView { fn market_listing_get_view(mut view: ListingGetView) -> ListingGetView { view.actions = match view.state.as_str() { "ready" => { - let listing_key = view - .product_key - .as_deref() - .unwrap_or(view.lookup.as_str()) - .to_owned(); if listing_addr_can_back_basket(view.listing_addr.as_deref()) { - vec![ - "radroots basket create".to_owned(), - format!("radroots basket item add {listing_key}"), - ] + vec!["radroots basket create".to_owned()] } else { Vec::new() } @@ -282,7 +273,11 @@ mod tests { use serde_json::{Map, Value}; use tempfile::tempdir; - use super::MarketOperationService; + use super::{MarketOperationService, market_listing_get_view, market_product_search_view}; + use crate::domain::runtime::{ + FindPriceView, FindQuantityView, FindResultProvenanceView, FindResultView, FindView, + ListingGetView, SyncFreshnessView, + }; use crate::operation_adapter::{ MarketListingGetRequest, MarketProductSearchRequest, MarketRefreshRequest, OperationAdapter, OperationContext, OperationData, OperationRequest, @@ -294,6 +289,8 @@ mod tests { SignerBackend, SignerConfig, Verbosity, }; + const LISTING_ADDR: &str = "30402:1111111111111111111111111111111111111111111111111111111111111111:AAAAAAAAAAAAAAAAAAAAAg"; + #[test] fn market_refresh_preserves_unconfigured_ingest_truth() { let dir = tempdir().expect("tempdir"); @@ -392,6 +389,105 @@ mod tests { assert_eq!(envelope.result["actions"][0], "radroots store init"); } + #[test] + fn market_ready_actions_do_not_emit_incomplete_basket_item_add_commands() { + let search = market_product_search_view(FindView { + state: "ready".to_owned(), + source: "test".to_owned(), + query: "eggs".to_owned(), + count: 1, + relay_count: 1, + replica_db: "ready".to_owned(), + freshness: freshness(), + results: vec![FindResultView { + id: "listing_eggs".to_owned(), + product_key: "eggs".to_owned(), + listing_addr: Some(LISTING_ADDR.to_owned()), + title: "Eggs".to_owned(), + category: "eggs".to_owned(), + summary: None, + location_primary: None, + available: quantity(), + price: price(), + provenance: provenance(), + hyf: None, + }], + hyf: None, + reason: None, + actions: Vec::new(), + }); + + assert_eq!( + search.actions, + vec![ + "radroots market listing get eggs".to_owned(), + "radroots basket create".to_owned() + ] + ); + + let listing = market_listing_get_view(ListingGetView { + state: "ready".to_owned(), + source: "test".to_owned(), + lookup: "eggs".to_owned(), + listing_id: Some("listing_eggs".to_owned()), + product_key: Some("eggs".to_owned()), + listing_addr: Some(LISTING_ADDR.to_owned()), + title: Some("Eggs".to_owned()), + category: Some("eggs".to_owned()), + description: None, + location_primary: None, + available: Some(quantity()), + price: Some(price()), + provenance: provenance(), + reason: None, + actions: Vec::new(), + }); + + assert_eq!(listing.actions, vec!["radroots basket create".to_owned()]); + assert!( + search + .actions + .iter() + .chain(listing.actions.iter()) + .all(|action| !action.starts_with("radroots basket item add ")) + ); + } + + fn freshness() -> SyncFreshnessView { + SyncFreshnessView { + state: "fresh".to_owned(), + display: "fresh".to_owned(), + age_seconds: Some(0), + last_event_at: Some(0), + } + } + + fn provenance() -> FindResultProvenanceView { + FindResultProvenanceView { + origin: "fixture".to_owned(), + freshness: "fresh".to_owned(), + relay_count: 1, + } + } + + fn quantity() -> FindQuantityView { + FindQuantityView { + total_amount: 1, + total_unit: "each".to_owned(), + label: None, + available_amount: Some(1), + } + } + + fn price() -> FindPriceView { + FindPriceView { + amount: 6.0, + currency: "USD".to_owned(), + per_amount: 1, + per_unit: "each".to_owned(), + } + } + fn sample_config(root: &Path) -> RuntimeConfig { let data = root.join("data"); let logs = root.join("logs"); diff --git a/src/runtime/management.rs b/src/runtime/management.rs @@ -348,8 +348,8 @@ fn execute_config_set( &target, RuntimeLifecycleAction::ConfigSet, format!( - "managed runtime `{}` instance `{}` is not installed; run `radroots runtime install {}` first", - target.runtime_id, target.instance_id, target.runtime_id + "managed runtime `{}` instance `{}` is not installed in local runtime state; run `radroots runtime status get` for current status", + target.runtime_id, target.instance_id ), )); }; @@ -504,8 +504,8 @@ fn start_managed_radrootsd( &target, RuntimeLifecycleAction::Start, format!( - "managed runtime `{}` instance `{}` is not installed; run `radroots runtime install {}` first", - target.runtime_id, target.instance_id, target.runtime_id + "managed runtime `{}` instance `{}` is not installed in local runtime state; run `radroots runtime status get` for current status", + target.runtime_id, target.instance_id ), )); }; diff --git a/tests/support/mod.rs b/tests/support/mod.rs @@ -136,6 +136,13 @@ pub fn assert_no_removed_command_reference(value: &Value, args: &[&str]) { "radroots account new", "radroots config show", "radroots runtime config show", + "radroots runtime install", + "radroots runtime uninstall", + "radroots runtime config set", + "radroots signer session", + "myc status", + "radroots job cancel", + "radroots job retry", "radroots market search", "radroots market view", "radroots market update", diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -119,6 +119,7 @@ fn target_outputs_do_not_suggest_removed_command_families() { ["--format", "json", "market", "listing", "get", "eggs"].as_slice(), ["--format", "json", "listing", "get", "eggs"].as_slice(), ["--format", "json", "sync", "status", "get"].as_slice(), + ["--format", "json", "runtime", "start"].as_slice(), [ "--format", "json",