Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3363ec5
feat(setup): enhance loader with tool installer and config isolation
tonythethompson Aug 16, 2026
d84b267
docs: update README, CHANGELOG, and CLI help for setup loader
tonythethompson Aug 17, 2026
64f59da
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 17, 2026
8869455
Fixed loader security, parsing, error handling
opencode-agent[bot] Aug 17, 2026
bb00c23
fix(setup): address PR review comments for loader and tool installer
tonythethompson Aug 17, 2026
2f45c38
fix(setup): align tool name validation with leading alphanumeric and …
tonythethompson Aug 17, 2026
374029f
fix(setup_tools): prevent false suffix match in checksum filename par…
tonythethompson Aug 17, 2026
11908e6
fix(setup_tools): enforce musl libc requirements on musl linux platforms
tonythethompson Aug 17, 2026
aeeceb5
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 18, 2026
e607213
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 18, 2026
dd590fe
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 18, 2026
3ac96d5
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 18, 2026
df50da0
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 20, 2026
78b5dd2
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 20, 2026
035b251
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 22, 2026
ce87615
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 27, 2026
e6152e0
Merge branch 'master' into feature/setup-loader-tool-installer
tonythethompson Aug 27, 2026
099d4a9
Fixes verified: loader nuon parsing, path-traversal guards, Mise inst…
github-actions[bot] Aug 27, 2026
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **Enhanced `numan setup loader`**:
- Configuration isolation: separates user tool configurations into `loader-config.nu` so that updating the loader engine (`numan setup loader --force`) preserves custom tool definitions.
- Direct GitHub release binary installer: downloads prebuilt binaries for CLI tools (Starship, Zoxide, Carapace, Atuin, Mise, Direnv, Oh-My-Posh) into `$NUMAN_ROOT/tools/bin/`, verifying SHA-256 integrity when release metadata or a checksum asset is available, with `--install` / `--install-missing` and persistence to the user's `PATH`.
- Tool management flags: `--status` (inspect health, config, PATH status, and cached autoload files), `--detect` (discover PATH tools), `--add <tool>` (preset or custom), `--remove <tool>` (with cache purge), and `--clean` (invalidate cached init files).

## [0.2.2] - 2026-08-16

### Added
Expand Down
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ These workflows are covered by unit tests, hermetic integration tests, and real-

## Features

