cli

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

commit e0797c775856e9e58630feb811360c20c18fcebd
parent b4765d78c6edfa261cbf0aa19af9156abec98834
Author: triesap <tyson@radroots.org>
Date:   Tue,  7 Jul 2026 06:11:24 +0000

transport: align CLI Reticulum preview status

- replace Reticulum preview Nostr relay guidance with transport-neutral follow-up actions
- assert profile output exposes preview_unavailable and unusable delivery state
- assert status output preserves Reticulum behavior without Nostr-specific messaging
- add mesh status coverage for explicit unavailable Reticulum preview state

Diffstat:
Msrc/runtime/transport.rs | 20++++++++++++++++----
Mtests/target_cli.rs | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/src/runtime/transport.rs b/src/runtime/transport.rs @@ -242,14 +242,26 @@ fn profile_view_from_parts( nostr_relays, reticulum_preview_behavior, proxy_url, - actions: if usable_for_delivery { - Vec::new() - } else { + actions: profile_actions(profile_id, usable_for_delivery), + } +} + +fn profile_actions(profile_id: &str, usable_for_delivery: bool) -> Vec<String> { + if usable_for_delivery { + return Vec::new(); + } + match profile_id { + "reticulum_preview" => vec![ + "radroots mesh status".to_owned(), + "radroots transport profile get".to_owned(), + ], + "nostr" => { vec![ "radroots transport profile set --kind nostr --nostr-relay wss://relay.example.com" .to_owned(), ] - }, + } + _ => vec!["radroots transport profile get".to_owned()], } } diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -1283,6 +1283,99 @@ fn root_help_explains_transport_and_mesh_surfaces() { assert!(stdout.contains("Show effective configuration and publish-plane readiness.")); } +#[test] +fn transport_profile_reticulum_preview_output_is_transport_specific() { + let sandbox = RadrootsCliSandbox::new(); + sandbox.write_app_config( + "[transport]\nprofile = \"reticulum_preview\"\n\n[transport.reticulum_preview]\nbehavior = \"defer_delivery_plans\"\n", + ); + + let value = sandbox.json_success(&["--format", "json", "transport", "profile", "get"]); + let result = &value["result"]; + let actions = result["actions"].as_array().expect("actions"); + + assert_eq!(value["operation_id"], "transport.profile.get"); + assert_eq!(result["profile_id"], "reticulum_preview"); + assert_eq!(result["transport_kind"], "reticulum"); + assert_eq!(result["implementation_state"], "preview_unavailable"); + assert_eq!(result["usable_for_delivery"], false); + assert_eq!(result["reticulum_preview_behavior"], "defer_delivery_plans"); + assert_contains( + &result["message"], + "Reticulum preview is explicit and unavailable", + ); + assert!( + !result["message"] + .as_str() + .expect("message") + .contains("Nostr") + ); + assert_eq!(actions.len(), 2); + assert_eq!(actions[0], "radroots mesh status"); + assert_eq!(actions[1], "radroots transport profile get"); + assert!( + !serde_json::to_string(actions) + .expect("actions json") + .contains("nostr") + ); +} + +#[test] +fn transport_status_reticulum_preview_output_reports_unusable_preview_state() { + let sandbox = RadrootsCliSandbox::new(); + sandbox.write_app_config( + "[transport]\nprofile = \"reticulum_preview\"\n\n[transport.reticulum_preview]\nbehavior = \"defer_delivery_plans\"\n", + ); + + let value = sandbox.json_success(&["--format", "json", "transport", "status"]); + let result = &value["result"]; + let transports = result["transports"].as_array().expect("transports"); + let active = &transports[0]; + + assert_eq!(value["operation_id"], "transport.status"); + assert_eq!(result["state"], "ready"); + assert_eq!(active["profile_id"], "reticulum_preview"); + assert_eq!(active["transport_kind"], "reticulum"); + assert_eq!(active["implementation_state"], "preview_unavailable"); + assert_eq!(active["usable_for_delivery"], false); + assert_eq!(active["reticulum_preview_behavior"], "defer_delivery_plans"); + assert_contains( + &active["message"], + "Reticulum preview is explicit and unavailable", + ); + assert!( + !active["message"] + .as_str() + .expect("message") + .contains("Nostr") + ); + assert!( + !serde_json::to_string(&active["actions"]) + .expect("actions json") + .contains("nostr") + ); +} + +#[test] +fn mesh_status_reports_reticulum_preview_unusable_state_without_fallback() { + let sandbox = RadrootsCliSandbox::new(); + + let value = sandbox.json_success(&["--format", "json", "mesh", "status"]); + let result = &value["result"]; + + assert_eq!(value["operation_id"], "mesh.status"); + assert_eq!(result["transport_kind"], "reticulum"); + assert_eq!(result["implementation_state"], "preview_unavailable"); + assert_eq!(result["usable_for_delivery"], false); + assert_contains(&result["message"], "Reticulum mesh preview is explicit"); + assert!( + !result["message"] + .as_str() + .expect("message") + .contains("Nostr") + ); +} + fn help_lists(stdout: &str, command: &str) -> bool { stdout.lines().any(|line| { let line = line.trim_start();