Add nushell support#17
Conversation
Design document for adding Nushell as a first-class shell in dotrun, covering bootstrap, alias/config loading, script dispatch, completions, installation, and testing strategy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14-task implementation plan covering: script template, shell detection, multi-extension dispatch, script creation, alias/config loaders, completion system, bootstrap, installer, dev setup, reload message, documentation, test runner, and integration verification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ence Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
validate_script_name() now permits dots so dr set myscript.nu works. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ride Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rride Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove `local` keyword outside function in dr reload handler (C1) - Preserve file extension in move_script() for .nu files (I1) - Update list_feature_files_tree.sh to find both .sh and .nu scripts (I2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added Nushell-specific directory to CONTRIBUTING.md. - Updated .drrc.nu to capture environment variables from Bash. - Removed .nu script support from scripts.bats and scripts.sh. - Deleted unused .nu template and related files. - Updated README.md to reflect changes in Nushell integration. - Removed tests and configurations related to .nu files. - Adjusted dr_completion to only consider .sh files for script completion.
| } | ||
|
|
||
| # Validate a script file is executable and not a broken symlink | ||
| _validate_script_file() { |
There was a problem hiding this comment.
this function should be created before the top of the find_script_file function, since it uses is internally, and depending on the shell, it can break it to use something not yet loaded/created
| "scripts" => "🚀 Script" | ||
| "aliases" => "📝 Alias file" | ||
| "configs" => "⚙️ Config" |
There was a problem hiding this comment.
This should be just the icons, because this is supposed to append to the autocomplete filenames of the FEATURE file we are accessing, so, when we do:
dr -a <TAB>
we should se something like:
📝 01.customalias.aliases
📝 02.customalias.aliases
but with this, we would get:
📝 Alias file 01.customalias.aliases
📝 Alias file 02.customalias.aliases
| } else if ("-col" in $words) or ("collections" in $words) { | ||
| [ | ||
| {value: "add", description: "➕ Add collection"} | ||
| {value: "list", description: "📋 List collections"} | ||
| {value: "list:details", description: "📋 List with details"} | ||
| {value: "remove", description: "🗑️ Remove collection"} | ||
| {value: "set", description: "⚙️ Set collection"} | ||
| {value: "sync", description: "🔄 Sync collections"} | ||
| {value: "update", description: "⬆️ Update collections"} | ||
| ] | ||
| } else { |
There was a problem hiding this comment.
we dont have this format anywhere, but i like it
lets just make the spacing between the icon and text equal, as the Remove/Set/Update have 2_spaces instead of 1_space like the others
| } | ||
| | each {|p| | ||
| let basename = ($p | path basename) | ||
| {value: $"($prefix)($basename)/", description: "📁 Folder"} |
There was a problem hiding this comment.
This should also be something like
| {value: $"($prefix)($basename)/", description: "📁 Folder"} | |
| {value: $"($prefix)($basename)/", description: $"📁 ($basename)"} |
jvPalma-anchorage
left a comment
There was a problem hiding this comment.
Great work getting nushell integration started — the completion system is well-structured, the bats test coverage is solid, and the capture-foreign-env function is a clever approach.
There are some critical issues to address before merge (alias parsing bugs, parse-time source crashes), plus architectural alignment needed with the project spec. See inline comments below.
Key themes:
- Alias generation has parsing bugs and skips complex aliases — spec requires
bash -cwrapping for all sourcein nushell is parse-time — missing files crash the entire shell config- Architecture should follow the modular
shell/nushell/pattern (4 files) instead of the monolithic.drrc.nuapproach - Directory should be
shell/nushell/(notshell/nu/) for consistency withbash/,zsh/,fish/
Version: This adds a new shell as a first-class citizen — recommend bumping to v4.0.0 (not 3.2.0). Current master is 3.1.3, so the VERSION file will also need rebasing.
I've prepared an OpenSpec proposal (openspec/changes/add-nushell-integration/) with the full spec, design decisions, and task breakdown. Please review it for the expected architecture and requirements.
| @@ -1 +1 @@ | |||
| 3.1.2 | |||
| 3.2.0 | |||
There was a problem hiding this comment.
This is a new major feature (fourth shell as a first-class citizen), not a minor bump. Recommend v4.0.0 instead of 3.2.0.
Also, master is currently at 3.1.3 — this will conflict on rebase.
| │ │ │ ├── bash/ # Bash-specific code | ||
| │ │ │ ├── zsh/ # Zsh-specific code | ||
| │ │ │ └── fish/ # Fish-specific code | ||
| │ │ │ └── nu/ # Nushell-specific code |
There was a problem hiding this comment.
Two issues:
- The
└── fish/on the line above should become├── fish/sincenushell/follows it - Directory name should be
nushell/(notnu/) for consistency withbash/,zsh/,fish/
| @@ -0,0 +1,56 @@ | |||
| # DotRun Configuration - Nushell | |||
There was a problem hiding this comment.
Architecture: split into modular files
The project follows a pattern where each shell has its own directory under shell/<name>/ with dedicated files for configs, aliases, and completion. This file combines config loading, alias generation, and sourcing into one monolithic file placed outside the shell directory.
Requested change: Split into the modular pattern:
shell/nushell/
├── dr_config_loader.nu # Entry point (sources the others)
├── configs.nu # Parse *.config files → load-env
├── aliases.nu # Generate + source alias temp file
└── dr_completion.nu # Tab completion (already exists)
The user's config.nu would then have:
source ~/.local/share/dotrun/shell/nushell/dr_config_loader.nuSee openspec/changes/add-nushell-integration/design.md for the full design rationale.
|
|
||
| # Capture environment from the bash .drrc (the actual source of truth) | ||
| # This runs .drrc in bash and captures all env var changes. | ||
| def capture-foreign-env [ |
There was a problem hiding this comment.
capture-foreign-env — acknowledge the complexity, but harden the implementation
After reviewing the actual config files in ~/.config/dotrun/configs/, I want to correct my earlier suggestion. These are NOT simple export KEY=value files — they contain:
- Bash functions with lazy-loading patterns (e.g.,
nvm_lazy_load(), wrapper functions fornvm,node,npm,yarn) - Conditional logic based on
$CURRENT_SHELL(gcloud, fzf shell-specific integrations) source/evalcommands (cargo env, fzf--bash/--zsh)- Array operations and loops (PATH deduplication, multi-path addition)
- Shell-specific tool integrations (gcloud completion loading)
Given this complexity, running the configs through bash and capturing the resulting env vars is actually the right approach — you cannot parse these natively in nushell.
However, the implementation still needs hardening:
- Fence string (
<ENV_CAPTURE_EVAL_FENCE>) — use a UUID-like token to avoid silent corruption if any env var contains that string SCRIPT_TO_SOURCEenv var name — rename to something collision-proof like__DR_INTERNAL_EVAL_PAYLOAD__- The approach only captures env var side effects — function definitions (like nvm lazy-loaders) and completions will NOT transfer to nushell. This is an inherent limitation that should be documented.
- Shell-specific tool configs (fzf, gcloud) that check
$CURRENT_SHELLwill need nushell equivalents added by users — document this as a known limitation.
Recommendation: Keep capture-foreign-env for config loading, but move it into a dedicated configs.nu file inside shell/nushell/ rather than inlining it in .drrc.nu.
| # Runs a bash script that parses alias files and writes Nushell-compatible syntax | ||
| # to ~/.cache/dotrun/aliases.nu. Simple aliases translate directly; | ||
| # complex aliases (pipes, &&, subshells) are skipped with a comment. | ||
| ^bash ~/.local/share/dotrun/shell/nu/generate_aliases.sh |
There was a problem hiding this comment.
If generate_aliases.sh fails (bash not found, script missing, set -euo pipefail error), no error is caught. The subsequent source on line 53 will crash the shell if the file wasn't created.
At minimum, ensure the generated file always exists (even empty) regardless of script success/failure.
| echo "$INSTALL_HOME/.config/fish/config.fish" | ||
| ;; | ||
| nu) | ||
| echo "$INSTALL_HOME/.config/nushell/config.nu" |
There was a problem hiding this comment.
Hardcoded path doesn't respect $XDG_CONFIG_HOME. The installer already defines INSTALL_CFG_PATH=${XDG_CONFIG_HOME:-$HOME/.config} at line 9.
On macOS, nushell uses ~/Library/Application Support/nushell/config.nu by default.
Fix:
echo "$INSTALL_CFG_PATH/nushell/config.nu"| `dr reload` cannot modify the parent Nushell environment. Instead, run: | ||
|
|
||
| source ~/.drrc.nu | ||
|
|
There was a problem hiding this comment.
This row says aliases are "Not supported (Nushell limitation)" but the PR implements alias generation via generate_aliases.sh. The body text above correctly describes the alias system.
Fix: Update to match the implementation, e.g., "Auto-translated via bash -c wrapping".
| 1. **Dynamic aliases** — Nushell aliases must be defined at parse time, not runtime. | ||
| Define aliases directly in your `config.nu`. | ||
|
|
||
| 2. **`dr reload`** — Cannot modify parent Nushell environment from a child bash process. |
There was a problem hiding this comment.
generate_aliases.sh is missing from this Files table.
| set -euo pipefail | ||
|
|
||
| # DotRun Test Runner | ||
| # Discovers and runs all .bats test files |
There was a problem hiding this comment.
Comment says "Discovers and runs all .bats test files" but the find on line 18 only searches $SCRIPT_DIR/core. Either broaden to $SCRIPT_DIR or adjust the comment to say "under core/".
| @@ -0,0 +1,182 @@ | |||
| #!/usr/bin/env bats | |||
There was a problem hiding this comment.
Good test coverage for dr-filesystem-find (16 tests). However, there are no tests for the actual completer function nu-complete dr. Missing scenarios:
-col/collectionsnamespace returning subcommand list-s,-a,-cnamespace routing- Pattern filtering (the
pattern?parameter)
Consider adding at least a smoke test for the completer with different context strings.
jvPalma-anchorage
left a comment
There was a problem hiding this comment.
Great work getting nushell integration started — the completion system is well-structured, the bats test coverage is solid, and the capture-foreign-env function is a clever approach.
There are some critical issues to address before merge (alias parsing bugs, parse-time source crashes), plus architectural alignment needed with the project spec. See inline comments below.
Key themes:
- Alias generation has parsing bugs and skips complex aliases — spec requires
bash -cwrapping for all sourcein nushell is parse-time — missing files crash the entire shell config- Architecture should follow the modular
shell/nushell/pattern (4 files) instead of the monolithic.drrc.nuapproach - Directory should be
shell/nushell/(notshell/nu/) for consistency withbash/,zsh/,fish/
Version: This adds a new shell as a first-class citizen — recommend bumping to v4.0.0 (not 3.2.0). Current master is 3.1.3, so the VERSION file will also need rebasing.
I've prepared an OpenSpec proposal (openspec/changes/add-nushell-integration/) with the full spec, design decisions, and task breakdown. Please review it for the expected architecture and requirements.
| @@ -1 +1 @@ | |||
| 3.1.2 | |||
| 3.2.0 | |||
There was a problem hiding this comment.
This is a new major feature (fourth shell as a first-class citizen), not a minor bump. Recommend v4.0.0 instead of 3.2.0.
Also, master is currently at 3.1.3 — this will conflict on rebase.
There was a problem hiding this comment.
this is not a breaking change, according to semver it doesn't justify a major version change
| │ │ │ ├── bash/ # Bash-specific code | ||
| │ │ │ ├── zsh/ # Zsh-specific code | ||
| │ │ │ └── fish/ # Fish-specific code | ||
| │ │ │ └── nu/ # Nushell-specific code |
There was a problem hiding this comment.
Two issues:
- The
└── fish/on the line above should become├── fish/sincenushell/follows it - Directory name should be
nushell/(notnu/) for consistency withbash/,zsh/,fish/
There was a problem hiding this comment.
agree on the tree char used
but if they're named based on their executable or their short forms I think it should stay nu instead of nushell
| @@ -0,0 +1,56 @@ | |||
| # DotRun Configuration - Nushell | |||
There was a problem hiding this comment.
Architecture: split into modular files
The project follows a pattern where each shell has its own directory under shell/<name>/ with dedicated files for configs, aliases, and completion. This file combines config loading, alias generation, and sourcing into one monolithic file placed outside the shell directory.
Requested change: Split into the modular pattern:
shell/nushell/
├── dr_config_loader.nu # Entry point (sources the others)
├── configs.nu # Parse *.config files → load-env
├── aliases.nu # Generate + source alias temp file
└── dr_completion.nu # Tab completion (already exists)
The user's config.nu would then have:
source ~/.local/share/dotrun/shell/nushell/dr_config_loader.nuSee openspec/changes/add-nushell-integration/design.md for the full design rationale.
|
|
||
| # Capture environment from the bash .drrc (the actual source of truth) | ||
| # This runs .drrc in bash and captures all env var changes. | ||
| def capture-foreign-env [ |
There was a problem hiding this comment.
Replace capture-foreign-env with native config parsing
This approach (run entire bash .drrc, diff the env) is clever but fragile:
- Fence-based parsing (
<ENV_CAPTURE_EVAL_FENCE>) silently corrupts if any env var contains that string — use a UUID-like token if kept SCRIPT_TO_SOURCEenv var is visible to all code inside.drrc— name collision risk- Spawns a full bash subprocess on every shell startup
Requested change: Parse *.config files natively in nushell using load-env, matching what shell/fish/configs.sh does for fish. The config files are simple export KEY=value lines — no need to run the full bash .drrc to capture them.
| # Runs a bash script that parses alias files and writes Nushell-compatible syntax | ||
| # to ~/.cache/dotrun/aliases.nu. Simple aliases translate directly; | ||
| # complex aliases (pipes, &&, subshells) are skipped with a comment. | ||
| ^bash ~/.local/share/dotrun/shell/nu/generate_aliases.sh |
There was a problem hiding this comment.
If generate_aliases.sh fails (bash not found, script missing, set -euo pipefail error), no error is caught. The subsequent source on line 53 will crash the shell if the file wasn't created.
At minimum, ensure the generated file always exists (even empty) regardless of script success/failure.
| echo "$INSTALL_HOME/.config/fish/config.fish" | ||
| ;; | ||
| nu) | ||
| echo "$INSTALL_HOME/.config/nushell/config.nu" |
There was a problem hiding this comment.
Hardcoded path doesn't respect $XDG_CONFIG_HOME. The installer already defines INSTALL_CFG_PATH=${XDG_CONFIG_HOME:-$HOME/.config} at line 9.
On macOS, nushell uses ~/Library/Application Support/nushell/config.nu by default.
Fix:
echo "$INSTALL_CFG_PATH/nushell/config.nu"| `dr reload` cannot modify the parent Nushell environment. Instead, run: | ||
|
|
||
| source ~/.drrc.nu | ||
|
|
There was a problem hiding this comment.
This row says aliases are "Not supported (Nushell limitation)" but the PR implements alias generation via generate_aliases.sh. The body text above correctly describes the alias system.
Fix: Update to match the implementation, e.g., "Auto-translated via bash -c wrapping".
| 1. **Dynamic aliases** — Nushell aliases must be defined at parse time, not runtime. | ||
| Define aliases directly in your `config.nu`. | ||
|
|
||
| 2. **`dr reload`** — Cannot modify parent Nushell environment from a child bash process. |
There was a problem hiding this comment.
generate_aliases.sh is missing from this Files table.
| set -euo pipefail | ||
|
|
||
| # DotRun Test Runner | ||
| # Discovers and runs all .bats test files |
There was a problem hiding this comment.
Comment says "Discovers and runs all .bats test files" but the find on line 18 only searches $SCRIPT_DIR/core. Either broaden to $SCRIPT_DIR or adjust the comment to say "under core/".
| @@ -0,0 +1,182 @@ | |||
| #!/usr/bin/env bats | |||
There was a problem hiding this comment.
Good test coverage for dr-filesystem-find (16 tests). However, there are no tests for the actual completer function nu-complete dr. Missing scenarios:
-col/collectionsnamespace returning subcommand list-s,-a,-cnamespace routing- Pattern filtering (the
pattern?parameter)
Consider adding at least a smoke test for the completer with different context strings.
Description
Add Nushell as a first-class shell alongside Bash, Zsh, and Fish. This includes shell-aware
script dispatch (
.nu/.shpreference based on caller shell), POSIX alias/config parsing forNushell, a monolithic tab completion system using the unified
_dr_filesystem_findsignature,bootstrap via
~/.drrc.nu, and installer/dev setup integration.Type of Change
expected)
Testing
36 BATS tests covering script dispatch, alias/config loading, completion finder, hidden
directory pruning, and sort ordering. All passing. Nu-dependent tests auto-skip when Nushell is
not installed.