Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ All notable changes to this project will be documented in this file.
- Add `--log-level <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: <head>` 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-<module>-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.
- 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::<resource>::*` to `crate::<resource>::*`. Binary import paths in `client/doublezero/src/{cli/command.rs,main.rs}` switch to `doublezero_serviceability_cli::cli::<resource>::*`. `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

Expand Down
7 changes: 7 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`, `--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.

## Style & Terminology

- Use "onchain" (one word, no hyphen), never "on-chain"
Expand Down
52 changes: 27 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }

Expand Down
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/src/cli/command.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/src/cli/config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clap::{Args, Subcommand};
use doublezero_cli::geolocation::config::{
use doublezero_serviceability_cli::geolocation::config::{
get::GetGeoConfigCliCommand, set::SetGeoConfigCliCommand,
};

Expand Down
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/src/cli/probe.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/src/cli/user.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion client/doublezero-geolocation-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions client/doublezero/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ 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
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
Expand Down
32 changes: 19 additions & 13 deletions client/doublezero/src/cli/command.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -15,11 +8,24 @@ use crate::{
};
use clap::{Args, Subcommand};
use clap_complete::Shell;
use doublezero_cli::{
account::GetAccountCliCommand, accounts::GetAccountsCliCommand, address::AddressCliCommand,
balance::BalanceCliCommand, export::ExportCliCommand,
geolocation::programconfig::init::InitProgramConfigCliCommand, init::InitCliCommand,
keygen::KeyGenCliCommand, logcommand::LogCliCommand, migrate::MigrateCliCommand,
use doublezero_serviceability_cli::{
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)]
Expand Down
2 changes: 1 addition & 1 deletion client/doublezero/src/cli/geolocation/probe.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion client/doublezero/src/cli/geolocation/user.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
13 changes: 0 additions & 13 deletions client/doublezero/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion client/doublezero/src/cli/multicast.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
14 changes: 8 additions & 6 deletions client/doublezero/src/command/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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::{
Expand Down
6 changes: 3 additions & 3 deletions client/doublezero/src/command/disable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down Expand Up @@ -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();
Expand All @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions client/doublezero/src/command/disconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions client/doublezero/src/command/enable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down Expand Up @@ -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();
Expand All @@ -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()
Expand Down
Loading
Loading