3.2.0 - 2026-06-07
Release Notes
Cross-method install cleanup: consolidate to a single nd300/speedqx install
(one version, one edition) — interactively from the installers AND on a silent
self-update. Windows-only behavior; macOS/Linux already overwrite the single
~/.cargo/bin copy and are unaffected.
Added
- Hidden
nd300 migrate-cleanupsubcommand (src/actions/migrate.rs,#[command(hide = true)]insrc/cli.rs). Detects and removes duplicate installs by reusing the existing tested deletion primitives — it does not re-implement deletion:- From
src/actions/uninstall.rs:uninstall_path,CleanupReport,is_sole_package_in_dir, and theOUR_BINARIESallowlist (nowpub(crate)). - From
src/actions/update.rs:cargo_bin_dir,same_path,classify_install_path,current_install_shadows_cargo_install,current_exe_real_path,classify_shadow_cleanup,ShadowCleanupDecision,InstallOrigin(nowpub(crate)). - Flags:
--cargo-copy,--other-edition,--quiet,--dry-run,--json,--user-profile <path>,--cargo-home <path>. With no target flag, defaults to--cargo-copyonly. - Targets: the shadowing older
cargo installcopy in~\.cargo\bin, and the other Windows edition (Global perMachineC:\Program Files\nd300\bin↔ Corporate perUser%LocalAppData%\Programs\nd300\bin).--cargo-home/--user-profiletake precedence over%USERPROFILE%/process env so a perMachine installer can resolve the invoking user's.cargo. - Hard safety guarantees (unit-tested): only ever deletes
nd300.exe/speedqx.exe(allowlist); nevercargo.exe/rustup.exe/non-allowlisted files; never removes the.cargo\binPATH entry (delegated touninstall_path, which only edits PATH whenis_sole_package_in_diris true — and.cargo\binalways also holds cargo/rustup); never touches~/Downloads; never deletes the running install (same_pathguard); never escalates privileges (a target needing admin we lack is reportedneeds admin: <path>and continues — exit 0); refuses shell-unsafe paths (viauninstall_path's existingbuild_delayed_delete_commandrefusal). - Exit 0 even on partial/empty/needs-admin — cleanup is advisory and must never fail an installer. Only a true internal error (couldn't determine the running install's own location) is nonzero.
- Reporting: human (removed / scheduled-on-exit / skipped:
<reason>/ needs-admin / failed, per target) and--json(stablestatusvaluesremoved/scheduled/would_remove/skipped/needs_admin/failed).
- From
- Installer consolidation UX + invocation on all four Windows installers. Both options default ON, so a SILENT install consolidates too:
- Inno (
inno/global.iss,inno/corporate.iss): two default-checked[Tasks](cleancargo,cleanotheredition) + a[Run]postinstall calling{app}\bin\nd300.exe migrate-cleanup --quiet <flag>withFlags: runhidden waituntilterminated, conditioned on each task. AddedAppMutex=ND300_Running+CloseApplications=yes. Under/SILENT(the self-updater's EXE path) default-checked tasks fire automatically — both cleanups run with no/MERGETASKSsuppression. The perMachine Global EXE passes the invoking user's profile via--user-profile "{userprofile}"(Innorunasoriginaluseris unreliable under right-click-Run-as-admin); the perUser Corporate EXE runs as the user (no--user-profile). - WiX (
wix/main.wxsGlobal perMachine,wix-corporate/corporate.wxsCorporate perUser):CLEANCARGO/CLEANOTHEREDITIONproperties (default1,Secure='yes') + aConsolidateDlgWixUI dialog (two pre-checked checkboxes inserted between WelcomeDlg and CustomizeDlg) + two deferred,Impersonate='yes',Return='ignore'custom actions scheduledBefore='InstallFinalize', conditionedNOT Installed AND CLEAN…="1"(install/upgrade only, not uninstall/repair). The CAs useFileKey='exe0'+ExeCommand(NOTWixUtilExtension'sWixQuietExec) becausecargo wix/ the barecandle+lightbuild only linkWixUIExtension— aWixQuietExecCA would fail the CI link step.Impersonate='yes'makes the perMachine MSI run cleanup as the invoking user, so the user's.cargo/%LocalAppData%resolve without needing--user-profile.
- Inno (
Changed
- Silent self-update now consolidates. No code change was required in
src/actions/update.rs:try_msi_installalready runsmsiexec /i … /passive /norestart(the default-1CLEANCARGO/CLEANOTHEREDITIONproperties stand), andtry_exe_installalready runs the EXE/SILENT …with no/MERGETASKSsuppression (the default-checked tasks fire). Verified both paths leave the cleanups enabled. Cargo.toml: version3.1.0→3.2.0.- Several
uninstall.rs/update.rsitems widened from private topub(crate)somigrate.rscan reuse them (no behavior change to update/uninstall).
Notes
- macOS/Linux compilation, and the WiX/Inno installer builds, are validated only in CI / on a Windows runner — the cross-platform Rust targets and
candle/light/isccare not run locally. All v3.1.0 update/uninstall behavior and tests are preserved.
Install nd300 3.2.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/QubeTX/qube-network-diagnostics/releases/download/v3.2.0/nd300-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/QubeTX/qube-network-diagnostics/releases/download/v3.2.0/nd300-installer.ps1 | iex"Download nd300 3.2.0
| File | Platform | Checksum |
|---|---|---|
| nd300-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| nd300-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| nd300-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| nd300-x86_64-pc-windows-msvc.msi | x64 Windows | checksum |
| nd300-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| nd300-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| nd300-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |