From 38ed34b6031a86f9f27145a53b0d6be0968dd24d Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Fri, 22 May 2026 10:57:09 +0000 Subject: [PATCH 1/6] cli: rename doublezero_cli to doublezero-serviceability-cli --- CHANGELOG.md | 1 + Cargo.lock | 50 +++++++++---------- Cargo.toml | 2 +- client/doublezero-geolocation-cli/Cargo.toml | 2 +- .../src/cli/command.rs | 2 +- .../src/cli/config.rs | 2 +- .../src/cli/probe.rs | 2 +- .../src/cli/user.rs | 2 +- client/doublezero-geolocation-cli/src/main.rs | 2 +- client/doublezero/Cargo.toml | 4 +- client/doublezero/src/cli/accesspass.rs | 2 +- client/doublezero/src/cli/command.rs | 2 +- client/doublezero/src/cli/config.rs | 2 +- client/doublezero/src/cli/contributor.rs | 4 +- client/doublezero/src/cli/device.rs | 2 +- client/doublezero/src/cli/exchange.rs | 2 +- .../doublezero/src/cli/geolocation/probe.rs | 2 +- client/doublezero/src/cli/geolocation/user.rs | 2 +- client/doublezero/src/cli/globalconfig.rs | 2 +- client/doublezero/src/cli/link.rs | 2 +- client/doublezero/src/cli/location.rs | 2 +- client/doublezero/src/cli/multicastgroup.rs | 2 +- client/doublezero/src/cli/permission.rs | 4 +- client/doublezero/src/cli/resource.rs | 2 +- client/doublezero/src/cli/tenant.rs | 2 +- client/doublezero/src/cli/user.rs | 2 +- client/doublezero/src/command/connect.rs | 14 +++--- client/doublezero/src/command/disable.rs | 6 +-- client/doublezero/src/command/disconnect.rs | 4 +- client/doublezero/src/command/enable.rs | 6 +-- client/doublezero/src/command/latency.rs | 2 +- client/doublezero/src/command/multicast.rs | 4 +- client/doublezero/src/command/routes.rs | 2 +- client/doublezero/src/command/status.rs | 4 +- client/doublezero/src/main.rs | 8 +-- client/doublezero/src/requirements.rs | 2 +- controlplane/doublezero-admin/Cargo.toml | 2 +- .../doublezero-admin/src/cli/accesspass.rs | 2 +- .../doublezero-admin/src/cli/command.rs | 2 +- .../doublezero-admin/src/cli/config.rs | 2 +- .../doublezero-admin/src/cli/contributor.rs | 4 +- .../doublezero-admin/src/cli/device.rs | 18 +++---- .../doublezero-admin/src/cli/exchange.rs | 2 +- .../doublezero-admin/src/cli/globalconfig.rs | 2 +- controlplane/doublezero-admin/src/cli/link.rs | 2 +- .../doublezero-admin/src/cli/location.rs | 2 +- .../doublezero-admin/src/cli/migrate.rs | 2 +- .../src/cli/multicastgroup.rs | 2 +- .../doublezero-admin/src/cli/permission.rs | 4 +- .../doublezero-admin/src/cli/tenant.rs | 2 +- controlplane/doublezero-admin/src/cli/user.rs | 2 +- controlplane/doublezero-admin/src/main.rs | 2 +- smartcontract/cli/Cargo.toml | 4 +- 53 files changed, 112 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c4e52e05..8fd61cb921 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - Add `--log-level ` global flag and initialize the `tracing` subscriber at startup. `LEVEL` is one of `off`, `error`, `warn` (default), `info`, `debug`, `trace`. Diagnostic logs go to stderr so `--json` output on stdout remains parseable. Honors the `RUST_LOG` environment variable when set, overriding the CLI-flag level for per-module filtering. Replaces the previous `println!("using keypair: ...")` stdout line with a `tracing::info!` event; the keypair confirmation now appears only at `--log-level info` or higher and no longer pollutes parseable stdout. (Named `--log-level` rather than the RFC-20 §Global-flags suggested `--verbose` / `-v` because the existing `doublezero connect` / `disconnect` subcommands already own a `--verbose` flag with `bool` type; the global flag deviation will be revisited when the daemon-control module crate is carved out.) - Build a `CliContext` once at binary startup from `--env`, the per-field global overrides (`--url`, `--ws`, `--solana-url`, `--program-id`, `--geo-program-id`, `--keypair`, `--sock-file`), and the persisted `~/.config/doublezero/cli/config.yml` (overridable via `DOUBLEZERO_CONFIG_FILE`), per RFC-20 (§CliContext). Precedence (highest wins): CLI flag > persisted config > env-derived default. When `--env` is not set and the persisted config has a serviceability program ID, the environment is derived from that program ID via `Environment::from_program_id`; otherwise the binary falls back to `Environment::default()`. The legacy `DZClient` is now constructed from the fully resolved `CliContext` URL, WebSocket, and program-ID values directly, so verbs that migrate to read `CliContext` see the same backend as the legacy bridge. Keypair resolution is intentionally left to `DZClient::new`'s internal `load_keypair` precedence (CLI `--keypair` flag > `DOUBLEZERO_KEYPAIR` env var > stdin > persisted config) so the `DOUBLEZERO_KEYPAIR` env var continues to override the persisted keypair path, as relied on by the e2e contributor-auth negative-authz suite. File reads happen only in the binary; module crates remain forbidden from touching the filesystem (RFC-20 §67). - Centralize top-level error rendering through `doublezero_cli_core::error::render_eyre`. Replaces three ad-hoc `eprintln!("Error: {e}")` sites in `client/doublezero/src/main.rs` (env-parse failure, env-config resolution failure, top-level command failure) with a single helper that prints `Error: ` followed by the full chain of causes on stderr. + - Rename the `smartcontract/cli/` crate from `doublezero_cli` to `doublezero-serviceability-cli` to satisfy RFC-20's module-crate naming contract (`doublezero--cli` in kebab-case). The crate stays at `smartcontract/cli/`; only the `[package].name` and `[lib].name` change (lib name is `doublezero_serviceability_cli` because Rust requires underscores in import paths). All in-tree consumers are updated: `client/doublezero`, `client/doublezero-geolocation-cli`, `controlplane/doublezero-admin`, and the workspace `Cargo.toml`. External operators who depend on the workspace crate by its old name (`doublezero_cli`) must update their `Cargo.toml` and `use` statements. No user-facing command, flag, or output change. ## [v0.24.0](https://github.com/malbeclabs/doublezero/compare/client/v0.23.0...client/v0.24.0) - 2026-05-22 diff --git a/Cargo.lock b/Cargo.lock index 4f86e2d2ec..81c37b74e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1484,7 +1484,7 @@ dependencies = [ "doublezero-config", "doublezero-program-common", "doublezero-serviceability", - "doublezero_cli", + "doublezero-serviceability-cli", "doublezero_sdk", "eyre", "futures", @@ -1524,7 +1524,7 @@ dependencies = [ "doublezero-program-common", "doublezero-sentinel", "doublezero-serviceability", - "doublezero_cli", + "doublezero-serviceability-cli", "doublezero_sdk", "eyre", "futures", @@ -1605,7 +1605,7 @@ dependencies = [ "doublezero-config", "doublezero-geolocation", "doublezero-serviceability", - "doublezero_cli", + "doublezero-serviceability-cli", "doublezero_sdk", "eyre", "libc", @@ -1696,28 +1696,7 @@ dependencies = [ ] [[package]] -name = "doublezero-telemetry" -version = "0.24.0" -dependencies = [ - "bincode 2.0.1", - "borsh 1.5.7", - "borsh-incremental", - "ctor", - "doublezero-config", - "doublezero-program-common", - "doublezero-serviceability", - "env_logger", - "log", - "serde", - "serde_bytes", - "solana-program", - "solana-program-test", - "solana-sdk", - "solana-system-interface", -] - -[[package]] -name = "doublezero_cli" +name = "doublezero-serviceability-cli" version = "0.24.0" dependencies = [ "anyhow", @@ -1752,6 +1731,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "doublezero-telemetry" +version = "0.24.0" +dependencies = [ + "bincode 2.0.1", + "borsh 1.5.7", + "borsh-incremental", + "ctor", + "doublezero-config", + "doublezero-program-common", + "doublezero-serviceability", + "env_logger", + "log", + "serde", + "serde_bytes", + "solana-program", + "solana-program-test", + "solana-sdk", + "solana-system-interface", +] + [[package]] name = "doublezero_sdk" version = "0.24.0" diff --git a/Cargo.toml b/Cargo.toml index 88d25ef721..fe8086e441 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,7 +107,7 @@ tokio = { version = "1", default-features = false, features = [ doublezero-cli-core = { path = "crates/doublezero-cli-core" } doublezero-config = { path = "config" } doublezero-sentinel = { path = "crates/sentinel" } -doublezero_cli = { path = "smartcontract/cli" } +doublezero-serviceability-cli = { path = "smartcontract/cli" } doublezero-program-common = { path = "smartcontract/programs/common" } doublezero_sdk = { path = "smartcontract/sdk/rs" } diff --git a/client/doublezero-geolocation-cli/Cargo.toml b/client/doublezero-geolocation-cli/Cargo.toml index c2fc9ffafd..653e57fe80 100644 --- a/client/doublezero-geolocation-cli/Cargo.toml +++ b/client/doublezero-geolocation-cli/Cargo.toml @@ -22,5 +22,5 @@ solana-sdk.workspace = true doublezero-config.workspace = true doublezero-geolocation.workspace = true doublezero-serviceability.workspace = true -doublezero_cli.workspace = true +doublezero-serviceability-cli.workspace = true doublezero_sdk.workspace = true diff --git a/client/doublezero-geolocation-cli/src/cli/command.rs b/client/doublezero-geolocation-cli/src/cli/command.rs index 1f8179ff60..b3ce23b1ac 100644 --- a/client/doublezero-geolocation-cli/src/cli/command.rs +++ b/client/doublezero-geolocation-cli/src/cli/command.rs @@ -1,6 +1,6 @@ use super::{config::ConfigCliCommand, probe::ProbeCliCommand, user::UserCliCommand}; use clap::Subcommand; -use doublezero_cli::geolocation::programconfig::init::InitProgramConfigCliCommand; +use doublezero_serviceability_cli::geolocation::programconfig::init::InitProgramConfigCliCommand; #[derive(Subcommand, Debug)] pub enum Command { diff --git a/client/doublezero-geolocation-cli/src/cli/config.rs b/client/doublezero-geolocation-cli/src/cli/config.rs index 886971e7ba..9e49f4c6d8 100644 --- a/client/doublezero-geolocation-cli/src/cli/config.rs +++ b/client/doublezero-geolocation-cli/src/cli/config.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::geolocation::config::{ +use doublezero_serviceability_cli::geolocation::config::{ get::GetGeoConfigCliCommand, set::SetGeoConfigCliCommand, }; diff --git a/client/doublezero-geolocation-cli/src/cli/probe.rs b/client/doublezero-geolocation-cli/src/cli/probe.rs index f94c51f47e..353b001982 100644 --- a/client/doublezero-geolocation-cli/src/cli/probe.rs +++ b/client/doublezero-geolocation-cli/src/cli/probe.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::geolocation::probe::{ +use doublezero_serviceability_cli::geolocation::probe::{ add_parent::AddParentGeoProbeCliCommand, create::CreateGeoProbeCliCommand, delete::DeleteGeoProbeCliCommand, get::GetGeoProbeCliCommand, list::ListGeoProbeCliCommand, remove_parent::RemoveParentGeoProbeCliCommand, update::UpdateGeoProbeCliCommand, diff --git a/client/doublezero-geolocation-cli/src/cli/user.rs b/client/doublezero-geolocation-cli/src/cli/user.rs index 751e075f1d..d4010a2bfd 100644 --- a/client/doublezero-geolocation-cli/src/cli/user.rs +++ b/client/doublezero-geolocation-cli/src/cli/user.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::geolocation::user::{ +use doublezero_serviceability_cli::geolocation::user::{ add_target::AddTargetCliCommand, create::CreateGeolocationUserCliCommand, delete::DeleteGeolocationUserCliCommand, get::GetGeolocationUserCliCommand, list::ListGeolocationUserCliCommand, remove_target::RemoveTargetCliCommand, diff --git a/client/doublezero-geolocation-cli/src/main.rs b/client/doublezero-geolocation-cli/src/main.rs index c6a7134050..527ba779ba 100644 --- a/client/doublezero-geolocation-cli/src/main.rs +++ b/client/doublezero-geolocation-cli/src/main.rs @@ -3,10 +3,10 @@ use std::path::PathBuf; mod cli; use cli::{command::Command, config::ConfigCommands, probe::ProbeCommands, user::UserCommands}; -use doublezero_cli::geoclicommand::GeoCliCommandImpl; use doublezero_config::Environment; use doublezero_sdk::{geolocation::client::GeoClient, DZClient}; use doublezero_serviceability::pda::get_globalstate_pda; +use doublezero_serviceability_cli::geoclicommand::GeoCliCommandImpl; #[derive(Parser, Debug)] #[command(term_width = 0)] diff --git a/client/doublezero/Cargo.toml b/client/doublezero/Cargo.toml index 8e669cf5e3..b5bdc24e2f 100644 --- a/client/doublezero/Cargo.toml +++ b/client/doublezero/Cargo.toml @@ -41,7 +41,7 @@ tokio.workspace = true # Dependencies from this workspace doublezero_sdk.workspace = true -doublezero_cli.workspace = true +doublezero-serviceability-cli.workspace = true doublezero-cli-core.workspace = true doublezero-config.workspace = true doublezero-serviceability.workspace = true @@ -49,7 +49,7 @@ doublezero-program-common.workspace = true tracing.workspace = true [features] -default-mainnet-beta = ["doublezero_sdk/default-mainnet-beta", "doublezero_cli/default-mainnet-beta"] +default-mainnet-beta = ["doublezero_sdk/default-mainnet-beta", "doublezero-serviceability-cli/default-mainnet-beta"] [dev-dependencies] assert_cmd.workspace = true diff --git a/client/doublezero/src/cli/accesspass.rs b/client/doublezero/src/cli/accesspass.rs index ed03a8ce0b..8dc90b753e 100644 --- a/client/doublezero/src/cli/accesspass.rs +++ b/client/doublezero/src/cli/accesspass.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::accesspass::{ +use doublezero_serviceability_cli::accesspass::{ close::CloseAccessPassCliCommand, fund::FundAccessPassCliCommand, get::GetAccessPassCliCommand, list::ListAccessPassCliCommand, set::SetAccessPassCliCommand, user_balances::UserBalancesAccessPassCliCommand, diff --git a/client/doublezero/src/cli/command.rs b/client/doublezero/src/cli/command.rs index 55adc07f04..d0ae55cd01 100644 --- a/client/doublezero/src/cli/command.rs +++ b/client/doublezero/src/cli/command.rs @@ -15,7 +15,7 @@ use crate::{ }; use clap::{Args, Subcommand}; use clap_complete::Shell; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ account::GetAccountCliCommand, accounts::GetAccountsCliCommand, address::AddressCliCommand, balance::BalanceCliCommand, export::ExportCliCommand, geolocation::programconfig::init::InitProgramConfigCliCommand, init::InitCliCommand, diff --git a/client/doublezero/src/cli/config.rs b/client/doublezero/src/cli/config.rs index 95736111ea..47021ded09 100644 --- a/client/doublezero/src/cli/config.rs +++ b/client/doublezero/src/cli/config.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; +use doublezero_serviceability_cli::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; #[derive(Args, Debug)] pub struct ConfigCliCommand { diff --git a/client/doublezero/src/cli/contributor.rs b/client/doublezero/src/cli/contributor.rs index 032c86feae..5254911278 100644 --- a/client/doublezero/src/cli/contributor.rs +++ b/client/doublezero/src/cli/contributor.rs @@ -1,6 +1,8 @@ use clap::{Args, Subcommand}; -use doublezero_cli::contributor::{create::*, delete::*, get::*, list::*, update::*}; +use doublezero_serviceability_cli::contributor::{ + create::*, delete::*, get::*, list::*, update::*, +}; #[derive(Args, Debug)] pub struct ContributorCliCommand { diff --git a/client/doublezero/src/cli/device.rs b/client/doublezero/src/cli/device.rs index 046ebc20d3..08921a8cc8 100644 --- a/client/doublezero/src/cli/device.rs +++ b/client/doublezero/src/cli/device.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::device::{ +use doublezero_serviceability_cli::device::{ create::CreateDeviceCliCommand, delete::DeleteDeviceCliCommand, get::GetDeviceCliCommand, diff --git a/client/doublezero/src/cli/exchange.rs b/client/doublezero/src/cli/exchange.rs index c450003947..a468a4b526 100644 --- a/client/doublezero/src/cli/exchange.rs +++ b/client/doublezero/src/cli/exchange.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::exchange::{ +use doublezero_serviceability_cli::exchange::{ create::*, delete::*, get::*, list::*, setdevice::SetDeviceExchangeCliCommand, update::*, }; diff --git a/client/doublezero/src/cli/geolocation/probe.rs b/client/doublezero/src/cli/geolocation/probe.rs index f94c51f47e..353b001982 100644 --- a/client/doublezero/src/cli/geolocation/probe.rs +++ b/client/doublezero/src/cli/geolocation/probe.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::geolocation::probe::{ +use doublezero_serviceability_cli::geolocation::probe::{ add_parent::AddParentGeoProbeCliCommand, create::CreateGeoProbeCliCommand, delete::DeleteGeoProbeCliCommand, get::GetGeoProbeCliCommand, list::ListGeoProbeCliCommand, remove_parent::RemoveParentGeoProbeCliCommand, update::UpdateGeoProbeCliCommand, diff --git a/client/doublezero/src/cli/geolocation/user.rs b/client/doublezero/src/cli/geolocation/user.rs index 751e075f1d..d4010a2bfd 100644 --- a/client/doublezero/src/cli/geolocation/user.rs +++ b/client/doublezero/src/cli/geolocation/user.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::geolocation::user::{ +use doublezero_serviceability_cli::geolocation::user::{ add_target::AddTargetCliCommand, create::CreateGeolocationUserCliCommand, delete::DeleteGeolocationUserCliCommand, get::GetGeolocationUserCliCommand, list::ListGeolocationUserCliCommand, remove_target::RemoveTargetCliCommand, diff --git a/client/doublezero/src/cli/globalconfig.rs b/client/doublezero/src/cli/globalconfig.rs index 73933c7c28..2dfb4b6aaa 100644 --- a/client/doublezero/src/cli/globalconfig.rs +++ b/client/doublezero/src/cli/globalconfig.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ allowlist::{ foundation::{ add::AddFoundationAllowlistCliCommand, list::ListFoundationAllowlistCliCommand, diff --git a/client/doublezero/src/cli/link.rs b/client/doublezero/src/cli/link.rs index 58f86086af..d67ba4f9d2 100644 --- a/client/doublezero/src/cli/link.rs +++ b/client/doublezero/src/cli/link.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ link::{ accept::AcceptLinkCliCommand, delete::*, dzx_create::CreateDZXLinkCliCommand, get::*, latency::LinkLatencyCliCommand, list::*, sethealth::SetLinkHealthCliCommand, update::*, diff --git a/client/doublezero/src/cli/location.rs b/client/doublezero/src/cli/location.rs index c497e27fa3..d14c7dd1a2 100644 --- a/client/doublezero/src/cli/location.rs +++ b/client/doublezero/src/cli/location.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::location::{create::*, delete::*, get::*, list::*, update::*}; +use doublezero_serviceability_cli::location::{create::*, delete::*, get::*, list::*, update::*}; #[derive(Args, Debug)] pub struct LocationCliCommand { diff --git a/client/doublezero/src/cli/multicastgroup.rs b/client/doublezero/src/cli/multicastgroup.rs index f216c3e997..ba135239b2 100644 --- a/client/doublezero/src/cli/multicastgroup.rs +++ b/client/doublezero/src/cli/multicastgroup.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::multicastgroup::{ +use doublezero_serviceability_cli::multicastgroup::{ allowlist::{ publisher::{ add::AddMulticastGroupPubAllowlistCliCommand, diff --git a/client/doublezero/src/cli/permission.rs b/client/doublezero/src/cli/permission.rs index e31073ca67..f773ce4580 100644 --- a/client/doublezero/src/cli/permission.rs +++ b/client/doublezero/src/cli/permission.rs @@ -1,6 +1,8 @@ use clap::{Args, Subcommand}; -use doublezero_cli::permission::{delete::*, get::*, list::*, resume::*, set::*, suspend::*}; +use doublezero_serviceability_cli::permission::{ + delete::*, get::*, list::*, resume::*, set::*, suspend::*, +}; #[derive(Args, Debug)] pub struct PermissionCliCommand { diff --git a/client/doublezero/src/cli/resource.rs b/client/doublezero/src/cli/resource.rs index cff1289f04..7fc8f679fb 100644 --- a/client/doublezero/src/cli/resource.rs +++ b/client/doublezero/src/cli/resource.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::resource::{ +use doublezero_serviceability_cli::resource::{ allocate::AllocateResourceCliCommand, close::CloseResourceCliCommand, create::CreateResourceCliCommand, deallocate::DeallocateResourceCliCommand, get::GetResourceCliCommand, verify::VerifyResourceCliCommand, diff --git a/client/doublezero/src/cli/tenant.rs b/client/doublezero/src/cli/tenant.rs index eca42d768c..627b937618 100644 --- a/client/doublezero/src/cli/tenant.rs +++ b/client/doublezero/src/cli/tenant.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::tenant::{ +use doublezero_serviceability_cli::tenant::{ add_administrator::*, create::*, delete::*, get::*, list::*, remove_administrator::*, update::*, }; diff --git a/client/doublezero/src/cli/user.rs b/client/doublezero/src/cli/user.rs index ba04bcf0bd..84394874d3 100644 --- a/client/doublezero/src/cli/user.rs +++ b/client/doublezero/src/cli/user.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::user::{ +use doublezero_serviceability_cli::user::{ create::CreateUserCliCommand, create_subscribe::CreateSubscribeUserCliCommand, delete::DeleteUserCliCommand, get::GetUserCliCommand, list::ListUserCliCommand, request_ban::RequestBanUserCliCommand, subscribe::SubscribeUserCliCommand, diff --git a/client/doublezero/src/command/connect.rs b/client/doublezero/src/command/connect.rs index 0ba609b95e..754eb9b05b 100644 --- a/client/doublezero/src/command/connect.rs +++ b/client/doublezero/src/command/connect.rs @@ -5,11 +5,6 @@ use crate::{ }; use backon::{BlockingRetryable, ExponentialBuilder}; use clap::{Args, Subcommand, ValueEnum}; -use doublezero_cli::{ - doublezerocommand::CliCommand, - helpers::init_command, - requirements::{check_accesspass, check_requirements, CHECK_BALANCE, CHECK_ID_JSON}, -}; use doublezero_sdk::{ commands::{ accesspass::get::GetAccessPassCommand, @@ -25,6 +20,11 @@ use doublezero_sdk::{ }, Device, User, UserCYOA, UserStatus, UserType, }; +use doublezero_serviceability_cli::{ + doublezerocommand::CliCommand, + helpers::init_command, + requirements::{check_accesspass, check_requirements, CHECK_BALANCE, CHECK_ID_JSON}, +}; use eyre; use indicatif::ProgressBar; use solana_sdk::pubkey::Pubkey; @@ -936,7 +936,6 @@ mod tests { DoubleZeroStatus, LatencyRecord, LatencyResponse, MockServiceController, StatusResponse, V2StatusResponse, }; - use doublezero_cli::{doublezerocommand::MockCliCommand, tests::utils::create_test_client}; use doublezero_config::Environment; use doublezero_sdk::{ commands::accesspass::get::GetAccessPassCommand, tests::utils::create_temp_config, @@ -953,6 +952,9 @@ mod tests { tenant::{Tenant, TenantBillingConfig, TenantPaymentStatus}, }, }; + use doublezero_serviceability_cli::{ + doublezerocommand::MockCliCommand, tests::utils::create_test_client, + }; use mockall::predicate; use solana_sdk::signature::Signature; use std::{ diff --git a/client/doublezero/src/command/disable.rs b/client/doublezero/src/command/disable.rs index 551f0f210b..6c7b130a50 100644 --- a/client/doublezero/src/command/disable.rs +++ b/client/doublezero/src/command/disable.rs @@ -3,7 +3,7 @@ use crate::{ servicecontroller::{ServiceController, ServiceControllerImpl}, }; use clap::Args; -use doublezero_cli::doublezerocommand::CliCommand; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; #[derive(Args, Debug)] pub struct DisableCliCommand {} @@ -44,8 +44,8 @@ impl DisableCliCommand { mod tests { use super::*; use crate::servicecontroller::{MockServiceController, V2StatusResponse}; - use doublezero_cli::tests::utils::create_test_client; use doublezero_config::Environment; + use doublezero_serviceability_cli::tests::utils::create_test_client; fn setup_mock() -> MockServiceController { let mut mock = MockServiceController::new(); @@ -64,7 +64,7 @@ mod tests { mock } - fn setup_client() -> doublezero_cli::doublezerocommand::MockCliCommand { + fn setup_client() -> doublezero_serviceability_cli::doublezerocommand::MockCliCommand { let mut client = create_test_client(); client .expect_get_environment() diff --git a/client/doublezero/src/command/disconnect.rs b/client/doublezero/src/command/disconnect.rs index ac3edadee1..c05c733bf8 100644 --- a/client/doublezero/src/command/disconnect.rs +++ b/client/doublezero/src/command/disconnect.rs @@ -9,7 +9,7 @@ use crate::{ requirements::check_doublezero, servicecontroller::{ServiceController, ServiceControllerImpl}, }; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ doublezerocommand::CliCommand, helpers::init_command, requirements::{check_requirements, CHECK_BALANCE, CHECK_ID_JSON}, @@ -469,8 +469,8 @@ mod tests { // --- delete_users tests --- - use doublezero_cli::tests::utils::create_test_client; use doublezero_sdk::{AccountType, User, UserCYOA, UserStatus}; + use doublezero_serviceability_cli::tests::utils::create_test_client; use std::collections::HashMap; fn make_test_user(client_ip: Ipv4Addr, owner: Pubkey, user_type: UserType) -> User { diff --git a/client/doublezero/src/command/enable.rs b/client/doublezero/src/command/enable.rs index 3ac4b5eccc..845ec3af3c 100644 --- a/client/doublezero/src/command/enable.rs +++ b/client/doublezero/src/command/enable.rs @@ -3,7 +3,7 @@ use crate::{ servicecontroller::{ServiceController, ServiceControllerImpl}, }; use clap::Args; -use doublezero_cli::doublezerocommand::CliCommand; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; #[derive(Args, Debug)] pub struct EnableCliCommand {} @@ -37,8 +37,8 @@ impl EnableCliCommand { mod tests { use super::*; use crate::servicecontroller::{MockServiceController, V2StatusResponse}; - use doublezero_cli::tests::utils::create_test_client; use doublezero_config::Environment; + use doublezero_serviceability_cli::tests::utils::create_test_client; fn setup_mock() -> MockServiceController { let mut mock = MockServiceController::new(); @@ -57,7 +57,7 @@ mod tests { mock } - fn setup_client() -> doublezero_cli::doublezerocommand::MockCliCommand { + fn setup_client() -> doublezero_serviceability_cli::doublezerocommand::MockCliCommand { let mut client = create_test_client(); client .expect_get_environment() diff --git a/client/doublezero/src/command/latency.rs b/client/doublezero/src/command/latency.rs index 87303cd833..07e82865be 100644 --- a/client/doublezero/src/command/latency.rs +++ b/client/doublezero/src/command/latency.rs @@ -1,7 +1,7 @@ use crate::command::util; use clap::Args; -use doublezero_cli::doublezerocommand::CliCommand; use doublezero_sdk::commands::device::list::ListDeviceCommand; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; use indicatif::{ProgressBar, ProgressStyle}; use std::time::Duration; diff --git a/client/doublezero/src/command/multicast.rs b/client/doublezero/src/command/multicast.rs index c6bba18813..7750e38b3b 100644 --- a/client/doublezero/src/command/multicast.rs +++ b/client/doublezero/src/command/multicast.rs @@ -1,6 +1,5 @@ use std::net::Ipv4Addr; -use doublezero_cli::{doublezerocommand::CliCommand, helpers::init_command}; use doublezero_sdk::{ commands::{ multicastgroup::{ @@ -10,6 +9,7 @@ use doublezero_sdk::{ }, User, UserType, }; +use doublezero_serviceability_cli::{doublezerocommand::CliCommand, helpers::init_command}; use indicatif::ProgressBar; use solana_sdk::pubkey::Pubkey; @@ -324,11 +324,11 @@ mod tests { MulticastPublishCliCommand, MulticastSubscribeCliCommand, MulticastUnpublishCliCommand, MulticastUnsubscribeCliCommand, }; - use doublezero_cli::tests::utils::create_test_client; use doublezero_sdk::{ commands::multicastgroup::subscribe::UpdateMulticastGroupRolesCommand, AccountType, MulticastGroup, MulticastGroupStatus, User, UserCYOA, UserStatus, }; + use doublezero_serviceability_cli::tests::utils::create_test_client; use std::collections::HashMap; fn make_user(client_ip: Ipv4Addr, user_type: UserType) -> User { diff --git a/client/doublezero/src/command/routes.rs b/client/doublezero/src/command/routes.rs index 2d7a73e1aa..5ae38dbade 100644 --- a/client/doublezero/src/command/routes.rs +++ b/client/doublezero/src/command/routes.rs @@ -1,7 +1,7 @@ use crate::command::util; use clap::Args; -use doublezero_cli::doublezerocommand::CliCommand; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; use crate::{ requirements::check_doublezero, routes::retrieve_routes, diff --git a/client/doublezero/src/command/status.rs b/client/doublezero/src/command/status.rs index 3e0c3b891b..c8d4980d93 100644 --- a/client/doublezero/src/command/status.rs +++ b/client/doublezero/src/command/status.rs @@ -7,7 +7,7 @@ use crate::{ }; use backon::{ExponentialBuilder, Retryable}; use clap::Args; -use doublezero_cli::{doublezerocommand::CliCommand, helpers::print_error}; +use doublezero_serviceability_cli::{doublezerocommand::CliCommand, helpers::print_error}; use serde::{Deserialize, Serialize}; use std::time::Duration; use tabled::Tabled; @@ -159,7 +159,7 @@ mod tests { use crate::servicecontroller::{ DoubleZeroStatus, MockServiceController, MulticastGroups, V2ServiceStatus, V2StatusResponse, }; - use doublezero_cli::doublezerocommand::MockCliCommand; + use doublezero_serviceability_cli::doublezerocommand::MockCliCommand; use std::sync::{ atomic::{AtomicUsize, Ordering}, Arc, diff --git a/client/doublezero/src/main.rs b/client/doublezero/src/main.rs index d0c1234434..0b6586ebfd 100644 --- a/client/doublezero/src/main.rs +++ b/client/doublezero/src/main.rs @@ -24,13 +24,13 @@ use crate::cli::{ location::LocationCommands, user::UserCommands, }; -use doublezero_cli::{ - checkversion::check_version, doublezerocommand::CliCommandImpl, - geoclicommand::GeoCliCommandImpl, version::VersionCliCommand, -}; use doublezero_cli_core::LogLevel; use doublezero_sdk::{geolocation::client::GeoClient, DZClient, ProgramVersion}; use doublezero_serviceability::pda::get_globalstate_pda; +use doublezero_serviceability_cli::{ + checkversion::check_version, doublezerocommand::CliCommandImpl, + geoclicommand::GeoCliCommandImpl, version::VersionCliCommand, +}; use servicecontroller::ServiceControllerImpl; #[derive(Parser, Debug)] diff --git a/client/doublezero/src/requirements.rs b/client/doublezero/src/requirements.rs index 2257030979..cfe5a5b2c0 100644 --- a/client/doublezero/src/requirements.rs +++ b/client/doublezero/src/requirements.rs @@ -1,5 +1,5 @@ use crate::servicecontroller::ServiceController; -use doublezero_cli::doublezerocommand::CliCommand; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; use indicatif::ProgressBar; pub async fn check_doublezero( diff --git a/controlplane/doublezero-admin/Cargo.toml b/controlplane/doublezero-admin/Cargo.toml index 961af009ad..47fe2cd9e5 100644 --- a/controlplane/doublezero-admin/Cargo.toml +++ b/controlplane/doublezero-admin/Cargo.toml @@ -40,7 +40,7 @@ tokio.workspace = true # Dependencies from this workspace doublezero_sdk.workspace = true -doublezero_cli.workspace = true +doublezero-serviceability-cli.workspace = true doublezero-config.workspace = true doublezero-serviceability.workspace = true doublezero-program-common.workspace = true diff --git a/controlplane/doublezero-admin/src/cli/accesspass.rs b/controlplane/doublezero-admin/src/cli/accesspass.rs index dddee1fab5..b18ce64afb 100644 --- a/controlplane/doublezero-admin/src/cli/accesspass.rs +++ b/controlplane/doublezero-admin/src/cli/accesspass.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::accesspass::{ +use doublezero_serviceability_cli::accesspass::{ close::CloseAccessPassCliCommand, fund::FundAccessPassCliCommand, get::GetAccessPassCliCommand, list::ListAccessPassCliCommand, set::SetAccessPassCliCommand, user_balances::UserBalancesAccessPassCliCommand, diff --git a/controlplane/doublezero-admin/src/cli/command.rs b/controlplane/doublezero-admin/src/cli/command.rs index aa84e6f51d..2fe1b6a0c5 100644 --- a/controlplane/doublezero-admin/src/cli/command.rs +++ b/controlplane/doublezero-admin/src/cli/command.rs @@ -7,7 +7,7 @@ use crate::cli::{ }; use clap::{Args, Subcommand}; use clap_complete::Shell; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ account::GetAccountCliCommand, accounts::GetAccountsCliCommand, address::AddressCliCommand, balance::BalanceCliCommand, export::ExportCliCommand, init::InitCliCommand, keygen::KeyGenCliCommand, logcommand::LogCliCommand, diff --git a/controlplane/doublezero-admin/src/cli/config.rs b/controlplane/doublezero-admin/src/cli/config.rs index 95736111ea..47021ded09 100644 --- a/controlplane/doublezero-admin/src/cli/config.rs +++ b/controlplane/doublezero-admin/src/cli/config.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; +use doublezero_serviceability_cli::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; #[derive(Args, Debug)] pub struct ConfigCliCommand { diff --git a/controlplane/doublezero-admin/src/cli/contributor.rs b/controlplane/doublezero-admin/src/cli/contributor.rs index 032c86feae..5254911278 100644 --- a/controlplane/doublezero-admin/src/cli/contributor.rs +++ b/controlplane/doublezero-admin/src/cli/contributor.rs @@ -1,6 +1,8 @@ use clap::{Args, Subcommand}; -use doublezero_cli::contributor::{create::*, delete::*, get::*, list::*, update::*}; +use doublezero_serviceability_cli::contributor::{ + create::*, delete::*, get::*, list::*, update::*, +}; #[derive(Args, Debug)] pub struct ContributorCliCommand { diff --git a/controlplane/doublezero-admin/src/cli/device.rs b/controlplane/doublezero-admin/src/cli/device.rs index 570210bc3b..2902e18b13 100644 --- a/controlplane/doublezero-admin/src/cli/device.rs +++ b/controlplane/doublezero-admin/src/cli/device.rs @@ -1,5 +1,12 @@ use clap::{Args, Subcommand}; -use doublezero_cli::{ +use doublezero_sdk::{ + commands::{ + device::{list::ListDeviceCommand, update::UpdateDeviceCommand}, + user::list::ListUserCommand, + }, + UserStatus, UserType, +}; +use doublezero_serviceability_cli::{ device::{ create::CreateDeviceCliCommand, delete::DeleteDeviceCliCommand, @@ -14,13 +21,6 @@ use doublezero_cli::{ }, doublezerocommand::CliCommand, }; -use doublezero_sdk::{ - commands::{ - device::{list::ListDeviceCommand, update::UpdateDeviceCommand}, - user::list::ListUserCommand, - }, - UserStatus, UserType, -}; use solana_sdk::pubkey::Pubkey; use std::{collections::HashMap, io::Write}; @@ -280,9 +280,9 @@ impl MigrateUnicastCountsCommand { #[cfg(test)] mod tests { use super::*; - use doublezero_cli::tests::utils::create_test_client; use doublezero_sdk::{Device, DeviceStatus, DeviceType, User, UserCYOA, UserStatus, UserType}; use doublezero_serviceability::state::device::{DeviceDesiredStatus, DeviceHealth}; + use doublezero_serviceability_cli::tests::utils::create_test_client; use solana_sdk::{pubkey::Pubkey, signature::Signature}; use std::collections::HashMap; diff --git a/controlplane/doublezero-admin/src/cli/exchange.rs b/controlplane/doublezero-admin/src/cli/exchange.rs index c450003947..a468a4b526 100644 --- a/controlplane/doublezero-admin/src/cli/exchange.rs +++ b/controlplane/doublezero-admin/src/cli/exchange.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::exchange::{ +use doublezero_serviceability_cli::exchange::{ create::*, delete::*, get::*, list::*, setdevice::SetDeviceExchangeCliCommand, update::*, }; diff --git a/controlplane/doublezero-admin/src/cli/globalconfig.rs b/controlplane/doublezero-admin/src/cli/globalconfig.rs index e55d2c8e08..e97e1fbaf7 100644 --- a/controlplane/doublezero-admin/src/cli/globalconfig.rs +++ b/controlplane/doublezero-admin/src/cli/globalconfig.rs @@ -1,5 +1,5 @@ use clap::{Args, Subcommand}; -use doublezero_cli::{ +use doublezero_serviceability_cli::{ allowlist::foundation::{ add::AddFoundationAllowlistCliCommand, list::ListFoundationAllowlistCliCommand, remove::RemoveFoundationAllowlistCliCommand, diff --git a/controlplane/doublezero-admin/src/cli/link.rs b/controlplane/doublezero-admin/src/cli/link.rs index cf0808e079..f38dd27f0b 100644 --- a/controlplane/doublezero-admin/src/cli/link.rs +++ b/controlplane/doublezero-admin/src/cli/link.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::link::{ +use doublezero_serviceability_cli::link::{ accept::AcceptLinkCliCommand, delete::*, dzx_create::CreateDZXLinkCliCommand, get::*, list::*, update::*, wan_create::*, }; diff --git a/controlplane/doublezero-admin/src/cli/location.rs b/controlplane/doublezero-admin/src/cli/location.rs index c497e27fa3..d14c7dd1a2 100644 --- a/controlplane/doublezero-admin/src/cli/location.rs +++ b/controlplane/doublezero-admin/src/cli/location.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::location::{create::*, delete::*, get::*, list::*, update::*}; +use doublezero_serviceability_cli::location::{create::*, delete::*, get::*, list::*, update::*}; #[derive(Args, Debug)] pub struct LocationCliCommand { diff --git a/controlplane/doublezero-admin/src/cli/migrate.rs b/controlplane/doublezero-admin/src/cli/migrate.rs index b8f5e993b9..8404139d28 100644 --- a/controlplane/doublezero-admin/src/cli/migrate.rs +++ b/controlplane/doublezero-admin/src/cli/migrate.rs @@ -1,5 +1,4 @@ use clap::{Args, Subcommand}; -use doublezero_cli::doublezerocommand::CliCommand; use doublezero_sdk::commands::{ device::list::ListDeviceCommand, link::{list::ListLinkCommand, update::UpdateLinkCommand}, @@ -8,6 +7,7 @@ use doublezero_sdk::commands::{ }, }; use doublezero_serviceability::{pda::get_topology_pda, state::interface::LoopbackType}; +use doublezero_serviceability_cli::doublezerocommand::CliCommand; use solana_sdk::pubkey::Pubkey; use std::io::Write; diff --git a/controlplane/doublezero-admin/src/cli/multicastgroup.rs b/controlplane/doublezero-admin/src/cli/multicastgroup.rs index f216c3e997..ba135239b2 100644 --- a/controlplane/doublezero-admin/src/cli/multicastgroup.rs +++ b/controlplane/doublezero-admin/src/cli/multicastgroup.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::multicastgroup::{ +use doublezero_serviceability_cli::multicastgroup::{ allowlist::{ publisher::{ add::AddMulticastGroupPubAllowlistCliCommand, diff --git a/controlplane/doublezero-admin/src/cli/permission.rs b/controlplane/doublezero-admin/src/cli/permission.rs index e31073ca67..f773ce4580 100644 --- a/controlplane/doublezero-admin/src/cli/permission.rs +++ b/controlplane/doublezero-admin/src/cli/permission.rs @@ -1,6 +1,8 @@ use clap::{Args, Subcommand}; -use doublezero_cli::permission::{delete::*, get::*, list::*, resume::*, set::*, suspend::*}; +use doublezero_serviceability_cli::permission::{ + delete::*, get::*, list::*, resume::*, set::*, suspend::*, +}; #[derive(Args, Debug)] pub struct PermissionCliCommand { diff --git a/controlplane/doublezero-admin/src/cli/tenant.rs b/controlplane/doublezero-admin/src/cli/tenant.rs index 1d9e6441e9..056d61c6f5 100644 --- a/controlplane/doublezero-admin/src/cli/tenant.rs +++ b/controlplane/doublezero-admin/src/cli/tenant.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::tenant::{ +use doublezero_serviceability_cli::tenant::{ add_administrator::*, create::*, delete::*, get::*, list::*, remove_administrator::*, update::*, }; diff --git a/controlplane/doublezero-admin/src/cli/user.rs b/controlplane/doublezero-admin/src/cli/user.rs index ba04bcf0bd..84394874d3 100644 --- a/controlplane/doublezero-admin/src/cli/user.rs +++ b/controlplane/doublezero-admin/src/cli/user.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_cli::user::{ +use doublezero_serviceability_cli::user::{ create::CreateUserCliCommand, create_subscribe::CreateSubscribeUserCliCommand, delete::DeleteUserCliCommand, get::GetUserCliCommand, list::ListUserCliCommand, request_ban::RequestBanUserCliCommand, subscribe::SubscribeUserCliCommand, diff --git a/controlplane/doublezero-admin/src/main.rs b/controlplane/doublezero-admin/src/main.rs index 253ee4b0ce..661f1feda0 100644 --- a/controlplane/doublezero-admin/src/main.rs +++ b/controlplane/doublezero-admin/src/main.rs @@ -17,8 +17,8 @@ use crate::cli::{ tenant::TenantCommands, user::UserCommands, }; -use doublezero_cli::doublezerocommand::CliCommandImpl; use doublezero_sdk::DZClient; +use doublezero_serviceability_cli::doublezerocommand::CliCommandImpl; #[derive(Parser, Debug)] #[command(term_width = 0)] diff --git a/smartcontract/cli/Cargo.toml b/smartcontract/cli/Cargo.toml index ce8265b4ad..ffd97e4316 100644 --- a/smartcontract/cli/Cargo.toml +++ b/smartcontract/cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "doublezero_cli" +name = "doublezero-serviceability-cli" # Workspace inherited keys version.workspace = true @@ -10,7 +10,7 @@ license.workspace = true repository.workspace = true [lib] -name = "doublezero_cli" +name = "doublezero_serviceability_cli" [dependencies] anyhow.workspace = true From 82adaf796f5bb8860d892e9eab453739a20bcfff Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Fri, 22 May 2026 10:58:19 +0000 Subject: [PATCH 2/6] cli/serviceability: rewrite location get to rfc-20 conforming pattern --- CHANGELOG.md | 1 + Cargo.lock | 2 + client/doublezero/src/main.rs | 2 +- controlplane/doublezero-admin/Cargo.toml | 1 + controlplane/doublezero-admin/src/main.rs | 9 ++- smartcontract/cli/Cargo.toml | 1 + smartcontract/cli/src/location/get.rs | 77 +++++++++++++++++------ 7 files changed, 73 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fd61cb921..025450887e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. - Build a `CliContext` once at binary startup from `--env`, the per-field global overrides (`--url`, `--ws`, `--solana-url`, `--program-id`, `--geo-program-id`, `--keypair`, `--sock-file`), and the persisted `~/.config/doublezero/cli/config.yml` (overridable via `DOUBLEZERO_CONFIG_FILE`), per RFC-20 (§CliContext). Precedence (highest wins): CLI flag > persisted config > env-derived default. When `--env` is not set and the persisted config has a serviceability program ID, the environment is derived from that program ID via `Environment::from_program_id`; otherwise the binary falls back to `Environment::default()`. The legacy `DZClient` is now constructed from the fully resolved `CliContext` URL, WebSocket, and program-ID values directly, so verbs that migrate to read `CliContext` see the same backend as the legacy bridge. Keypair resolution is intentionally left to `DZClient::new`'s internal `load_keypair` precedence (CLI `--keypair` flag > `DOUBLEZERO_KEYPAIR` env var > stdin > persisted config) so the `DOUBLEZERO_KEYPAIR` env var continues to override the persisted keypair path, as relied on by the e2e contributor-auth negative-authz suite. File reads happen only in the binary; module crates remain forbidden from touching the filesystem (RFC-20 §67). - Centralize top-level error rendering through `doublezero_cli_core::error::render_eyre`. Replaces three ad-hoc `eprintln!("Error: {e}")` sites in `client/doublezero/src/main.rs` (env-parse failure, env-config resolution failure, top-level command failure) with a single helper that prints `Error: ` followed by the full chain of causes on stderr. - Rename the `smartcontract/cli/` crate from `doublezero_cli` to `doublezero-serviceability-cli` to satisfy RFC-20's module-crate naming contract (`doublezero--cli` in kebab-case). The crate stays at `smartcontract/cli/`; only the `[package].name` and `[lib].name` change (lib name is `doublezero_serviceability_cli` because Rust requires underscores in import paths). All in-tree consumers are updated: `client/doublezero`, `client/doublezero-geolocation-cli`, `controlplane/doublezero-admin`, and the workspace `Cargo.toml`. External operators who depend on the workspace crate by its old name (`doublezero_cli`) must update their `Cargo.toml` and `use` statements. No user-facing command, flag, or output change. + - Migrate `location get` to the RFC-20 conforming verb pattern as the project's reference. `GetLocationCliCommand::execute` is now `async fn`, takes `&CliContext` as its first non-self argument, and emits a `tracing::debug!` event so `-v` surfaces what the verb is doing. The verb's user-facing args, flags, table layout, and JSON schema are unchanged. The unit test consumes the shared `doublezero_cli_core::testing::cli_context_default_for_tests()` helper and continues to use the existing `MockCliCommand` (auto-generated by `#[automock]`) as the backend. Binary dispatch arms in `client/doublezero` and `controlplane/doublezero-admin` are updated to `.await` the new method; other location verbs (Create, Update, List, Delete) keep their current sync signatures and migrate opportunistically. ## [v0.24.0](https://github.com/malbeclabs/doublezero/compare/client/v0.23.0...client/v0.24.0) - 2026-05-22 diff --git a/Cargo.lock b/Cargo.lock index 81c37b74e8..b158ec2bbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1520,6 +1520,7 @@ dependencies = [ "clap", "clap_complete", "console", + "doublezero-cli-core", "doublezero-config", "doublezero-program-common", "doublezero-sentinel", @@ -1729,6 +1730,7 @@ dependencies = [ "temp-env", "tempfile", "tokio", + "tracing", ] [[package]] diff --git a/client/doublezero/src/main.rs b/client/doublezero/src/main.rs index 0b6586ebfd..ba63dfd3ec 100644 --- a/client/doublezero/src/main.rs +++ b/client/doublezero/src/main.rs @@ -320,7 +320,7 @@ async fn main() -> eyre::Result<()> { LocationCommands::Create(args) => args.execute(&client, &mut handle), LocationCommands::Update(args) => args.execute(&client, &mut handle), LocationCommands::List(args) => args.execute(&client, &mut handle), - LocationCommands::Get(args) => args.execute(&client, &mut handle), + LocationCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await, LocationCommands::Delete(args) => args.execute(&client, &mut handle), }, Command::Exchange(command) => match command.command { diff --git a/controlplane/doublezero-admin/Cargo.toml b/controlplane/doublezero-admin/Cargo.toml index 47fe2cd9e5..4e5796578d 100644 --- a/controlplane/doublezero-admin/Cargo.toml +++ b/controlplane/doublezero-admin/Cargo.toml @@ -41,6 +41,7 @@ tokio.workspace = true # Dependencies from this workspace doublezero_sdk.workspace = true doublezero-serviceability-cli.workspace = true +doublezero-cli-core.workspace = true doublezero-config.workspace = true doublezero-serviceability.workspace = true doublezero-program-common.workspace = true diff --git a/controlplane/doublezero-admin/src/main.rs b/controlplane/doublezero-admin/src/main.rs index 661f1feda0..4af44d8126 100644 --- a/controlplane/doublezero-admin/src/main.rs +++ b/controlplane/doublezero-admin/src/main.rs @@ -57,6 +57,10 @@ async fn main() -> eyre::Result<()> { println!("using keypair: {}", keypair.display()); } + let env_for_ctx = match app.env.as_deref() { + Some(s) => s.parse::()?, + None => Environment::default(), + }; let (url, ws, program_id) = if let Some(env) = app.env { let config = env.parse::()?.config()?; ( @@ -70,6 +74,9 @@ async fn main() -> eyre::Result<()> { let dzclient = DZClient::new(url, ws, program_id, app.keypair)?; let client = CliCommandImpl::new(&dzclient); + let ctx = doublezero_cli_core::CliContextBuilder::new() + .with_env(env_for_ctx) + .build()?; let stdout = std::io::stdout(); let mut handle = stdout.lock(); @@ -107,7 +114,7 @@ async fn main() -> eyre::Result<()> { LocationCommands::Create(args) => args.execute(&client, &mut handle), LocationCommands::Update(args) => args.execute(&client, &mut handle), LocationCommands::List(args) => args.execute(&client, &mut handle), - LocationCommands::Get(args) => args.execute(&client, &mut handle), + LocationCommands::Get(args) => args.execute(&ctx, &client, &mut handle).await, LocationCommands::Delete(args) => args.execute(&client, &mut handle), }, Command::Exchange(command) => match command.command { diff --git a/smartcontract/cli/Cargo.toml b/smartcontract/cli/Cargo.toml index ffd97e4316..714f31b1f5 100644 --- a/smartcontract/cli/Cargo.toml +++ b/smartcontract/cli/Cargo.toml @@ -34,6 +34,7 @@ solana-rpc-client-api.workspace = true solana-sdk.workspace = true tabled.workspace = true tokio.workspace = true +tracing.workspace = true # Dependencies from this workspace doublezero-cli-core.workspace = true diff --git a/smartcontract/cli/src/location/get.rs b/smartcontract/cli/src/location/get.rs index da05637323..baab7d8ca8 100644 --- a/smartcontract/cli/src/location/get.rs +++ b/smartcontract/cli/src/location/get.rs @@ -1,10 +1,21 @@ -use crate::{doublezerocommand::CliCommand, validators::validate_pubkey_or_code}; use clap::Args; +use doublezero_cli_core::CliContext; use doublezero_sdk::commands::location::get::GetLocationCommand; use serde::Serialize; use std::io::Write; use tabled::Tabled; +use crate::{doublezerocommand::CliCommand, validators::validate_pubkey_or_code}; + +/// Reference RFC-20 conforming verb. See `docs/cli-standard.md` and RFC-20 +/// (`rfcs/rfc20-cli-standardization.md`) for the contract: +/// +/// - args type colocated with the verb +/// - `async fn execute(self, ctx, client, out) -> Result<()>` +/// - shared `validate_pubkey_or_code` validator on the identifier flag +/// - all output flows through the writer +/// - typed structured output (`LocationDisplay`) so JSON output is a stable +/// schema #[derive(Args, Debug)] pub struct GetLocationCliCommand { /// Location Pubkey or code to get details for @@ -30,7 +41,18 @@ struct LocationDisplay { } impl GetLocationCliCommand { - pub fn execute(self, client: &C, out: &mut W) -> eyre::Result<()> { + /// RFC-20 §Module contract item 3: `async fn` taking `&CliContext` and a + /// reference to the module's typed backend client (`CliCommand` here, the + /// existing serviceability-module trait). Returns a fallible result; the + /// binary catches the top-level error and renders the chain of causes. + pub async fn execute( + self, + ctx: &CliContext, + client: &C, + out: &mut W, + ) -> eyre::Result<()> { + tracing::debug!(env = %ctx.env, code = %self.code, "location get"); + let (pubkey, location) = client.get_location(GetLocationCommand { pubkey_or_code: self.code, })?; @@ -66,11 +88,22 @@ impl GetLocationCliCommand { #[cfg(test)] mod tests { - use crate::{location::get::GetLocationCliCommand, tests::utils::create_test_client}; + use doublezero_cli_core::testing::cli_context_default_for_tests; use doublezero_sdk::{AccountType, GetLocationCommand, Location, LocationStatus}; use mockall::predicate; use solana_sdk::pubkey::Pubkey; use std::{collections::HashMap, str::FromStr}; + use tokio::runtime::Builder; + + use crate::{location::get::GetLocationCliCommand, tests::utils::create_test_client}; + + fn block_on(f: F) -> F::Output { + Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(f) + } #[test] fn test_cli_location_get() { @@ -117,22 +150,28 @@ mod tests { Ok(list) }); + let ctx = cli_context_default_for_tests(); + // Expected failure let mut output = Vec::new(); - let res = GetLocationCliCommand { - code: Pubkey::new_unique().to_string(), - json: false, - } - .execute(&client, &mut output); + let res = block_on( + GetLocationCliCommand { + code: Pubkey::new_unique().to_string(), + json: false, + } + .execute(&ctx, &client, &mut output), + ); assert!(res.is_err(), "I shouldn't find anything."); // Expected success by pubkey (table) let mut output = Vec::new(); - let res = GetLocationCliCommand { - code: location1_pubkey.to_string(), - json: false, - } - .execute(&client, &mut output); + let res = block_on( + GetLocationCliCommand { + code: location1_pubkey.to_string(), + json: false, + } + .execute(&ctx, &client, &mut output), + ); assert!(res.is_ok(), "I should find a item by pubkey"); let output_str = String::from_utf8(output).unwrap(); let has_row = |header: &str, value: &str| { @@ -152,11 +191,13 @@ mod tests { // Expected success by code (JSON) let mut output = Vec::new(); - let res = GetLocationCliCommand { - code: "test".to_string(), - json: true, - } - .execute(&client, &mut output); + let res = block_on( + GetLocationCliCommand { + code: "test".to_string(), + json: true, + } + .execute(&ctx, &client, &mut output), + ); assert!(res.is_ok(), "I should find a item by code"); let json: serde_json::Value = serde_json::from_str(&String::from_utf8(output).unwrap()).unwrap(); From bfc148514bf380e912720c1df50a05796dc10261 Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Fri, 22 May 2026 10:59:04 +0000 Subject: [PATCH 3/6] docs/cli: add cli-standard.md and CLAUDE.md pointer --- CHANGELOG.md | 2 + CLAUDE.md | 7 ++ docs/cli-standard.md | 244 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 253 insertions(+) create mode 100644 docs/cli-standard.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 025450887e..8e2e268f67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ All notable changes to this project will be documented in this file. - Centralize top-level error rendering through `doublezero_cli_core::error::render_eyre`. Replaces three ad-hoc `eprintln!("Error: {e}")` sites in `client/doublezero/src/main.rs` (env-parse failure, env-config resolution failure, top-level command failure) with a single helper that prints `Error: ` followed by the full chain of causes on stderr. - Rename the `smartcontract/cli/` crate from `doublezero_cli` to `doublezero-serviceability-cli` to satisfy RFC-20's module-crate naming contract (`doublezero--cli` in kebab-case). The crate stays at `smartcontract/cli/`; only the `[package].name` and `[lib].name` change (lib name is `doublezero_serviceability_cli` because Rust requires underscores in import paths). All in-tree consumers are updated: `client/doublezero`, `client/doublezero-geolocation-cli`, `controlplane/doublezero-admin`, and the workspace `Cargo.toml`. External operators who depend on the workspace crate by its old name (`doublezero_cli`) must update their `Cargo.toml` and `use` statements. No user-facing command, flag, or output change. - Migrate `location get` to the RFC-20 conforming verb pattern as the project's reference. `GetLocationCliCommand::execute` is now `async fn`, takes `&CliContext` as its first non-self argument, and emits a `tracing::debug!` event so `-v` surfaces what the verb is doing. The verb's user-facing args, flags, table layout, and JSON schema are unchanged. The unit test consumes the shared `doublezero_cli_core::testing::cli_context_default_for_tests()` helper and continues to use the existing `MockCliCommand` (auto-generated by `#[automock]`) as the backend. Binary dispatch arms in `client/doublezero` and `controlplane/doublezero-admin` are updated to `.await` the new method; other location verbs (Create, Update, List, Delete) keep their current sync signatures and migrate opportunistically. + - Add `docs/cli-standard.md`, the contributor-facing summary of RFC-20 with the `location get` worked example and pointers to the shared validators, formatters, logging facade, and test helpers in `doublezero-cli-core`. + - Update `CLAUDE.md` with a CLI-standard section pointing at RFC-20, the contributor doc, and the reference verb so future contributors land on the standard quickly. ## [v0.24.0](https://github.com/malbeclabs/doublezero/compare/client/v0.23.0...client/v0.24.0) - 2026-05-22 diff --git a/CLAUDE.md b/CLAUDE.md index 8e70d35363..1ab9e77c90 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -100,6 +100,13 @@ make generate-fixtures # Regenerate .bin/.json fixtures from Rust - When asked if a doc is up to date, evaluate it against its intended purpose and scope — not against whatever was most recently worked on. Implementation bug fixes and edge-case handling are not design decisions. Don't inflate docs with implementation details just because they're fresh in context. +## CLI Standard (RFC-20) + +- New CLI verbs and module crates follow RFC-20 (`rfcs/rfc20-cli-standardization.md`). A contributor-facing summary lives at `docs/cli-standard.md`, with `smartcontract/cli/src/location/get.rs` as the reference verb. +- Shared CLI utilities (`CliContext`, validators, formatters, `RequirementCheck`, `init_logging`) live in `crates/doublezero-cli-core/`. Verbs MUST consume the shared validators and route diagnostic output through `tracing`. The `doublezero` binary owns global flags (`--env`, `--url`, `--ws`, `--solana-url`, `--keypair`, `--program-id`, `--geo-program-id`, `--sock-file`, `--verbose`, `--version`); modules MUST NOT redeclare them. +- The serviceability module crate is named `doublezero-serviceability-cli` (crate path `smartcontract/cli/`, import path `doublezero_serviceability_cli`). +- Migration is opportunistic. Existing verbs are grandfathered; new verbs conform from day one. + ## Style & Terminology - Use "onchain" (one word, no hyphen), never "on-chain" diff --git a/docs/cli-standard.md b/docs/cli-standard.md new file mode 100644 index 0000000000..43ab04c2eb --- /dev/null +++ b/docs/cli-standard.md @@ -0,0 +1,244 @@ +# DoubleZero CLI Standard (RFC-20) + +This document is a contributor-facing summary of the CLI standard defined by +[RFC-20: CLI Standardization and Library Composition](../rfcs/rfc20-cli-standardization.md). +The RFC is the normative source; this page is the day-to-day reference for +writing a new verb or migrating an existing one. + +## The shape + +DoubleZero ships a single `doublezero` binary. The binary is thin: it parses +global flags, builds a `CliContext`, then dispatches to verbs that live in +**module crates**. Each module crate is a library named +`doublezero--cli` and conforms to a fixed contract. + +``` +doublezero (binary) client/doublezero/ + └─ CliContext + dispatch +doublezero-cli-core (shared library) crates/doublezero-cli-core/ + ├─ CliContext, CliContextBuilder, OutputFormat + ├─ RequirementCheck (preflight bitflags) + ├─ shared validators (pubkey, code, bandwidth, latency, ...) + ├─ display formatters + ├─ init_logging (tracing facade) + └─ testing helpers +doublezero-serviceability-cli (module) smartcontract/cli/ +doublezero--cli ... +``` + +The core crate stays small on purpose: it depends on `clap`, the logging +facade, `doublezero-config`, and `doublezero-program-common`. The Solana +SDK, daemon HTTP stack, and remote-service transports live with the module +crates that use them. + +## The module contract + +A CLI module crate **MUST**: + +1. Be a library-only crate named `doublezero--cli`. No `[[bin]]`. +2. Export at least one top-level subcommand type that derives clap's + `Subcommand`. Verbs are variants. +3. Provide an `async fn execute` on each subcommand type. The runtime lives + in the binary; modules MUST NOT call `block_on` or hide async work behind + a sync facade. +4. Define per-verb args and display types **colocated** with the verb. +5. Consume `CliContext` for environment-derived inputs. Modules MUST NOT + read environment variables, configuration files, or `argv` directly. +6. Use the shared validators (`validate_pubkey`, `validate_pubkey_or_code`, + `validate_code`, `validate_parse_bandwidth`, ...) from + `doublezero_cli_core::validators` wherever those types appear. +7. Send all output through the writer. `println!`, `eprintln!`, and + `print!` MUST NOT appear in execute paths. Diagnostic logging goes + through `tracing` (stderr). + +A module **SHOULD** keep each verb in a single file, expose its backend +client(s) behind a mockable trait, and provide per-verb unit tests against a +mocked client. + +## Argument conventions + +- Named flags only. No positional arguments. +- Long names in kebab-case. +- Short aliases on booleans only. +- Identifiers that reference an onchain entity use `validate_pubkey_or_code` + and accept either a pubkey or the entity's code. The literal `"me"` + resolves to the current payer. +- Repeatable inputs use one flag per value (`--add a --add b`), not comma + lists. +- No env-var reads at the verb level. Anything an operator might set in + their environment is parsed at the binary's global-flag layer and + surfaced through `CliContext`. + +## Output conventions + +- Default output is a table. +- Every `get`, `list`, and read command MUST expose `--json`. The display + type MUST be `Serialize`. Pubkey fields use the shared stable + serializer. +- Commands MAY additionally expose `--json-compact` for single-line JSON. + The flag name is fixed. +- Mutating commands print the transaction signature and post-confirmation + status; they MAY accept `-w` / `--wait` to poll for activation. +- All user-facing output flows through the writer passed to `execute`. + +## Global flags + +The binary owns these globals; modules MUST NOT redeclare them: + +| Flag | Purpose | +| ---- | ------- | +| `--env` | Primary config knob; selects deployment and resolves URLs, program IDs, and default service endpoints. | +| `--url` | DZ ledger RPC URL override (does NOT affect Solana L1). | +| `--ws` | DZ ledger WebSocket URL override. | +| `--solana-url` | Solana L1 RPC URL override (does NOT affect DZ ledger). | +| `--keypair` | Path to signer keypair file. | +| `--program-id` | Serviceability program ID override. | +| `--geo-program-id` | Geolocation program ID override. | +| `--sock-file` | Daemon Unix socket path override. | +| `--no-version-warning` | Suppress version-check banner. | +| `--verbose`, `-v` | Diagnostic logging at debug (`-v`) or trace (`-vv`). | +| `--version`, `-V` | Print version and exit. | + +`--env` resolves through `doublezero-config`. Recognized values are +`mainnet-beta`/`m`, `testnet`/`t`, `devnet`/`d`, `local`/`l`. + +## Diagnostic logging + +Diagnostic output goes to **stderr** via `tracing`. Modules use the +standard log macros (`debug!`, `info!`, `warn!`, `error!`, `trace!`) for +anything that explains what a verb is doing internally: backend requests, +retries, pubkey-or-code resolution, polling progress. + +```rust +tracing::debug!(env = %ctx.env, code = %self.code, "location get"); +``` + +Modules MUST NOT call `init_subscriber` themselves; the binary calls +`doublezero_cli_core::init_logging(verbosity)` once at startup. The +`RUST_LOG` env var overrides verbosity for per-module filtering. + +JSON output on stdout stays parseable at every verbosity level because logs +go to stderr. + +## Reference verb: `location get` + +`smartcontract/cli/src/location/get.rs` is the worked example. It demonstrates +the conforming pattern end to end: + +```rust +use clap::Args; +use doublezero_cli_core::CliContext; +use doublezero_sdk::commands::location::get::GetLocationCommand; +use serde::Serialize; +use std::io::Write; +use tabled::Tabled; + +use crate::{doublezerocommand::CliCommand, validators::validate_pubkey_or_code}; + +#[derive(Args, Debug)] +pub struct GetLocationCliCommand { + /// Location Pubkey or code to get details for + #[arg(long, value_parser = validate_pubkey_or_code)] + pub code: String, + /// Output as JSON + #[arg(long)] + pub json: bool, +} + +#[derive(Tabled, Serialize)] +struct LocationDisplay { /* ... */ } + +impl GetLocationCliCommand { + pub async fn execute( + self, + ctx: &CliContext, + client: &C, + out: &mut W, + ) -> eyre::Result<()> { + tracing::debug!(env = %ctx.env, code = %self.code, "location get"); + + let (pubkey, location) = client.get_location(GetLocationCommand { + pubkey_or_code: self.code, + })?; + + let display = LocationDisplay { /* ... */ }; + if self.json { + writeln!(out, "{}", serde_json::to_string_pretty(&display)?)?; + } else { + // render table via Tabled + } + Ok(()) + } +} +``` + +Unit test (excerpt): + +```rust +use doublezero_cli_core::testing::cli_context_default_for_tests; + +let ctx = cli_context_default_for_tests(); +let mut output = Vec::new(); +let res = block_on( + GetLocationCliCommand { code: "test".into(), json: true } + .execute(&ctx, &client, &mut output), +); +assert!(res.is_ok()); +``` + +The test uses `MockCliCommand` (auto-generated by `#[automock]` on the +`CliCommand` trait) as the backend, and the shared +`cli_context_default_for_tests()` helper from +`doublezero_cli_core::testing` to build a `CliContext` with sensible +defaults. + +## Preflight checks + +Verbs MAY call `RequirementCheck` to gate on common preconditions: + +```rust +use doublezero_cli_core::RequirementCheck; + +let checks = RequirementCheck::KEYPAIR | RequirementCheck::BALANCE; +``` + +The bitflags align with the legacy `CHECK_ID_JSON | CHECK_BALANCE | +CHECK_FOUNDATION_ALLOWLIST` `u8` constants in +`smartcontract/cli/src/requirements.rs`: + +| Flag | Bit | +| ---- | --- | +| `RequirementCheck::KEYPAIR` | `0b001` | +| `RequirementCheck::BALANCE` | `0b010` | +| `RequirementCheck::FOUNDATION_ALLOWLIST` | `0b100` | + +The actual `check_requirements` function lives with the module that owns +the typed backend client (today, `smartcontract/cli/src/requirements.rs`). +The bitflag type is shared so future modules consume the same canonical +set. + +## Authorization + +Authorization is **onchain**. The CLI is a thin client. The program +rejects unauthorized signers; the CLI surfaces the error. Modules MUST NOT +gate verbs by inspecting the caller's identity. + +## Migration is opportunistic + +RFC-20 explicitly grandfathers existing CLI surfaces. Existing verbs keep +their current shape until they are touched for unrelated work. New verbs +MUST conform from day one. When you touch a legacy verb, prefer to +migrate it to the conforming pattern; if migration would balloon the +change, leave it for a follow-up and note it in the PR description. + +## Open follow-ups + +Tracked in RFC-20 §Open Questions and in this work's plan: + +- Serviceability `Command` enum lives in the binary today; future PR moves + it into `smartcontract/cli` with `#[command(flatten)]` mounting. +- Geolocation module crate (defer per current scope). +- Daemon-control verbs (Connect, Status, Enable, Disable, Latency, Routes) + become their own module crate. +- JSON schema versioning once `--json` is a stable contract. +- Shell-completion install location. From ba06a094521afcb4e29e28943bcd91d50e0c64b8 Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Sun, 24 May 2026 15:07:26 +0000 Subject: [PATCH 4/6] docs/cli: clarify "me" resolution is verb-level, not validator-level --- crates/doublezero-cli-core/src/validators.rs | 16 ++++++++++++---- docs/cli-standard.md | 10 +++++++--- rfcs/rfc20-cli-standardization.md | 6 +++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/crates/doublezero-cli-core/src/validators.rs b/crates/doublezero-cli-core/src/validators.rs index 6a9018906b..86d19bf039 100644 --- a/crates/doublezero-cli-core/src/validators.rs +++ b/crates/doublezero-cli-core/src/validators.rs @@ -1,11 +1,19 @@ //! Shared `clap` value-parser validators. //! -//! Per RFC-20 (§Argument conventions): "Identifiers accept both pubkey and +//! Per RFC-20 (§Argument conventions): identifiers accept both pubkey and //! code. Any flag that references an onchain entity MUST accept either a //! Solana pubkey or the entity's human-readable code via the shared -//! validator. The magic value `\"me\"` resolves to the current payer's pubkey -//! at execution time." Module crates re-export and consume these helpers -//! rather than re-implementing them. +//! validator. Module crates re-export and consume these helpers rather than +//! re-implementing them. +//! +//! Resolution of the literal `"me"` to the current payer's pubkey is a +//! verb-level responsibility, performed in the verb's `execute` path using +//! the payer pubkey from `CliContext`. The validators here only enforce +//! grammar; they do not perform runtime resolution. `validate_pubkey` +//! short-circuits `"me"` because pubkey-only fields have no code fallback; +//! `validate_pubkey_or_code` admits `"me"` as a syntactically valid code, +//! and verbs that opt in to payer resolution check for the literal +//! themselves. use doublezero_program_common::{types::parse_utils::bandwidth_parse, validate_account_code}; use solana_sdk::pubkey::Pubkey; diff --git a/docs/cli-standard.md b/docs/cli-standard.md index 43ab04c2eb..76801726a0 100644 --- a/docs/cli-standard.md +++ b/docs/cli-standard.md @@ -61,8 +61,12 @@ mocked client. - Long names in kebab-case. - Short aliases on booleans only. - Identifiers that reference an onchain entity use `validate_pubkey_or_code` - and accept either a pubkey or the entity's code. The literal `"me"` - resolves to the current payer. + and accept either a pubkey or the entity's code. Where a flag denotes a + signer or payer-scoped entity (for example `--administrator`, + `--user-payer`, `--contributor`), the verb MAY also accept the literal + `"me"` and resolve it to the current payer's pubkey at execution time. + `"me"` resolution is a verb-level responsibility, not a validator + behavior; verbs that do not opt in will treat `"me"` as a literal code. - Repeatable inputs use one flag per value (`--add a --add b`), not comma lists. - No env-var reads at the verb level. Anything an operator might set in @@ -96,7 +100,7 @@ The binary owns these globals; modules MUST NOT redeclare them: | `--geo-program-id` | Geolocation program ID override. | | `--sock-file` | Daemon Unix socket path override. | | `--no-version-warning` | Suppress version-check banner. | -| `--verbose`, `-v` | Diagnostic logging at debug (`-v`) or trace (`-vv`). | +| `--log-verbose` | Diagnostic logging. Repeat for higher levels: once raises to `debug`, twice raises to `trace`. No short alias because `connect`/`disconnect` still own `-v`/`--verbose` for their own flags. | | `--version`, `-V` | Print version and exit. | `--env` resolves through `doublezero-config`. Recognized values are diff --git a/rfcs/rfc20-cli-standardization.md b/rfcs/rfc20-cli-standardization.md index 0d7006f1a8..d48e03bd79 100644 --- a/rfcs/rfc20-cli-standardization.md +++ b/rfcs/rfc20-cli-standardization.md @@ -110,7 +110,7 @@ Modules MUST NOT mutate `CliContext` and MUST NOT re-resolve any value from `--e - **Short aliases on booleans only.** Boolean toggles MAY declare a single-letter short alias. Non-boolean flags MUST NOT use short aliases. -- **Identifiers accept both pubkey and code.** Any flag that references an onchain entity MUST accept either a Solana pubkey or the entity's human-readable code via the shared validator. The magic value `"me"` resolves to the current payer's pubkey at execution time. +- **Identifiers accept both pubkey and code.** Any flag that references an onchain entity MUST accept either a Solana pubkey or the entity's human-readable code via the shared validator. Where a flag denotes a signer or payer-scoped entity (for example `--administrator`, `--user-payer`, `--contributor`), the verb MAY also accept the literal `"me"` and resolve it to the current payer's pubkey at execution time. `"me"` resolution is a verb-level responsibility, performed in the verb's `execute` path using the payer pubkey from `CliContext`; the shared validators only enforce grammar. Verbs that do not opt in will treat `"me"` as a literal code. - **Repeatable inputs use one flag per value.** A list of permissions is `--add perm1 --add perm2`, not `--add perm1,perm2`. Exception: values that are naturally lists (such as CIDR prefix lists) MAY use a typed list parser. @@ -136,7 +136,7 @@ Modules MUST NOT mutate `CliContext` and MUST NOT re-resolve any value from `--e Diagnostic output is separate from user-facing output and goes to standard error through the shared logging facade in the CLI core crate. Modules use the standard log macros (`debug!`, `info!`, `warn!`, `error!`, and `trace!` when finer granularity is justified) for anything that explains what a verb is doing internally: backend requests issued, retries, resolution of pubkey-or-code arguments, polling progress, and similar. -The binary configures the global log level from `--verbose`: warnings and errors only by default, `debug` when `--verbose` is set, and `trace` when `-vv` is set. Modules MUST NOT set or override the log level themselves and MUST NOT use `println!` or `eprintln!` for diagnostics. JSON output remains parseable regardless of `--verbose` because diagnostic logs go to stderr and the user-facing writer goes to stdout. +The binary configures the global log level from `--log-verbose`: warnings and errors only by default, `debug` when `--log-verbose` is set once, and `trace` when set twice (`--log-verbose --log-verbose`). The flag is spelled `--log-verbose` rather than `--verbose, -v` because `connect` and `disconnect` still own their own per-subcommand `--verbose` (`-v`) flags from earlier releases; a future RFC may deprecate those and reclaim the shorter spelling. Modules MUST NOT set or override the log level themselves and MUST NOT use `println!` or `eprintln!` for diagnostics. JSON output remains parseable regardless of `--log-verbose` because diagnostic logs go to stderr and the user-facing writer goes to stdout. ### Environments and configuration resolution @@ -168,7 +168,7 @@ The unified binary owns the following global flags, propagated to every subcomma | `--geo-program-id` | Geolocation program ID override. | | `--sock-file` | Daemon Unix socket path override. | | `--no-version-warning` | Suppress the version-check banner. | -| `--verbose`, `-v` | Enable diagnostic logging at `debug` level. Repeating (`-vv`) MAY raise the level to `trace`. | +| `--log-verbose` | Enable diagnostic logging. Repeating (`--log-verbose --log-verbose`) raises the level from `debug` to `trace`. No short alias yet because `connect`/`disconnect` still own `-v`/`--verbose` for legacy per-subcommand flags. | | `--version`, `-V` | Print the binary version and exit. | The DZ-ledger and Solana-L1 transports use separate override flags by design: confusing the two leads to verbs that quietly run against the wrong network. When `--env` is set, all transports resolve consistently; when an override is needed for one transport, the others continue to follow `--env`. From 874f1c4c2bb626eae60eb24fbd6fe3ca2c4464bb Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Mon, 25 May 2026 13:28:18 +0000 Subject: [PATCH 5/6] docs/cli: update CLI standard to include new global flag `--log-verbose` --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 1ab9e77c90..752b1cfc71 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -103,7 +103,7 @@ make generate-fixtures # Regenerate .bin/.json fixtures from Rust ## CLI Standard (RFC-20) - New CLI verbs and module crates follow RFC-20 (`rfcs/rfc20-cli-standardization.md`). A contributor-facing summary lives at `docs/cli-standard.md`, with `smartcontract/cli/src/location/get.rs` as the reference verb. -- Shared CLI utilities (`CliContext`, validators, formatters, `RequirementCheck`, `init_logging`) live in `crates/doublezero-cli-core/`. Verbs MUST consume the shared validators and route diagnostic output through `tracing`. The `doublezero` binary owns global flags (`--env`, `--url`, `--ws`, `--solana-url`, `--keypair`, `--program-id`, `--geo-program-id`, `--sock-file`, `--verbose`, `--version`); modules MUST NOT redeclare them. +- Shared CLI utilities (`CliContext`, validators, formatters, `RequirementCheck`, `init_logging`) live in `crates/doublezero-cli-core/`. Verbs MUST consume the shared validators and route diagnostic output through `tracing`. The `doublezero` binary owns global flags (`--env`, `--url`, `--ws`, `--solana-url`, `--keypair`, `--program-id`, `--geo-program-id`, `--sock-file`, `--log-verbose`, `--version`); modules MUST NOT redeclare them. - The serviceability module crate is named `doublezero-serviceability-cli` (crate path `smartcontract/cli/`, import path `doublezero_serviceability_cli`). - Migration is opportunistic. Existing verbs are grandfathered; new verbs conform from day one. From 62e5e74064738283f1f6c10729a002a5b4ff290f Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Fri, 22 May 2026 12:46:53 +0000 Subject: [PATCH 6/6] cli/serviceability: move per-resource subcommand wrappers into module crate --- CHANGELOG.md | 1 + client/doublezero/src/cli/command.rs | 30 +++-- client/doublezero/src/cli/mod.rs | 13 -- client/doublezero/src/cli/multicast.rs | 2 +- client/doublezero/src/main.rs | 122 +++++++++--------- .../cli}/src/cli/accesspass.rs | 4 +- .../cli}/src/cli/config.rs | 2 +- .../cli}/src/cli/contributor.rs | 4 +- .../cli}/src/cli/device.rs | 4 +- .../cli}/src/cli/exchange.rs | 2 +- .../cli}/src/cli/globalconfig.rs | 4 +- .../cli}/src/cli/link.rs | 4 +- .../cli}/src/cli/location.rs | 2 +- smartcontract/cli/src/cli/mod.rs | 22 ++++ .../cli}/src/cli/multicastgroup.rs | 2 +- .../cli}/src/cli/permission.rs | 4 +- .../cli}/src/cli/resource.rs | 4 +- .../cli}/src/cli/tenant.rs | 2 +- .../cli}/src/cli/user.rs | 2 +- smartcontract/cli/src/lib.rs | 1 + 20 files changed, 124 insertions(+), 107 deletions(-) rename {client/doublezero => smartcontract/cli}/src/cli/accesspass.rs (95%) rename {client/doublezero => smartcontract/cli}/src/cli/config.rs (78%) rename {client/doublezero => smartcontract/cli}/src/cli/contributor.rs (86%) rename {client/doublezero => smartcontract/cli}/src/cli/device.rs (97%) rename {client/doublezero => smartcontract/cli}/src/cli/exchange.rs (94%) rename {client/doublezero => smartcontract/cli}/src/cli/globalconfig.rs (99%) rename {client/doublezero => smartcontract/cli}/src/cli/link.rs (98%) rename {client/doublezero => smartcontract/cli}/src/cli/location.rs (86%) create mode 100644 smartcontract/cli/src/cli/mod.rs rename {client/doublezero => smartcontract/cli}/src/cli/multicastgroup.rs (98%) rename {client/doublezero => smartcontract/cli}/src/cli/permission.rs (87%) rename {client/doublezero => smartcontract/cli}/src/cli/resource.rs (95%) rename {client/doublezero => smartcontract/cli}/src/cli/tenant.rs (96%) rename {client/doublezero => smartcontract/cli}/src/cli/user.rs (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e2e268f67..f10268119a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. - Migrate `location get` to the RFC-20 conforming verb pattern as the project's reference. `GetLocationCliCommand::execute` is now `async fn`, takes `&CliContext` as its first non-self argument, and emits a `tracing::debug!` event so `-v` surfaces what the verb is doing. The verb's user-facing args, flags, table layout, and JSON schema are unchanged. The unit test consumes the shared `doublezero_cli_core::testing::cli_context_default_for_tests()` helper and continues to use the existing `MockCliCommand` (auto-generated by `#[automock]`) as the backend. Binary dispatch arms in `client/doublezero` and `controlplane/doublezero-admin` are updated to `.await` the new method; other location verbs (Create, Update, List, Delete) keep their current sync signatures and migrate opportunistically. - Add `docs/cli-standard.md`, the contributor-facing summary of RFC-20 with the `location get` worked example and pointers to the shared validators, formatters, logging facade, and test helpers in `doublezero-cli-core`. - Update `CLAUDE.md` with a CLI-standard section pointing at RFC-20, the contributor doc, and the reference verb so future contributors land on the standard quickly. + - Move the per-resource serviceability subcommand wrapper files (`accesspass`, `config`, `contributor`, `device`, `exchange`, `globalconfig`, `link`, `location`, `multicastgroup`, `permission`, `resource`, `tenant`, `user`) from `client/doublezero/src/cli/` into the module crate at `smartcontract/cli/src/cli/` per RFC-20 §Module contract item 2. Internal imports in the moved files switch from `doublezero_serviceability_cli::::*` to `crate::::*`. Binary import paths in `client/doublezero/src/{cli/command.rs,main.rs}` switch to `doublezero_serviceability_cli::cli::::*`. `cli/multicast.rs` stays in the binary because its `Subscribe`/`Unsubscribe`/`Publish`/`Unpublish` variants are async and depend on binary-local daemon-control infrastructure (`ServiceControllerImpl`, `crate::command::helpers::resolve_client_ip`); the binary now imports `MulticastGroupCliCommand` from the library. Binary `Command` enum and `main.rs` dispatch are unchanged; this is pure file relocation. ## [v0.24.0](https://github.com/malbeclabs/doublezero/compare/client/v0.23.0...client/v0.24.0) - 2026-05-22 diff --git a/client/doublezero/src/cli/command.rs b/client/doublezero/src/cli/command.rs index d0ae55cd01..97332e210b 100644 --- a/client/doublezero/src/cli/command.rs +++ b/client/doublezero/src/cli/command.rs @@ -1,12 +1,5 @@ -use super::multicast::MulticastCliCommand; use crate::{ - cli::{ - accesspass::AccessPassCliCommand, config::ConfigCliCommand, - contributor::ContributorCliCommand, device::DeviceCliCommand, exchange::ExchangeCliCommand, - geolocation::GeolocationCliCommand, globalconfig::GlobalConfigCliCommand, - link::LinkCliCommand, location::LocationCliCommand, permission::PermissionCliCommand, - resource::ResourceCliCommand, tenant::TenantCliCommand, user::UserCliCommand, - }, + cli::{geolocation::GeolocationCliCommand, multicast::MulticastCliCommand}, command::{ connect::ProvisioningCliCommand, disable::DisableCliCommand, disconnect::DecommissioningCliCommand, enable::EnableCliCommand, @@ -16,10 +9,23 @@ use crate::{ use clap::{Args, Subcommand}; use clap_complete::Shell; use doublezero_serviceability_cli::{ - account::GetAccountCliCommand, accounts::GetAccountsCliCommand, address::AddressCliCommand, - balance::BalanceCliCommand, export::ExportCliCommand, - geolocation::programconfig::init::InitProgramConfigCliCommand, init::InitCliCommand, - keygen::KeyGenCliCommand, logcommand::LogCliCommand, migrate::MigrateCliCommand, + account::GetAccountCliCommand, + accounts::GetAccountsCliCommand, + address::AddressCliCommand, + balance::BalanceCliCommand, + cli::{ + accesspass::AccessPassCliCommand, config::ConfigCliCommand, + contributor::ContributorCliCommand, device::DeviceCliCommand, exchange::ExchangeCliCommand, + globalconfig::GlobalConfigCliCommand, link::LinkCliCommand, location::LocationCliCommand, + permission::PermissionCliCommand, resource::ResourceCliCommand, tenant::TenantCliCommand, + user::UserCliCommand, + }, + export::ExportCliCommand, + geolocation::programconfig::init::InitProgramConfigCliCommand, + init::InitCliCommand, + keygen::KeyGenCliCommand, + logcommand::LogCliCommand, + migrate::MigrateCliCommand, }; #[derive(Subcommand, Debug)] diff --git a/client/doublezero/src/cli/mod.rs b/client/doublezero/src/cli/mod.rs index 4661143e46..9b9c38b536 100644 --- a/client/doublezero/src/cli/mod.rs +++ b/client/doublezero/src/cli/mod.rs @@ -1,16 +1,3 @@ -pub mod accesspass; pub mod command; -pub mod config; -pub mod contributor; -pub mod device; -pub mod exchange; pub mod geolocation; -pub mod globalconfig; -pub mod link; -pub mod location; pub mod multicast; -pub mod multicastgroup; -pub mod permission; -pub mod resource; -pub mod tenant; -pub mod user; diff --git a/client/doublezero/src/cli/multicast.rs b/client/doublezero/src/cli/multicast.rs index 55e2335408..c7064a6956 100644 --- a/client/doublezero/src/cli/multicast.rs +++ b/client/doublezero/src/cli/multicast.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use super::multicastgroup::MulticastGroupCliCommand; +use doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCliCommand; #[derive(Args, Debug)] pub struct MulticastCliCommand { diff --git a/client/doublezero/src/main.rs b/client/doublezero/src/main.rs index ba63dfd3ec..d6e8cf2a34 100644 --- a/client/doublezero/src/main.rs +++ b/client/doublezero/src/main.rs @@ -10,26 +10,30 @@ mod requirements; mod servicecontroller; use crate::cli::{ command::Command, - config::ConfigCommands, - device::{DeviceCommands, InterfaceCommands}, - exchange::ExchangeCommands, geolocation::{ probe::ProbeCommands, user::UserCommands as GeoUserCommands, GeolocationCommands, }, - globalconfig::{ - AirdropCommands, AuthorityCommands, FeatureFlagsCommands, FoundationAllowlistCommands, - GlobalConfigCommands, QaAllowlistCommands, - }, - link::{LinkCommands, TopologyCommands}, - location::LocationCommands, - user::UserCommands, }; use doublezero_cli_core::LogLevel; use doublezero_sdk::{geolocation::client::GeoClient, DZClient, ProgramVersion}; use doublezero_serviceability::pda::get_globalstate_pda; use doublezero_serviceability_cli::{ - checkversion::check_version, doublezerocommand::CliCommandImpl, - geoclicommand::GeoCliCommandImpl, version::VersionCliCommand, + checkversion::check_version, + cli::{ + config::ConfigCommands, + device::{DeviceCommands, InterfaceCommands}, + exchange::ExchangeCommands, + globalconfig::{ + AirdropCommands, AuthorityCommands, FeatureFlagsCommands, FoundationAllowlistCommands, + GlobalConfigCommands, QaAllowlistCommands, + }, + link::{LinkCommands, TopologyCommands}, + location::LocationCommands, + user::UserCommands, + }, + doublezerocommand::CliCommandImpl, + geoclicommand::GeoCliCommandImpl, + version::VersionCliCommand, }; use servicecontroller::ServiceControllerImpl; @@ -332,37 +336,37 @@ async fn main() -> eyre::Result<()> { ExchangeCommands::Delete(args) => args.execute(&client, &mut handle), }, Command::Contributor(command) => match command.command { - cli::contributor::ContributorCommands::Create(args) => { + doublezero_serviceability_cli::cli::contributor::ContributorCommands::Create(args) => { args.execute(&client, &mut handle) } - cli::contributor::ContributorCommands::Update(args) => { + doublezero_serviceability_cli::cli::contributor::ContributorCommands::Update(args) => { args.execute(&client, &mut handle) } - cli::contributor::ContributorCommands::List(args) => args.execute(&client, &mut handle), - cli::contributor::ContributorCommands::Get(args) => args.execute(&client, &mut handle), - cli::contributor::ContributorCommands::Delete(args) => { + doublezero_serviceability_cli::cli::contributor::ContributorCommands::List(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::contributor::ContributorCommands::Get(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::contributor::ContributorCommands::Delete(args) => { args.execute(&client, &mut handle) } }, Command::Permission(command) => match command.command { - cli::permission::PermissionCommands::Set(args) => args.execute(&client, &mut handle), - cli::permission::PermissionCommands::Suspend(args) => { + doublezero_serviceability_cli::cli::permission::PermissionCommands::Set(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::permission::PermissionCommands::Suspend(args) => { args.execute(&client, &mut handle) } - cli::permission::PermissionCommands::Resume(args) => args.execute(&client, &mut handle), - cli::permission::PermissionCommands::Delete(args) => args.execute(&client, &mut handle), - cli::permission::PermissionCommands::Get(args) => args.execute(&client, &mut handle), - cli::permission::PermissionCommands::List(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::permission::PermissionCommands::Resume(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::permission::PermissionCommands::Delete(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::permission::PermissionCommands::Get(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::permission::PermissionCommands::List(args) => args.execute(&client, &mut handle), }, Command::Tenant(command) => match command.command { - cli::tenant::TenantCommands::Create(args) => args.execute(&client, &mut handle), - cli::tenant::TenantCommands::Update(args) => args.execute(&client, &mut handle), - cli::tenant::TenantCommands::List(args) => args.execute(&client, &mut handle), - cli::tenant::TenantCommands::Get(args) => args.execute(&client, &mut handle), - cli::tenant::TenantCommands::Delete(args) => args.execute(&client, &mut handle), - cli::tenant::TenantCommands::Administrator(command) => match command.command { - cli::tenant::AdministratorCommands::Add(args) => args.execute(&client, &mut handle), - cli::tenant::AdministratorCommands::Remove(args) => { + doublezero_serviceability_cli::cli::tenant::TenantCommands::Create(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::TenantCommands::Update(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::TenantCommands::List(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::TenantCommands::Get(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::TenantCommands::Delete(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::TenantCommands::Administrator(command) => match command.command { + doublezero_serviceability_cli::cli::tenant::AdministratorCommands::Add(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::tenant::AdministratorCommands::Remove(args) => { args.execute(&client, &mut handle) } }, @@ -384,8 +388,8 @@ async fn main() -> eyre::Result<()> { }, Command::Link(command) => match command.command { LinkCommands::Create(args) => match args.command { - cli::link::CreateLinkCommands::Wan(args) => args.execute(&client, &mut handle), - cli::link::CreateLinkCommands::Dzx(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::link::CreateLinkCommands::Wan(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::link::CreateLinkCommands::Dzx(args) => args.execute(&client, &mut handle), }, LinkCommands::Accept(args) => args.execute(&client, &mut handle), LinkCommands::Update(args) => args.execute(&client, &mut handle), @@ -403,14 +407,14 @@ async fn main() -> eyre::Result<()> { }, }, Command::AccessPass(command) => match command.command { - cli::accesspass::AccessPassCommands::Set(args) => args.execute(&client, &mut handle), - cli::accesspass::AccessPassCommands::Close(args) => args.execute(&client, &mut handle), - cli::accesspass::AccessPassCommands::List(args) => args.execute(&client, &mut handle), - cli::accesspass::AccessPassCommands::Get(args) => args.execute(&client, &mut handle), - cli::accesspass::AccessPassCommands::UserBalances(args) => { + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::Set(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::Close(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::List(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::Get(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::UserBalances(args) => { args.execute(&client, &mut handle) } - cli::accesspass::AccessPassCommands::Fund(args) => { + doublezero_serviceability_cli::cli::accesspass::AccessPassCommands::Fund(args) => { args.execute(&client, &mut handle, &mut std::io::stdin().lock()) } }, @@ -426,49 +430,49 @@ async fn main() -> eyre::Result<()> { }, Command::Multicast(args) => match args.command { cli::multicast::MulticastCommands::Group(args) => match args.command { - cli::multicastgroup::MulticastGroupCommands::Allowlist(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::Allowlist(args) => { match args.command { - cli::multicastgroup::MulticastGroupAllowlistCommands::Publisher(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupAllowlistCommands::Publisher(args) => { match args.command { - cli::multicastgroup::MulticastGroupPubAllowlistCommands::List( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupPubAllowlistCommands::List( args, ) => args.execute(&client, &mut handle), - cli::multicastgroup::MulticastGroupPubAllowlistCommands::Add( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupPubAllowlistCommands::Add( args, ) => args.execute(&client, &mut handle), - cli::multicastgroup::MulticastGroupPubAllowlistCommands::Remove( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupPubAllowlistCommands::Remove( args, ) => args.execute(&client, &mut handle), } } - cli::multicastgroup::MulticastGroupAllowlistCommands::Subscriber(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupAllowlistCommands::Subscriber(args) => { match args.command { - cli::multicastgroup::MulticastGroupSubAllowlistCommands::List( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupSubAllowlistCommands::List( args, ) => args.execute(&client, &mut handle), - cli::multicastgroup::MulticastGroupSubAllowlistCommands::Add( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupSubAllowlistCommands::Add( args, ) => args.execute(&client, &mut handle), - cli::multicastgroup::MulticastGroupSubAllowlistCommands::Remove( + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupSubAllowlistCommands::Remove( args, ) => args.execute(&client, &mut handle), } } } } - cli::multicastgroup::MulticastGroupCommands::Create(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::Create(args) => { args.execute(&client, &mut handle) } - cli::multicastgroup::MulticastGroupCommands::Update(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::Update(args) => { args.execute(&client, &mut handle) } - cli::multicastgroup::MulticastGroupCommands::List(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::List(args) => { args.execute(&client, &mut handle) } - cli::multicastgroup::MulticastGroupCommands::Get(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::Get(args) => { args.execute(&client, &mut handle) } - cli::multicastgroup::MulticastGroupCommands::Delete(args) => { + doublezero_serviceability_cli::cli::multicastgroup::MulticastGroupCommands::Delete(args) => { args.execute(&client, &mut handle) } }, @@ -511,12 +515,12 @@ async fn main() -> eyre::Result<()> { } Command::Resource(command) => match command.command { - cli::resource::ResourceCommands::Allocate(args) => args.execute(&client, &mut handle), - cli::resource::ResourceCommands::Create(args) => args.execute(&client, &mut handle), - cli::resource::ResourceCommands::Deallocate(args) => args.execute(&client, &mut handle), - cli::resource::ResourceCommands::Get(args) => args.execute(&client, &mut handle), - cli::resource::ResourceCommands::Close(args) => args.execute(&client, &mut handle), - cli::resource::ResourceCommands::Verify(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Allocate(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Create(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Deallocate(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Get(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Close(args) => args.execute(&client, &mut handle), + doublezero_serviceability_cli::cli::resource::ResourceCommands::Verify(args) => args.execute(&client, &mut handle), }, Command::Export(args) => args.execute(&client, &mut handle), diff --git a/client/doublezero/src/cli/accesspass.rs b/smartcontract/cli/src/cli/accesspass.rs similarity index 95% rename from client/doublezero/src/cli/accesspass.rs rename to smartcontract/cli/src/cli/accesspass.rs index 8dc90b753e..c32b9e2f3c 100644 --- a/client/doublezero/src/cli/accesspass.rs +++ b/smartcontract/cli/src/cli/accesspass.rs @@ -1,9 +1,9 @@ -use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::accesspass::{ +use crate::accesspass::{ close::CloseAccessPassCliCommand, fund::FundAccessPassCliCommand, get::GetAccessPassCliCommand, list::ListAccessPassCliCommand, set::SetAccessPassCliCommand, user_balances::UserBalancesAccessPassCliCommand, }; +use clap::{Args, Subcommand}; #[derive(Args, Debug)] pub struct AccessPassCliCommand { diff --git a/client/doublezero/src/cli/config.rs b/smartcontract/cli/src/cli/config.rs similarity index 78% rename from client/doublezero/src/cli/config.rs rename to smartcontract/cli/src/cli/config.rs index 47021ded09..58f2288535 100644 --- a/client/doublezero/src/cli/config.rs +++ b/smartcontract/cli/src/cli/config.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; +use crate::config::{get::GetConfigCliCommand, set::SetConfigCliCommand}; #[derive(Args, Debug)] pub struct ConfigCliCommand { diff --git a/client/doublezero/src/cli/contributor.rs b/smartcontract/cli/src/cli/contributor.rs similarity index 86% rename from client/doublezero/src/cli/contributor.rs rename to smartcontract/cli/src/cli/contributor.rs index 5254911278..91f61349d7 100644 --- a/client/doublezero/src/cli/contributor.rs +++ b/smartcontract/cli/src/cli/contributor.rs @@ -1,8 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::contributor::{ - create::*, delete::*, get::*, list::*, update::*, -}; +use crate::contributor::{create::*, delete::*, get::*, list::*, update::*}; #[derive(Args, Debug)] pub struct ContributorCliCommand { diff --git a/client/doublezero/src/cli/device.rs b/smartcontract/cli/src/cli/device.rs similarity index 97% rename from client/doublezero/src/cli/device.rs rename to smartcontract/cli/src/cli/device.rs index 08921a8cc8..14e0e8d92d 100644 --- a/client/doublezero/src/cli/device.rs +++ b/smartcontract/cli/src/cli/device.rs @@ -1,5 +1,4 @@ -use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::device::{ +use crate::device::{ create::CreateDeviceCliCommand, delete::DeleteDeviceCliCommand, get::GetDeviceCliCommand, @@ -12,6 +11,7 @@ use doublezero_serviceability_cli::device::{ sethealth::SetDeviceHealthCliCommand, update::UpdateDeviceCliCommand, }; +use clap::{Args, Subcommand}; #[derive(Debug, Subcommand)] pub enum InterfaceCommands { diff --git a/client/doublezero/src/cli/exchange.rs b/smartcontract/cli/src/cli/exchange.rs similarity index 94% rename from client/doublezero/src/cli/exchange.rs rename to smartcontract/cli/src/cli/exchange.rs index a468a4b526..9af2f1e044 100644 --- a/client/doublezero/src/cli/exchange.rs +++ b/smartcontract/cli/src/cli/exchange.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::exchange::{ +use crate::exchange::{ create::*, delete::*, get::*, list::*, setdevice::SetDeviceExchangeCliCommand, update::*, }; diff --git a/client/doublezero/src/cli/globalconfig.rs b/smartcontract/cli/src/cli/globalconfig.rs similarity index 99% rename from client/doublezero/src/cli/globalconfig.rs rename to smartcontract/cli/src/cli/globalconfig.rs index 2dfb4b6aaa..1ba1660456 100644 --- a/client/doublezero/src/cli/globalconfig.rs +++ b/smartcontract/cli/src/cli/globalconfig.rs @@ -1,5 +1,4 @@ -use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::{ +use crate::{ allowlist::{ foundation::{ add::AddFoundationAllowlistCliCommand, list::ListFoundationAllowlistCliCommand, @@ -16,6 +15,7 @@ use doublezero_serviceability_cli::{ setversion::SetVersionCliCommand, }, }; +use clap::{Args, Subcommand}; #[derive(Args, Debug)] pub struct GlobalConfigCliCommand { diff --git a/client/doublezero/src/cli/link.rs b/smartcontract/cli/src/cli/link.rs similarity index 98% rename from client/doublezero/src/cli/link.rs rename to smartcontract/cli/src/cli/link.rs index d67ba4f9d2..fe075fcad5 100644 --- a/client/doublezero/src/cli/link.rs +++ b/smartcontract/cli/src/cli/link.rs @@ -1,5 +1,4 @@ -use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::{ +use crate::{ link::{ accept::AcceptLinkCliCommand, delete::*, dzx_create::CreateDZXLinkCliCommand, get::*, latency::LinkLatencyCliCommand, list::*, sethealth::SetLinkHealthCliCommand, update::*, @@ -11,6 +10,7 @@ use doublezero_serviceability_cli::{ list::ListTopologyCliCommand, }, }; +use clap::{Args, Subcommand}; #[derive(Args, Debug)] pub struct LinkCliCommand { diff --git a/client/doublezero/src/cli/location.rs b/smartcontract/cli/src/cli/location.rs similarity index 86% rename from client/doublezero/src/cli/location.rs rename to smartcontract/cli/src/cli/location.rs index d14c7dd1a2..5f6aa2232e 100644 --- a/client/doublezero/src/cli/location.rs +++ b/smartcontract/cli/src/cli/location.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::location::{create::*, delete::*, get::*, list::*, update::*}; +use crate::location::{create::*, delete::*, get::*, list::*, update::*}; #[derive(Args, Debug)] pub struct LocationCliCommand { diff --git a/smartcontract/cli/src/cli/mod.rs b/smartcontract/cli/src/cli/mod.rs new file mode 100644 index 0000000000..cf6d1c5477 --- /dev/null +++ b/smartcontract/cli/src/cli/mod.rs @@ -0,0 +1,22 @@ +//! Module-crate-owned subcommand enums per RFC-20 (§Module contract item 2). +//! +//! Each file in this module defines one resource's clap `Subcommand` enum +//! (`DeviceCommands`, `LinkCommands`, ...) wrapping the per-verb args types +//! that live next to the verbs themselves (`crate::device::create::*`, +//! `crate::link::create::*`, ...). A future PR adds a top-level +//! `ServiceabilityCommand` aggregator and hoists these variants into the +//! unified `doublezero` binary via `#[command(flatten)]`. + +pub mod accesspass; +pub mod config; +pub mod contributor; +pub mod device; +pub mod exchange; +pub mod globalconfig; +pub mod link; +pub mod location; +pub mod multicastgroup; +pub mod permission; +pub mod resource; +pub mod tenant; +pub mod user; diff --git a/client/doublezero/src/cli/multicastgroup.rs b/smartcontract/cli/src/cli/multicastgroup.rs similarity index 98% rename from client/doublezero/src/cli/multicastgroup.rs rename to smartcontract/cli/src/cli/multicastgroup.rs index ba135239b2..8e77e66b51 100644 --- a/client/doublezero/src/cli/multicastgroup.rs +++ b/smartcontract/cli/src/cli/multicastgroup.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::multicastgroup::{ +use crate::multicastgroup::{ allowlist::{ publisher::{ add::AddMulticastGroupPubAllowlistCliCommand, diff --git a/client/doublezero/src/cli/permission.rs b/smartcontract/cli/src/cli/permission.rs similarity index 87% rename from client/doublezero/src/cli/permission.rs rename to smartcontract/cli/src/cli/permission.rs index f773ce4580..d258d66e12 100644 --- a/client/doublezero/src/cli/permission.rs +++ b/smartcontract/cli/src/cli/permission.rs @@ -1,8 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::permission::{ - delete::*, get::*, list::*, resume::*, set::*, suspend::*, -}; +use crate::permission::{delete::*, get::*, list::*, resume::*, set::*, suspend::*}; #[derive(Args, Debug)] pub struct PermissionCliCommand { diff --git a/client/doublezero/src/cli/resource.rs b/smartcontract/cli/src/cli/resource.rs similarity index 95% rename from client/doublezero/src/cli/resource.rs rename to smartcontract/cli/src/cli/resource.rs index 7fc8f679fb..bb7886edbd 100644 --- a/client/doublezero/src/cli/resource.rs +++ b/smartcontract/cli/src/cli/resource.rs @@ -1,9 +1,9 @@ -use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::resource::{ +use crate::resource::{ allocate::AllocateResourceCliCommand, close::CloseResourceCliCommand, create::CreateResourceCliCommand, deallocate::DeallocateResourceCliCommand, get::GetResourceCliCommand, verify::VerifyResourceCliCommand, }; +use clap::{Args, Subcommand}; #[derive(Args, Debug)] pub struct ResourceCliCommand { diff --git a/client/doublezero/src/cli/tenant.rs b/smartcontract/cli/src/cli/tenant.rs similarity index 96% rename from client/doublezero/src/cli/tenant.rs rename to smartcontract/cli/src/cli/tenant.rs index 627b937618..c6bcd76211 100644 --- a/client/doublezero/src/cli/tenant.rs +++ b/smartcontract/cli/src/cli/tenant.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::tenant::{ +use crate::tenant::{ add_administrator::*, create::*, delete::*, get::*, list::*, remove_administrator::*, update::*, }; diff --git a/client/doublezero/src/cli/user.rs b/smartcontract/cli/src/cli/user.rs similarity index 96% rename from client/doublezero/src/cli/user.rs rename to smartcontract/cli/src/cli/user.rs index 84394874d3..10e3610afb 100644 --- a/client/doublezero/src/cli/user.rs +++ b/smartcontract/cli/src/cli/user.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use doublezero_serviceability_cli::user::{ +use crate::user::{ create::CreateUserCliCommand, create_subscribe::CreateSubscribeUserCliCommand, delete::DeleteUserCliCommand, get::GetUserCliCommand, list::ListUserCliCommand, request_ban::RequestBanUserCliCommand, subscribe::SubscribeUserCliCommand, diff --git a/smartcontract/cli/src/lib.rs b/smartcontract/cli/src/lib.rs index 14f5d11498..5ef51ebf92 100644 --- a/smartcontract/cli/src/lib.rs +++ b/smartcontract/cli/src/lib.rs @@ -5,6 +5,7 @@ pub mod address; pub mod allowlist; pub mod balance; pub mod checkversion; +pub mod cli; pub mod config; pub mod contributor; pub mod device;