Releases: devlooped/ndnx
Release list
v0.6.0
Keep floating versions evergreen with a graceful child restart.
Evergreen
A floating version — unspecified, @*, @*-*, or a NuGet range — stays current. ndnx starts the latest match, watches the feed, downloads a newer matching version before stopping the child, then sends SIGINT / Ctrl+C (and WM_CLOSE if the tool is a GUI) and restarts.
ndnx stop # latest stable, restart when a newer one lands
ndnx stop@* # same
ndnx stop@*-* # include prerelease
ndnx stop@[2.0,3.0) # stay on the newest 2.x
ndnx stop@2.1.0 # exact pin: one-shot, no loop
Short tools still exit as soon as the child exits. Only a long-running child is watched and restarted.
The new package is staged in the global packages folder first, so the old process keeps running until the update is on disk. If the child exits on its own during that window, ndnx returns that exit code and does not restart.
The poll interval defaults to 5 seconds and can be set in .netconfig:
[ndnx]
interval = 5
ndnx walks from the working directory up, then ~/.netconfig. --verbosity quiet hides the Updating … line.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.5.2
Hash the root .nuspec like dnx instead of SHA512 of the whole nupkg.
Package hash
.nupkg.sha512 (and .nupkg.metadata contentHash) is now Base64(SHA512(root nuspec)) — the same shortcut dnx writes via CryptoHashProvider("SHA512").CalculateHash(reader.GetNuspec()).
Restore hashes the entire nupkg. Tool packages are never part of a plain dotnet restore, can be large (Native AOT RID payloads), and only the manifest is needed to recognize an install. Packages already extracted by dnx stay cache hits.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.5.1
Drop OSMF
Full Changelog: v0.5.0...v0.5.1
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.5.0
Download tool@version from the constructed nupkg URL — no version-index round-trip unless that GET is 404.
Exact-version download
A first ndnx stop@2.1.0 now:
- Resolves
PackageBaseAddressfrom the v3 service index (kept in memory for the process) - GETs
{base}{id}/{version}/{id}.{version}.nupkg - Lists versions only if that GET returns 404
A RID hop (stop → stop.win-x64) reuses the cached service index and the same constructed URL, so index.json is not fetched again.
Unspecified version or @* still lists the feed for latest, same as dnx. An exact version already in the global packages folder is still a cache hit with no network.
Startup time
Cold is empty-cache download → start; cached is start only (tool@version). linux-x64 (WSL2) is SDK 10.0.110; win-x64 is SDK 10.0.303.
| Tool | Runner | Cold linux-x64 | Cold win-x64 | Cached linux-x64 | Cached win-x64 |
|---|---|---|---|---|---|
stop@2.1.0 (native AOT) |
dnx |
2.2 s | 2.1 s | 580 ms | 520 ms |
ndnx |
1.2 s | 1.5 s | 10 ms | 34 ms | |
dotnetsay@1.0.0 (framework-dependent) |
dnx |
1.6 s | 1.8 s | 570 ms | 545 ms |
ndnx |
849 ms | 1.1 s | 12 ms | 50 ms |
Isolated NUGET_PACKAGES, source https://kzu.blob.core.windows.net/nuget/index.json. Cold is the median of 3 empty-cache runs. Cached is the median of 10 runs after one seed.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.4.0
Skip the NuGet feed when tool@version is already cached, so a warm native tool starts in tens of milliseconds.
Cached exact versions
Like dnx's GetBestPackageVersionAsync, an exact version is the answer:
ndnx stop@2.1.0 -- --help
ndnx stop --version 2.1.0 -- --help
If that package is already in the global packages folder, ndnx does not query the feed. RID-specific hops (stop → stop.win-x64) use the same installed check.
Unspecified version or @* still resolve latest from the feed, same as dnx.
Startup time
Cold start is download + launch. Cached start is launch only, with an exact version so neither runner has to resolve latest.
| Tool | Runner | Cold (download → start) | Cached (start) |
|---|---|---|---|
stop@2.1.0 (native AOT) |
dnx |
5.6 s | 563 ms |
ndnx |
5.6 s | 33 ms | |
dotnetsay@1.0.0 (framework-dependent) |
dnx |
4.6 s | 585 ms |
ndnx |
4.8 s | 51 ms |
win-x64, .NET SDK 11.0.100-preview.6, isolated NUGET_PACKAGES, source https://pkg.kzu.app/index.json. Cold is the median of 3 empty-cache runs. Cached is the median of 10 runs after one seed.
Gzip v3 feeds
HttpClient now enables automatic decompression, so gzip-compressed NuGet v3 indexes (including static Sleet feeds such as https://pkg.kzu.app/index.json) parse instead of failing with 0x1F is an invalid start of a value.
Docs
The readme now shows side-by-side dnx / ndnx / dotnet dnx examples, shared cache and flags, and the timings above.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.3.0
Share the NuGet global packages cache with dnx and restore, and fail clearly when a framework-dependent tool needs a newer runtime than the host dotnet.
NuGet v3 cache
ndnx now installs one-shot tools into the same folder restore uses (NUGET_PACKAGES, nuget.config's globalPackagesFolder, or ~/.nuget/packages). NDNX_STORE still overrides that for isolated runs.
The on-disk layout matches NuGet, not a private .ndnx-ok dump:
{id}/{version}/{id}.{version}.nupkg{id}.{version}.nupkg.sha512isBase64(SHA512(nupkg bytes))— the restore algorithm, notdnx's nuspec-hash shortcut.nupkg.metadatais written last, which is how NuGet decides the install finished
A package already extracted by dnx or dotnet restore is reused. Packages ndnx writes are visible to dnx and restore.
Framework-dependent tools
Runner=executable (native / AOT tools) is unchanged.
Runner=dotnet is checked against the muxer (DOTNET_ROOT, then PATH), not ndnx's own compile-time TFM. If the tool needs .NET 10 and that dotnet only has 8.0.19, ndnx exits before launch:
This tool requires .NET 10.0. The 'dotnet.exe' at 'C:\Program Files\dotnet\dotnet.exe' has Microsoft.NETCore.App 8.0.19.
Packages with several tools/{tfm}/ groups pick the newest TFM that muxer can load.
Other
ndnx --version
prints the ndnx version and exits.
v0.2.0
Self-update the installed ndnx binary from GitHub Releases.
Self-update
ndnx --update (with no package identity) checks GitHub Releases, prints the version being installed, replaces the running binary, and exits.
ndnx --update # latest stable release
ndnx --update 0.1.1 # exact version, including downgrades
A leading v is accepted (--update v0.1.1). --update=0.1.1 and --update --version 0.1.1 work too.
If you are already on that version, ndnx says so and does nothing. Otherwise it downloads the RID archive (win-x64, linux-arm64, …) and its .sha256, verifies the hash, and swaps the executable. On Windows the running file is renamed first so the replace can succeed.
NDNX_REPO still overrides which GitHub repository is used (same as the install scripts).
--update cannot be combined with a package name or extra tool arguments.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.1.1
Multi-RID (RID-specific) .NET tools now run instead of failing on the wrapper package.
Multi-RID tool packages
.NET 10 can pack a tool as a thin wrapper plus per-RID nupkgs (RuntimeIdentifierPackages in DotnetToolSettings.xml). v0.1.0 stopped on those wrappers with declares RID-specific packages, which are not resolved by this runner.
ndnx now hops the same way the SDK does:
- Pick the best declared RID for this machine (exact host RID, then the portable RID graph — e.g.
ubuntu.24.04-x64→linux-x64— thenany) - Download that mapped package at the same version
- Run the RID package’s
EntryPoint+Runner
That unblocks Native AOT tools such as stop and winget, and the same layout used by go, runfile, and gist. Classic tools/{tfm}/{rid} packages are unchanged.
Executable payloads extracted from nupkgs also get Unix execute bits, so RID binaries actually run after extract on macOS and Linux.
Packaging
Windows release zips are submitted to WinGet (Devlooped.ndnx) after a published GitHub release.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜
v0.1.0
Initial public release of ndnx.
Native AOT binaries for Windows, macOS, and Linux (x64 and arm64), plus install scripts.
Sponsors
The following sponsors made this release possible: @clarius, @MFB-Technologies-Inc, @sandrock, @drivenet, @Keflon, @tbolon, @kfrancis, @rbnswartz, @jfoshee, @Mrxx99, @eajhnsn1, @Jonathan-Hickey, @KenBonny, @SimonCropp, @agileworks-eu, @arsdragonfly, @vezel-dev, @ChilliCream, @4OTC, @DominicSchell, @adalon, @torutek, @mccaffers, @SeikaLogiciel, @wizardness, @eska-gmbh, @geodata-no.
Thanks 💜