- **Registry-backed installs**: Search packages, inspect available versions, and install `owner/name` or `owner/name@version`.
- **Official registry**: `numan init` configures the `official` registry automatically. Its production trust root is built into numan, and `numan registry sync` verifies every signed index.
- **Registry-backed installs**: Search packages, inspect available versions, and install `owner/name` or `owner/name@version`.
- **Official registry**: `numan init` configures the `official` registry automatically. Its production trust root is built into numan, and `numan registry sync` verifies every signed index.
- **Package types**: Plugins and modules support activation. Scripts and completion packages are currently install-only while their activation contracts are finalized.
- **Verified artifacts**: Plugin binaries require SHA-256 hashes, and registry indexes require valid Ed25519 signatures.
- **Scoped activation**: Plugins remain active only while the Nushell executable hash, Nushell version, and plugin registry path match the recorded activation state.
- **Module autoloads**: numan writes managed vendor autoload files with ownership markers and validates candidate files before promotion.
- **Lifecycle management**: Update, remove, and garbage collection operations recover safely through lifecycle journals.
- **Shell tool integration & loader**: `numan setup loader` configures cached initialization for third-party shell CLI tools (Starship, Zoxide, Carapace, Atuin, Mise, Direnv, Oh-My-Posh), detects installed tools, isolates configurations in `loader-config.nu`, and downloads missing prebuilt binaries into `$NUMAN_ROOT/tools/bin/`.
- **nupm interoperability**: Use `numan nupm status`, `inspect`, `import`, and `diff` to inspect, migrate, and detect drift in existing [nupm](https://github.com/nushell/nupm) installations.
- **Health checks**: `numan doctor` diagnoses installation health and applies safe repairs by default. Use `--scan` for report-only mode.
- **Shell completions**: Install completions for Bash, Fish, Zsh, PowerShell, and Nushell with `numan completions` (use `--print` to emit the script).
Expand Down Expand Up @@ -353,6 +352,7 @@ Global flag: `--root <path>` — override the numan root directory (all commands
| `numan setup nu remove` | Remove the managed Nushell install and fall back to PATH Nu |
| `numan setup nu path` | Use the Nushell already on PATH (removes managed install) |
| `numan setup nu use <path>` | Register a specific existing Nushell binary |
| `numan setup loader` | Setup nushell-loader integration and third-party shell CLI tools |
| `numan use <version>` | Switch the active managed Nu to a pinned version (no auto-install; errors with a hint to run `numan setup nu <version>` if missing). Cross-minor switches deactivate Numan-active plugins/modules for the leaving Nu and restore that minor's remembered set when you switch back. |
| `numan use latest` | Switch the active managed Nu to the latest installed version (same leave/restore behavior as `use <version>`) |
| `numan use list` | List installed managed Nu versions and mark the active one |
Expand Down Expand Up @@ -380,11 +380,38 @@ Global flag: `--root <path>` — override the numan root directory (all commands
| `nupm import` | `--as owner/name` (single import); `--manifest <file>` (batch); `--nupm-home <path>`; `--yes` skip consent |
| `doctor` | `--scan` report only; `--json` machine output; `--nupm-home <path>` (repairs by default) |
| `setup nu` | `--force` re-download; `--skip-path` don't update PATH; `--yes` skip prompt |
| `setup loader` | `--status` check health/cache; `--detect` scan PATH tools; `--add <tool>` add preset/custom; `--remove <tool>` remove tool; `--clean` purge caches; `--install` / `--install-missing` download binaries; `--force` overwrite engine; `--configure` append to `config.nu` |

Run `numan <command> --help` for full flag documentation.

---

## Shell tool integration (nushell-loader)

Numan includes a high-performance loader integration based on [nushell-loader](https://github.com/aidnem/nushell-loader). It caches initialization scripts for external tools (Starship, Zoxide, Carapace, Atuin, Mise, Direnv, Oh-My-Posh) in `$nu.data-dir/vendor/autoload/`, speeding up Nushell startup.

```bash
# 1. Install loader.nu and append source snippet to config.nu
numan setup loader --configure

# 2. Detect shell tools on your PATH and register them
numan setup loader --detect

# 3. Add a tool preset (with optional binary download if missing from PATH)
numan setup loader --add starship --install
numan setup loader --add "custom=echo 'source ~/.custom.nu'"

# 4. Check status and cache files
numan setup loader --status

# 5. Clean / invalidate cached initialization scripts
numan setup loader --clean
```

Tool definitions are isolated in `loader-config.nu`, ensuring that updating the loader engine (`numan setup loader --force`) preserves your custom configuration. Binaries downloaded via `--install` or `--install-missing` are placed in `$NUMAN_ROOT/tools/bin/` and persisted to your `PATH`.

---

## nupm migration

numan can discover and import compatible packages from an existing [nupm](https://github.com/nushell/nupm) installation without modifying nupm state.
Expand Down
63 changes: 46 additions & 17 deletions assets/nushell-loader/loader.nu
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,69 @@
# Installed by `numan setup loader`. Re-run with --force to update.

let autoload_dir: path = $nu.data-dir | path join "vendor/autoload"

mkdir $autoload_dir

# Place init commands here, in the following format:
# let aidnem_loader_configs = [
# {name: 'starship', command: "starship init nu" }
# {name: 'zoxide', command: "zoxide init nushell" }
# {name: 'carapace', command: "carapace _carapace nushell"}
# ]
let aidnem_loader_configs: list<record> = []
# Load tool configuration from loader-config.nu in the same directory as loader.nu.
# Uses `open` at runtime instead of `source` so the path does not need to be a
# parse-time constant and a missing config file is handled gracefully.
let loader_config_file = ($nu.config-path | path dirname | path join 'loader-config.nu')

def _aidnem_loader_get_file_from_name [name] {
let aidnem_loader_configs: list<record> = if ($loader_config_file | path exists) {
try {
# The config is stored as nuon data in a .nu file, so read it raw and parse it.
let cfg = (open --raw $loader_config_file | from nuon)
if ($cfg | describe | str starts-with "list") {
$cfg
} else {
[]
}
} catch {
[]
}
} else {
[]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

def _aidnem_loader_get_file_from_name [name: string] {
if not ($name =~ '^[A-Za-z0-9][A-Za-z0-9_-]*$') {
Comment thread
tonythethompson marked this conversation as resolved.
error make { msg: $"Invalid loader name: '($name)'. Names must match [A-Za-z0-9][A-Za-z0-9_-]*" }
}
{ parent: $autoload_dir, stem: $name, extension: 'nu' } | path join
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

for item in $aidnem_loader_configs {
let target = _aidnem_loader_get_file_from_name $item.name
if not ($target | path exists) {
print $"[Aidnem Loader] File not found for ($item.name), generating it now."
print $"[Aidnem Loader] Running `($item.command) | save ($target)`"
nu -n -c $item.command | save $target
print $"[Aidnem Loader] Generating cache for ($item.name)..."
try {
let res = (nu -n -c $item.command | complete)
if $res.exit_code == 0 and ($res.stderr | is-empty) and not ($res.stdout | is-empty) {
$res.stdout | save -f $target
print $"[Aidnem Loader] Successfully cached ($item.name) -> ($target)"
} else {
print -e $"[Aidnem Loader] Warning: Failed to generate ($item.name) (exit code ($res.exit_code))"
if not ($res.stderr | is-empty) {
print -e $"[Aidnem Loader] ($res.stderr)"
}
}
} catch { |err|
print -e $"[Aidnem Loader] Error generating ($item.name): ($err.msg)"
}
}
}

def _aidnem_loader_completer [context: string, position: int]: nothing -> list {
$aidnem_loader_configs | get name
def _aidnem_loader_completer [context: string, position: int]: nothing -> list<string> {
$aidnem_loader_configs | get -i name | default []
}

# Remove a cached init file so that it will be regenerated on next startup.
# Configs are listed in $aidnem_loader_configs
# Configs are listed in $aidnem_loader_configs (from loader-config.nu)
def aidnem_loader_remove_file [...names: string@_aidnem_loader_completer]: nothing -> nothing {
for name in $names {
let target = _aidnem_loader_get_file_from_name $name
print $"[Aidnem Loader] Removing ($target)"
rm $target
if ($target | path exists) {
print $"[Aidnem Loader] Removing ($target)"
rm -f $target
}
}
}
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub enum Commands {
Completions(cmd::completions::CompletionsArgs),
/// Diagnose Numan root health and apply safe repairs (use `--scan` for report-only)
Doctor(cmd::doctor::DoctorArgs),
/// Install optional Nushell integration helpers
/// Manage Nushell installations and external shell CLI tool integrations
#[command(subcommand)]
Setup(cmd::setup::SetupCommands),
/// Try a package against your current Nu and platform, with compatibility guidance
Expand Down
1 change: 1 addition & 0 deletions src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod remove;
pub mod search;
pub mod self_update;
pub mod setup;
pub mod setup_tools;
pub mod snapshot;
pub mod try_cmd;
pub mod update;
Expand Down
Loading