diff --git a/blog/2025-10-15-nushell_v0_108_0.md b/blog/2025-10-15-nushell_v0_108_0.md new file mode 100644 index 00000000000..6200f9fbe59 --- /dev/null +++ b/blog/2025-10-15-nushell_v0_108_0.md @@ -0,0 +1,1609 @@ +--- +title: Nushell 0.108.0 +author: The Nu Authors +author_site: https://www.nushell.sh/blog +author_image: https://www.nushell.sh/blog/images/nu_logo.png +excerpt: Today, we're releasing version 0.108.0 of Nu. This release adds an optional MCP server for AI agents, new experimental options (`pipefail` and `enforce-runtime-annotations`), smarter completions with per-command completers, clearer errors and better streaming behavior, `reorder-cell-paths` enabled by default, and stronger `CustomValue` support. +--- + +# Nushell 0.108.0 + +Today, we're releasing version 0.108.0 of Nu. This release adds an optional MCP server for AI agents, new experimental options (`pipefail` and `enforce-runtime-annotations`), smarter completions with per-command completers, clearer errors and better streaming behavior, `reorder-cell-paths` enabled by default, and stronger `CustomValue` support. + +# Where to get it + +Nu 0.108.0 is available as [pre-built binaries](https://github.com/nushell/nushell/releases/tag/0.108.0) or from [crates.io](https://crates.io/crates/nu). If you have Rust installed you can install it using `cargo install nu`. + +As part of this release, we also publish a set of optional [plugins](https://www.nushell.sh/book/plugins.html) you can install and use with Nushell. + +# Table of contents + +- [_Highlights and themes of this release_](#highlights-and-themes-of-this-release-toc) + - [_Let AI agents use Nushell commands_](#let-ai-agents-use-nushell-commands-toc) + - [_More cool experiments_](#more-cool-experiments-toc) + - [_Tab, tab, tab... Aha!_](#tab-tab-tab-aha-toc) + - [_Fish out error sources_](#fish-out-error-sources-toc) + - [_Smarter `CustomValue`s_](#smarter-customvalues-toc) +- [_Changes_](#changes-toc) + - [_Breaking changes_](#breaking-changes-toc) + - [_`into value` is now `detect type`, and `into value` now converts custom values to plain values_](#into-value-is-now-detect-type-and-into-value-now-converts-custom-values-to-plain-values-16697-toc) + - [_Collecting a stream that contains errors now raises an error itself_](#collecting-a-stream-that-contains-errors-now-raises-an-error-itself-16738-toc) + - [_Errors raised in nested `each` calls preserve their context_](#errors-raised-in-nested-each-calls-preserve-their-context-toc) + - [_Changes to `EditCommand`s_](#changes-to-editcommand-s-16841-toc) + - [_Vi Mode Text Objects_](#vi-mode-text-objects-16841-toc) + - [_Other breaking changes_](#other-breaking-changes-toc) + - [_Additions_](#additions-toc) + - [_Promoted `reorder-cell-paths` to opt-out_](#promoted-reorder-cell-paths-to-opt-out-16795-toc) + - [_Pipefail_](#pipefail-16449-toc) + - [_Enforce Assignment Type Annotations at Runtime_](#enforce-assignment-type-annotations-at-runtime-16079-toc) + - [_`--endian` flag for `format bits`_](#endian-flag-for-format-bits-16574-toc) + - [_Guess no more! More completions in built-in commands_](#guess-no-more-more-completions-in-built-in-commands-16383-toc) + - [_Simple syntax for simple completions_](#simple-syntax-for-simple-completions-16789-toc) + - [_Command-wide completion handler_](#command-wide-completion-handler-16765-toc) + - [_`for` loops no longer collect their source_](#for-loops-no-longer-collect-their-source-16593-toc) + - [_Streams of Streams_](#streams-of-streams-16735-toc) + - [_Arbitrary Pipeline Metadata_](#arbitrary-pipeline-metadata-16821-toc) + - [_HTTP Response Metadata_](#http-response-metadata-16821-toc) + - [_Add `$nu.is-lsp` to help with printing in lsp mode_](#add-nu-is-lsp-to-help-with-printing-in-lsp-mode-16635-toc) + - [_New Configuration Option: `$env.config.table.batch_duration`_](#new-configuration-option-env-config-table-batch-duration-16629-toc) + - [_New Configuration Option: `$env.config.table.stream_page_size`_](#new-configuration-option-env-config-table-stream-page-size-16629-toc) + - [_Table literal columns support variables_](#table-literal-columns-support-variables-16669-toc) + - [_Add %J and %Q format specifiers for compact date/time formatting_](#add-j-and-q-format-specifiers-for-compact-date-time-formatting-16588-toc) + - [_Add configuration for columnar menu traversal direction_](#add-configuration-for-columnar-menu-traversal-direction-16724-toc) + - [_Nushell MCP Server_](#nushell-mcp-server-16693-16758-16839-16857-toc) + - [_Add `--chars` to `str length` command_](#add-chars-to-str-length-command-16768-toc) + - [_The `to md` command now always returns valid Markdown tables_](#the-to-md-command-now-always-returns-valid-markdown-tables-16681-toc) + - [_New switches are available for `to md`_](#new-switches-are-available-for-to-md-16681-toc) + - [_`compact` your records_](#compact-your-records-16810-toc) + - [_Breaking changes_](#breaking-changes-toc) + - [_`collect` removes `source` metadata_](#collect-removes-source-metadata-16821-toc) + - [_`string`s and `glob`s can now be implicitly cast between each other_](#string-s-and-glob-s-can-now-be-implicitly-cast-between-each-other-16079-toc) + - [_Other additions_](#other-additions-toc) + - [_Other changes_](#other-changes-toc) + - [_Add `run pr` and `download pr` to `toolkit`_](#add-run-pr-and-download-pr-to-toolkit-16770-toc) + - [_Add `network` feature to top-level crate_](#add-network-feature-to-top-level-crate-16686-toc) + - [_Improved error messages for binary literals_](#improved-error-messages-for-binary-literals-16688-toc) + - [_Polars 50.1 upgrade_](#polars-50-1-upgrade-16703-toc) + - [_Additional changes_](#additional-changes-toc) + - [_Bug fixes_](#bug-fixes-toc) + - [_Aliases are now expanded before being sent to external completers_](#aliases-are-now-expanded-before-being-sent-to-external-completers-16640-toc) + - [_Discard `path add` input_](#discard-path-add-input-16606-toc) + - [_Fixed IR evaluation error caused by redirecting output of branched blocks_](#fixed-ir-evaluation-error-caused-by-redirecting-output-of-branched-blocks-16676-toc) + - [_Dotnu completion refactor, fixes path with space for both dotnu module path and external executable_](#dotnu-completion-refactor-fixes-path-with-space-for-both-dotnu-module-path-and-external-executable-16715-toc) + - [_boolean coloring in light theme_](#boolean-coloring-in-light-theme-16722-toc) + - [_changed fallback for unknown color names_](#changed-fallback-for-unknown-color-names-16722-toc) + - [_Improve collection type inference_](#improve-collection-type-inference-16530-toc) + - [_Using `break`/`continue` outside loops raises a compile error_](#using-break-continue-outside-loops-raises-a-compile-error-16740-toc) + - [_Windows device path fixes_](#windows-device-path-fixes-16775-toc) + - [_Clean up error handlers when jumping outside of `try` blocks_](#clean-up-error-handlers-when-jumping-outside-of-try-blocks-16838-toc) + - [_Other fixes_](#other-fixes-toc) +- [_Notes for plugin developers_](#notes-for-plugin-developers-toc) + - [_Allow saving `CustomValue`s_](#allow-saving-customvalue-s-16692-toc) + - [_Pass optional and casing to follow path methods for `CustomValue`_](#pass-optional-and-casing-to-follow-path-methods-for-customvalue-16736-toc) +- [_Hall of fame_](#hall-of-fame-toc) +- [_Full changelog_](#full-changelog-toc) + + +# Highlights and themes of this release [[toc](#table-of-contents)] + +## Let AI agents use Nushell commands [[toc](#table-of-contents)] + +Thanks to [@ayax79](https://github.com/ayax79), this release adds an [MCP server](https://modelcontextprotocol.io/docs/getting-started/intro) for Nushell, allowing AI agents to run Nushell commands. + +To use it, compile Nushell with the `mcp` feature (it's not included by default), then start the server with: + +```nu +nu --mcp +``` + +This is a brand new feature and will keep evolving as we refine it. +You can join the discussion on our [Discord server](https://discord.gg/NtAbbGn) in [#ai-with-nu](https://discord.com/channels/601130461678272522/1420802579155390616). + +## More cool experiments [[toc](#table-of-contents)] + +This release brings two new experimental options. +You can read more about experimental features [here](./2025-07-23-nushell_0_106_0.html#new-experimental-options-toc). + +First, `pipefail`, added by [@WindSoilder](https://github.com/WindSoilder). +When enabled, `$env.LAST_EXIT_CODE` will be set to the exit code of the rightmost command in a pipeline that exited with a non-zero status, or zero if all commands succeeded. +When used together with `$env.config.display_errors.exit_code = true`, Nushell will also report which command failed. +See some examples [here](#pipefail-16449-toc). + +Second, `enforce-runtime-annotations`, added by [@mkatychev](https://github.com/mkatychev). +When enabled, Nushell will catch errors at runtime when assigning values to type-annotated variables. +Without it, type annotations are only checked at parse time. +This helps catch tricky type errors during execution. +Read more about it [here](#enforce-assignment-type-annotations-at-runtime-16079-toc). + +We also promoted one of our experimental options from _opt-in_ to _opt-out_, so itโ€™s now enabled by default: `reorder-cell-paths`. +It improves performance by reordering how cell-paths are evaluated, making lookups faster. +If it causes any issues, you can disable it by setting `reorder-cell-paths=false` in your experimental options. +More info [here](#promoted-reorder-cell-paths-to-opt-out-16795-toc). + +[Learn how to enable experimental options.](#additions-toc) + +## Tab, tab, tab... Aha! [[toc](#table-of-contents)] + +Thanks to [@Bahex](https://github.com/Bahex), tab completion just got a lot smarter! +[A ton of built-in commands](#guess-no-more-more-completions-in-built-in-commands-16383-toc) now come with handy suggestions. +Custom commands can use [a new, easy syntax](#simple-syntax-for-simple-completions-16789-toc) to add their own completions. +And for full control, you can now pick which completer to use by [adding the `@complete` attribute](#command-wide-completion-handler-16765-toc) to your commands. + +## Fish out error sources [[toc](#table-of-contents)] + +Some errors hiding inside other commands werenโ€™t showing up quite right. +[@Bahex](https://github.com/Bahex) fixed that by making [stream collection raise an error when the stream itself contains one](#collecting-a-stream-that-contains-errors-now-raises-an-error-itself-16738-toc). +Errors inside `each` calls also now [keep their full context](#errors-raised-in-nested-each-calls-preserve-their-context-toc), making it easier to track down what went wrong. + +## Smarter `CustomValue`s [[toc](#table-of-contents)] + +`CustomValue`s let plugin authors introduce their own data types without being limited to Nushell's built-in `Value`s. +Until now, though, they often lagged behind in functionality. +Thanks to [@cptpiepmatz](https://github.com/cptpiepmatz), theyโ€™re now much closer to behaving like regular `Value`s. + +They now support both the `$value!` syntax added by [@Bahex](https://github.com/Bahex) in [0.105.0](./2025-06-10-nushell_0_105_0.html#case-sensitive-cell-paths-or-not-toc) and the older `$value?` syntax. +Plugin authors can now decide exactly how these should behave for their custom types. + +On top of that, `CustomValue`s now work with the `save` command. +Plugin authors can define how their custom data should be saved, which is often more complex than for built-in types. + +See the [notes for plugin developers](#notes-for-plugin-developers-toc) for more details. + +# Changes [[toc](#table-of-contents)] + +## Breaking changes [[toc](#table-of-contents)] + +### `into value` is now `detect type`, and `into value` now converts custom values to plain values ([#16697]) [[toc](#table-of-contents)] + +Until 0.107, `into value` tried to detect the types of table cells. It converted strings into typed values, which is where the name came from. But it didn't match the purpose of the other `into` commands. +This command is now called `detect type` but it doesn't operate on cells anymore, so you have to call `update cells {detect type}` to use that functionality again. With that we can also use that command on non-table types to try to infer the types. +The `into value` name is now used for converting custom values from plugins into native Nushell values. + +The `table` command already showed the base Nushell value: + +```ansi:no-line-numbers +> custom-value generate | table +I used to be a custom value! My data was (abc) + +> custom-value generate | describe +CoolCustomValue + +> custom-value generate | into value | describe +string +``` + +### Collecting a stream that contains errors now raises an error itself ([#16738]) [[toc](#table-of-contents)] + +Previously, if an error was returned as a stream item and you collected that stream into a value, you would and up with a list that has an `error` item which you wouldn't know about until you interacted with that specific item. + +You could even end up with a list entirely made up of `error`s: + +```nushell +let items = 1..10 | each {|n| error make { msg: $"Error ($n)" } } +items | describe +# list +``` + +With this release that's no longer the case: + +```nushell +let items = 1..10 | each {|n| error make { msg: $"Error ($n)" } } +``` + +```ansi:no-line-numbers +Error: nu::shell::eval_block_with_input + + ร— Eval block failed with pipeline input + โ•ญโ”€[entry #4:1:13] + 1 โ”‚ let items = 1..10 | each {|n| error make { msg: $"Error ($n)" } } + ยท  โ”€โ”€โ”ฌโ”€โ”€ + ยท โ•ฐโ”€โ”€ source value + โ•ฐโ”€โ”€โ”€โ”€ + +Error: + ร— Error 1 + โ•ญโ”€[entry #4:1:31] + 1 โ”‚ let items = 1..10 | each {|n| error make { msg: $"Error ($n)" } } + ยท  โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ originates from here + โ•ฐโ”€โ”€โ”€โ”€ +``` + +Simply attempting to collect such a stream immediately re-throws the first error encountered. + +This also has the effect of preserving the context of errors raised some nested command calls like... + +### Errors raised in nested `each` calls preserve their context [[toc](#table-of-contents)] + +Previously, errors raised in nested `each` calls (and other commands that returned streams) could lose their outer/caller context. + +If the closure returned a stream, errors in the stream were not properly chained and lost this context. Running the following code: + +```nushell +0..1 | each { + 0..1 | each {|e| + error make {msg: boom} + } +} +``` + +we get: + +```ansi:no-line-numbers title="Before" +Error: nu::shell::eval_block_with_input + + ร— Eval block failed with pipeline input + โ•ญโ”€[source:2:2] + 1 โ”‚ 0..1 | each { + 2 โ”‚ 0..1 | each {|e| + ยท  โ”€โ”€โ”ฌโ”€ + ยท โ•ฐโ”€โ”€ source value + 3 โ”‚ error make {msg: boom} + โ•ฐโ”€โ”€โ”€โ”€ + +Error: + ร— boom + โ•ญโ”€[source:3:3] + 2 โ”‚ 0..1 | each {|e| + 3 โ”‚ error make {msg: boom} + ยท  โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ originates from here + 4 โ”‚ } + โ•ฐโ”€โ”€โ”€โ”€ +``` + +```ansi:no-line-numbers title="After" +Error: nu::shell::eval_block_with_input + + ร— Eval block failed with pipeline input + โ•ญโ”€[source:1:1] + 1 โ”‚ 0..1 | each { + ยท โ”€โ”€โ”ฌโ”€ + ยท โ•ฐโ”€โ”€ source value + 2 โ”‚ 0..1 | each {|e| + โ•ฐโ”€โ”€โ”€โ”€ + +Error: nu::shell::eval_block_with_input + + ร— Eval block failed with pipeline input + โ•ญโ”€[source:2:2] + 1 โ”‚ 0..1 | each { + 2 โ”‚ 0..1 | each {|e| + ยท  โ”€โ”€โ”ฌโ”€ + ยท โ•ฐโ”€โ”€ source value + 3 โ”‚ error make {msg: boom} + โ•ฐโ”€โ”€โ”€โ”€ + +Error: + ร— boom + โ•ญโ”€[source:3:3] + 2 โ”‚ 0..1 | each {|e| + 3 โ”‚ error make {msg: boom} + ยท  โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ originates from here + 4 โ”‚ } + โ•ฐโ”€โ”€โ”€โ”€ +``` + +### Changes to `EditCommand`s ([#16841]) [[toc](#table-of-contents)] + +- renamed `cutinside` to `cutinsidepair` +- renamed `yankinside` to `copyinsidepair` +- added `cutaroundpair` +- added `copyaroundpair` +- added `cuttextobject` +- added `copytextobject` + +### Vi Mode Text Objects ([#16841]) [[toc](#table-of-contents)] + +Vi mode now supports inner and around (`i` and `a`) text objects for: + +- word, bound to `w` (a sequence of letters, digits and underscores, separated with white space) +- WORD, bound to `W` (a sequence of non-blank characters, separated with white space) +- brackets, bound to `b` (any of `( )`, `[ ]`, `{ }`) +- quotes, bound to `q` (any of `" "`, `' '`, ` `` `) + +Existing "pair" motions for specific matching pairs (e.g. `di(` or `ci"`) are also extended to support "around" versions (e.g. `da(` or `ca"`) that cover the pair characters. + +Additionally, the pair motions will now jump to the next pair if non are found within search range. + +- For _symmetric pairs_ like quotes, searching is restricted to the current line. +- For _asymmetric pairs_ like brackets, search is multi-line across the whole buffer. + +Symmetric pairs search does not do any parsing or matching of pairs based on language/groupings. +It simply searches for the previous and next matching characters. + +### Other breaking changes [[toc](#table-of-contents)] + +- The LSP session is no longer marked as interactive (`$nu.is-interactive == false`) ([#16580]) + +- The Polars plugin's value types are renamed to be prefixed with `polars_` (e.g. polars_dataframe) ([#16819]) + +## Additions [[toc](#table-of-contents)] + +::: tip Experimental Options + +Opt-in experimental options can be enabled and opt-out options can disabled using the command-line argument: + +```nushell +nu --experimental-options '[foo,bar=false]' +``` + +or the environment variable: + +```nushell +NU_EXPERIMENTAL_OPTIONS="foo,bar=false" nu +``` + +Or if you're feeling adventurous you can enable all of them with `all` + +```nushell +nu --experimental-options '[all]' +NU_EXPERIMENTAL_OPTIONS="all" nu +``` + +::: + +### Promoted `reorder-cell-paths` to opt-out ([#16795]) [[toc](#table-of-contents)] + +In Nushell 0.106.0, [experimental options](https://www.nushell.sh/blog/2025-07-23-nushell_0_106_0.html#experimental-options-toc) were added, first of which is [`reorder-cell-paths`](https://github.com/nushell/nushell/issues/16766). With this release `reorder-cell-paths` is promoted to being opt-out, meaning that by default this experimental option is enabled now. + +This option improves cell-path accesses by reordering how the cell-path should be evaluated without modifying the output in any way. + +If you experience any trouble with this, you can disable it via passing `reorder-cell-paths=false` via the command-line argument or environment variable. + +### Pipefail ([#16449]) [[toc](#table-of-contents)] + +This release adds a new experimental option: `pipefail`. + +When enabled, `$env.LAST_EXIT_CODE` will be set to the exit code of rightmost command in the pipeline which exit with a non-zero status, or zero if all commands in the pipeline exit successfully. + +```nushell +> ^false | print aa +aa +> $env.LAST_EXIT_CODE +1 +``` + +Using it together with `$env.config.display_errors.exit_code = true` will report the command that failed: + +```nushell +> $env.config.display_errors.exit_code = true +> ^ls | ^false | print aa +aa +``` + +```ansi:no-line-numbers +aa +Error: nu::shell::non_zero_exit_code + + ร— External command had a non-zero exit code + โ•ญโ”€[entry #3:1:8] + 1 โ”‚ ^ls | ^false | print aa + ยท  โ”€โ”€โ”ฌโ”€โ”€ + ยท โ•ฐโ”€โ”€ exited with code 1 + โ•ฐโ”€โ”€โ”€โ”€ +``` + +### Enforce Assignment Type Annotations at Runtime ([#16079]) [[toc](#table-of-contents)] + +Nushell is perfectly capable of catching type errors at parse time... + +```nushell +let table1: table = [{a: "foo"}] +let table2: table = $table1 +``` + +```ansi:no-line-numbers +Error: nu::parser::type_mismatch + + ร— Type mismatch. + โ•ญโ”€[entry #1:2:32] + 1 โ”‚ let table1: table = [{a: "foo"}] + 2 โ”‚ let table2: table = $table1 + ยท  โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ expected table, found table + โ•ฐโ”€โ”€โ”€โ”€ +``` + +But only if the relevant types are known at parse time. + +```nushell +let table1: table = ({a: 1} | into record | to nuon | from nuon); +let table2: table = $table1 +# * crickets * +``` + +Which can lead to some unexpected results: + +```nushell +let x: table = ({a: 1} | to nuon | from nuon) +$x | describe +# record +``` + +This release adds a new experimental option: [`enforce-runtime-annotations`](https://github.com/nushell/nushell/issues/16832) + +When it's enabled, nushell can catch this class of type errors at runtime, and throw a `cant_convert` error: + +```ansi:no-line-numbers +Error: nu::shell::cant_convert + + ร— Can't convert to table. + โ•ญโ”€[entry #9:1:56] + 1 โ”‚ let table1: table = ({a: 1} | into record | to nuon | from nuon); + ยท  โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ can't convert record to table + 2 โ”‚ let table2: table = $table1 + โ•ฐโ”€โ”€โ”€โ”€ +``` + +This would be a breaking change for scripts where `any` coercion/conversions previously ignored field constraints for records and tables, which is why it's being phased in with an experimental option. + +
Examples + +```nushell title="enforce-runtime-annotations=false" +mut a: record = {b:1}; $a.b += 3; $a.b -= 2; $a.b *= 10; $a.b /= 4; $a.b +# 5.0 +``` + +```nushell title="enforce-runtime-annotations=true" +mut a: record = {b:1} +$a.b += 3 +$a.b -= 2 +$a.b *= 10 +$a.b /= 4 +$a.b +``` + +```ansi:no-line-numbers +Error: nu::shell::cant_convert + + ร— Can't convert to record. + โ•ญโ”€[entry #1:5:1] + 4 โ”‚ $a.b *= 10 + 5 โ”‚ $a.b /= 4 + ยท โ”€โ”ฌ + ยท โ•ฐโ”€โ”€ can't convert record to record + 6 โ”‚ $a.b + โ•ฐโ”€โ”€โ”€โ”€ +``` + +--- + +```nushell title="enforce-runtime-annotations=false" +let x: record = ({a: 1} | to nuon | from nuon) +$x | describe +# record +``` + +```nushell title="enforce-runtime-annotations=true" +let x: record = ({a: 1} | to nuon | from nuon) +$x | describe +``` + +```ansi:no-line-numbers +Error: nu::shell::cant_convert + + ร— Can't convert to record. + โ•ญโ”€[entry #2:1:45] + 1 โ”‚ let x: record = ({a: 1} | to nuon | from nuon) + ยท  โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ can't convert record to record + 2 โ”‚ $x | describe + โ•ฐโ”€โ”€โ”€โ”€ +``` + +
+ +### `--endian` flag for `format bits` ([#16574]) [[toc](#table-of-contents)] + +`format bits` used to output in native endian, until Nu 0.107.0 (#16435) changed it to big endian. Now, you will be able to choose the behavior with `--endian` (use `format bits --endian native` to get the original behavior from before Nu 0.107.0). + +```nushell +~> 258 | format bits +00000001 00000010 +``` + +```nushell +~> 258 | format bits --endian little # (or `--endian native` in a little endian system) +00000010 00000001 +``` + +### Guess no more! More completions in built-in commands ([#16383]) [[toc](#table-of-contents)] + +Thanks to some recent improvements behind the scenes, nushell built-in commands that expect a specific set of values now suggests these values. + +The following commands now have suggestions: + +- `random uuid --version <...> --namespace <...>` +- `into int --endian <...>` +- `into duration --unit <...>` +- `into datetime --timezone <...>` +- `histogram --percentage-type <...>` +- `http* --redirect-mode <...>` +- `fill --alignment <...>` +- `cal --week-start <...>` +- `date to-timezone <...>` +- `attr deprecated --report <...>` +- `merge deep --strategy <...>` +- `from csv`, `from tsv`: `--trim <...>` +- `table --theme <...>` +- `split list --split <...>` + +### Simple syntax for simple completions ([#16789]) [[toc](#table-of-contents)] + +Custom completions are powerful, able to provide dynamic completions based on what's written on the command line so far. + +But you don't always need that power. In fact, for most cases a simple static list of options is enough. + +To make it simpler and more concise to meet this need, this release adds a new way to define completions for command parameters: + +```ansi:no-line-numbers +def go [ + direction: string@[ left up right down ] +] { + $direction +} +``` + +Completions can be provided as a list of strings inline in the command signature, or stored in a `const` variable and used like that. + +```ansi:no-line-numbers +const directions = [ left up right down ] + +def go [ direction: string@$directions ] { + $direction +} +``` + +### Command-wide completion handler ([#16765]) [[toc](#table-of-contents)] + +There is big difference between custom completions that can be specified in a command's signature, and the "global" external completer (`$env.config.completions.external.completer`). + +The former is added to individual parameters, while the latter provides completions for all arguments of (external) commands. + +This makes using custom commands that wrap external commands awkward. The global external completer won't provide completions for the wrapper command and adding completions to that command uses a completely different API. It would be nice to be able to use the external completer's API for custom completions, or use the external completer for wrapper commands... + +#### `@complete external` + +Now it's possible to explicitly enable the global external completer for `extern` and custom command `def`initions: + +```nushell +@complete external +def --wrapped jc [...args] { + ^jc ...$args | from json +} +``` + +#### `@complete ` + +Instead of using the external completer, command-wide custom completers can be used for specific commands: + +```nushell +def carapace-completer [spans: list] { + ^carapace .. +} + +@complete carapace-completer +def --env get-env [name] { $env | get $name } + +@complete carapace-completer +def --env set-env [name, value] { load-env { $name: $value } } + +@complete carapace-completer +def --env unset-env [name] { hide-env $name } +``` + +Combined with `extern` definitions, this makes it trivial to use specific completion sources for specific commands: + +```nushell +def fish-completer [spans: list] { + ^fish .. +} + +@complete fish-completer +extern git [] + +@complete fish-completer +extern asdf [] +``` + +Yes, you can remove the `match` expression from your external completer! + +```nushell +{|spans: list| + + # ... + + # no need for this anymore! + match $spans.0 { + # fish completes commits and branch names in a nicer way + git => $fish_completer + # carapace doesn't have completions for asdf + asdf => $fish_completer + _ => $carapace_completer + } | do $in $spans +``` + +
+ Full implementation of fish-completer from the cookbook. + +```nushell +def fish-completer [spans: list] { + ^fish --command $"complete '--do-complete=($spans | str replace --all "'" "\\'" | str join ' ')'" + | from tsv --flexible --noheaders --no-infer + | rename value description + | update value {|row| + let value = $row.value + let need_quote = ['\' ',' '[' ']' '(' ')' ' ' '\t' "'" '"' "`"] | any { $in in $value } + if ($need_quote and ($value | path exists)) { + let expanded_path = if ($value starts-with ~) { $value | path expand --no-symlink } else { $value } + $'"($expanded_path | str replace --all "\"" "\\\"")"' + } else { $value } + } +} +``` + +
+ +### `for` loops no longer collect their source ([#16593]) [[toc](#table-of-contents)] + +Previously, `for` loops only worked with values (ranges, lists, etc), so using them with streaming commands would collect the whole stream before iteration could start. Now it also works with streams too! + +This makes it possible to use it with slow or unbounded streams: + +```nushell +for event in (watch . --glob=**/*.rs) { + cargo test +} +``` + +### Streams of Streams ([#16735]) [[toc](#table-of-contents)] + +When you run `each` over a list (or stream), it can only return a single item for each input. When we need to create multiple values from a single input, we can just return a list in the closure and run the output through `flatten`. + +```nushell +each { .. } | flatten +``` + +When the closure itself generates a _stream_ however, that pattern can be inadequate, as the stream has to be collected into a list, just to be flattened afterwards. This might increase memory usage, and result in unnecessary waits. + +To address this, `each` has a new flag: `--flatten` + +`each --flatten` does not wait to collect closure output to ensure returning a single output item for each input, instead the stream from the closure is directly passed through. Here's a demonstration of differences: + + + + + + + + + + + + +
+ +```nushell:title="each | flatten" +def slow-source [range: range] { + $range | each {|e| sleep 0.1sec; $e } +} + +0..5..<25 +| each {|e| slow-source ($e)..<($e + 5) } +| flatten +| each {|e| print $e; $e} +| ignore +``` + + + +```nushell:title="each --flatten" +# +def slow-source [range: range] { + $range | each {|e| sleep 0.1sec; $e } +} + +0..5..<25 +| each --flatten {|e| slow-source ($e)..<($e + 5) } +| each {|e| print $e; $e} +| ignore +``` + +
+ +![each then flatten](https://gist.githubusercontent.com/Bahex/50beec0aaf82671d55f23feda65dca27/raw/690cdbe49d761d8a8f0886451868cd16fe275184/pr_16735_old.nu.cast.svg) + + + +![each --flatten](https://gist.githubusercontent.com/Bahex/50beec0aaf82671d55f23feda65dca27/raw/690cdbe49d761d8a8f0886451868cd16fe275184/pr_16735_new.nu.cast.svg) + +
+ +### Arbitrary Pipeline Metadata ([#16821]) [[toc](#table-of-contents)] + +In addition to existing metadata fields (`content_type`, `source`, `span`), it's now possible to attach arbitrary metadata fields to pipeline data using `metadata set --merge`: + +```nushell +"data" | metadata set --merge {custom_key: "value"} | metadata | get custom_key +``` + +Combined with `metadata access`, this makes it possible to carry extra data with streams, without impacting the stream data itself. + +### HTTP Response Metadata ([#16821]) [[toc](#table-of-contents)] + +All `http` commands now attach response data (previously only accessible with `http * --full`) as metadata to their output streams. This can be accessed under the `http_response` field within the pipeline metadata: + +- `status` - HTTP status code +- `headers` - Response headers as `[{name, value}, ...]` +- `urls` - Redirect history + +Accessing this metadata after the response completes may not offer much benefit. + +```nushell +http get https://api.example.com | metadata | get http_response.status +# => 200 +``` + +Where it shines is accessing it _alongside_ the streaming response body using `metadata access`: + +```nushell +http get --allow-errors https://api.example.com/events.jsonl +| metadata access {|meta| + if $meta.http_response.status != 200 { + error make {msg: "failed"} + } else { } + } +| lines +| each { from json } +| where event_type == "error" +``` + +### Add `$nu.is-lsp` to help with printing in lsp mode ([#16635]) [[toc](#table-of-contents)] + +When nushell is launched with the `--lsp` flag, nushell will set `$nu.is-lsp` to true so that users can programmatically know when nushell is in LSP mode. + +When in LSP mode, the `print` command will only print to stderr. This is done to prevent the LSP from misbehaving when it sees text that isn't JSON-RPC in stdout, which is being listened to by the LSP. + +### New Configuration Option: `$env.config.table.batch_duration` ([#16629]) [[toc](#table-of-contents)] + +It is now possible to configure the batch duration for the `table` command. + +The `table` command (and by proxy the default pipeline output) handles streaming in batches to avoid long wait times until any data is visible. With the `$env.config.table.batch_duration` option, it is now possible to define this time it will collect a batch. This is by default 1 second as it was previously a hard-coded value. + +Default setting and previous output: + +```nushell +1..=6 | each {|i| sleep 1sec; $i | into string | $"after ($in) sec"} +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 0 โ”‚ after 1 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 1 โ”‚ after 2 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 2 โ”‚ after 3 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 3 โ”‚ after 4 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 4 โ”‚ after 5 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 5 โ”‚ after 6 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +Configured to wait for two seconds: + +```nushell +$env.config.table.batch_duration = 2sec +1..=6 | each {|i| sleep 1sec; $i | into string | $"after ($in) sec"} +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 0 โ”‚ after 1 sec โ”‚ +# โ”‚ 1 โ”‚ after 2 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 2 โ”‚ after 3 sec โ”‚ +# โ”‚ 3 โ”‚ after 4 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 4 โ”‚ after 5 sec โ”‚ +# โ”‚ 5 โ”‚ after 6 sec โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +### New Configuration Option: `$env.config.table.stream_page_size` ([#16629]) [[toc](#table-of-contents)] + +It is now possible to configure the maximum page size of streamed data in the `table` command. + +The `table` command (and by proxy the default pipeline output) chunks streamed data into separate tables according to the stream page size which can now be set via `$env.config.table.stream_page_size`. By default it's 1000, so (if fast enough) it will collect 1000 entries into a single table and then start a new table. + +Default setting and previous output: + +```nushell +1..4 | each {"item " + ($in | into string)} +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 0 โ”‚ item 1 โ”‚ +# โ”‚ 1 โ”‚ item 2 โ”‚ +# โ”‚ 2 โ”‚ item 3 โ”‚ +# โ”‚ 3 โ”‚ item 4 โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +Configured to page at maximum 2 entries: + +```nushell +$env.config.table.stream_page_size = 2 +1..4 | each {"item " + ($in | into string)} +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 0 โ”‚ item 1 โ”‚ +# โ”‚ 1 โ”‚ item 2 โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ 2 โ”‚ item 3 โ”‚ +# โ”‚ 3 โ”‚ item 4 โ”‚ +# โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +### Table literal columns support variables ([#16669]) [[toc](#table-of-contents)] + +Table literals can now have variables in the column names list. For example, this is now allowed: + +```ansi:no-line-numbers +> let column_name = 'column0' +[[ $column_name column1 ]; + [ foo bar ] + [ baz car ] + [ far fit ]] +โ•ญโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +โ”‚ # โ”‚ column0 โ”‚ column1 โ”‚ +โ”œโ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 0 โ”‚ foo โ”‚ bar โ”‚ +โ”‚ 1 โ”‚ baz โ”‚ car โ”‚ +โ”‚ 2 โ”‚ far โ”‚ fit โ”‚ +โ•ฐโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +### Add %J and %Q format specifiers for compact date/time formatting ([#16588]) [[toc](#table-of-contents)] + +The `format date` and `into datetime` commands now support two new format specifiers for creating compact, sortable date and time components: + +- **%J** produces compact dates in `YYYYMMDD` format (e.g., `20250918`) +- **%Q** produces compact times in `HHMMSS` format (e.g., `131144`) + +These can be used individually for date-only or time-only formatting, or combined for full timestamps (`%J_%Q` produces `20250918_131144`), providing more flexibility than a single combined format. + +Perfect for: + +- Backup file naming with custom separators +- Log file timestamps with flexible formatting +- Date-only or time-only compact representations +- Any scenario requiring sortable, human-readable date/time components + +Both commands use the same format specifications, ensuring consistency when parsing and formatting dates. + +This addition is fully backward compatible - all existing format specifiers continue to work unchanged. + +### Add configuration for columnar menu traversal direction ([#16724]) [[toc](#table-of-contents)] + +The feature makes it possible to choose the direction that items are placed in the columnar menu. With the default value of `"horizontal"`, items are ordered left-to-right in each row, with later items appearing in rows below earlier items. + +``` +1 2 3 4 +5 6 7 8 +9 10 +``` + +With the value set to `"vertical"`, items are ordered top-to-bottom in each column, with later items appearing in columns to the right of earlier items. + +``` +1 4 7 10 +2 5 8 +3 6 9 +``` + +The configuration option is currently called "tab_traversal" with a default value of "horizontal". + +In order to toggle horizontal or vertical, add or update the completion_menu in your config.nu + +```nushell +# Example - Completion menu configuration +$env.config.menus ++= [{ + name: completion_menu + only_buffer_difference: false # Search is done on the text written after activating the menu + marker: "| " # Indicator that appears with the menu is active + type: { + layout: columnar # Type of menu + columns: 4 # Number of columns where the options are displayed + col_width: 20 # Optional value. If missing all the screen width is used to calculate column width + col_padding: 2 # Padding between columns + tab_traversal: "horizontal" # Direction in which pressing will cycle through options, "horizontal" or "vertical" + } + style: { + text: green # Text style + selected_text: green_reverse # Text style for selected option + description_text: yellow # Text style for description + } +}] +``` + +### Nushell MCP Server ([#16693], [#16758], [#16839], [#16857]) [[toc](#table-of-contents)] + +When compiled with the "mcp" feature (not a part of the default feature set), the nushell binary can be used as a local (stdio) MCP server. + +To start the nushell MCP server + +```nu +nu --mcp +``` + +This will allow a local AI agent to use MCP to execute native nushell commands and external commands. + +### Add `--chars` to `str length` command ([#16768]) [[toc](#table-of-contents)] + +The `str length` command now has a `--chars` flag to allow you to count characters. + +```nushell +> 'hรคllo' | str length --chars + 5 +``` + +### The `to md` command now always returns valid Markdown tables ([#16681]) [[toc](#table-of-contents)] + +Previously, a command like this: + +```shell +> [['foo' 'bar']; ['1 | 2' 'a | b']] | to md +|foo|bar| +|-|-| +|1 | 2|a | b| +``` + +would generate an invalid table, since the `|` characters inside the cell content were not escaped. + +Now, such special characters are automatically escaped, ensuring the output always follows proper Markdown table syntax: + +```shell +> [['foo' 'bar']; ['1 | 2' 'a | b']] | to md +| foo | bar | +| --- | --- | +| 1 \| 2 | a \| b | +``` + +### New switches are available for `to md` ([#16681]) [[toc](#table-of-contents)] + +- `--escape-md` | `-m` escape all Markdown special characters +- `--escape-html` | `-t` escape HTML special characters +- `--escape-all` | `-a` escape both HTML and Markdown + +### `compact` your records ([#16810]) [[toc](#table-of-contents)] + +`compact` can now be used to remove `null` or `--empty` items from records too. + +### Breaking changes [[toc](#table-of-contents)] + +### `collect` removes `source` metadata ([#16821]) [[toc](#table-of-contents)] + +`collect` now removes `source` metadata field even when `content_type` is set. +Previously: both were preserved, now only `content_type` is preserved. + +### `string`s and `glob`s can now be implicitly cast between each other ([#16079]) [[toc](#table-of-contents)] + +Previously `string` types were not able to be coerced into `glob` types (and vice versa). +They are now subtypes of each other. + +Before: + +```nushell +> def spam [foo: glob] { echo $foo }; let f = 'aa'; spam $f +Error: nu::shell::cant_convert + + ร— Can't convert to glob. + โ•ญโ”€[entry #109:1:56] + 1 โ”‚ def spam [foo: glob] { echo $foo }; let f = 'aa'; spam $f + ยท โ”€โ”ฌ + ยท โ•ฐโ”€โ”€ can't convert string to glob + โ•ฐโ”€โ”€โ”€โ”€ +``` + +Now: + +```nushell +> def spam [foo: glob] { echo $foo }; let f = 'aa'; spam $f +aa +``` + +### Other additions [[toc](#table-of-contents)] + +- Added support for exabyte and exbibyte filesize format. ([#16689]) + +- Experimental options now provide two new fields `since` and `issue` which refer to when the experimental option was introduced and an issue on Github that tracks the status of that issue. You can see them via `debug experimental-options`. ([#16142]) + +- New operators: `not-starts-with` and `not-ends-with`. Added for parity with other comparison operators. ([#16852]) + +- Added file completions for command redirections (`o>>`, `e>`, ...) ([#16831]) + +## Other changes [[toc](#table-of-contents)] + +### Add `run pr` and `download pr` to `toolkit` ([#16770]) [[toc](#table-of-contents)] + +The toolkit in the Nushell repository can now download and run PRs by downloading artifacts from CI runs. It can be run like this: + +```nushell +use toolkit +toolkit run pr +``` + +### Add `network` feature to top-level crate ([#16686]) [[toc](#table-of-contents)] + +Nushell can now be compiled without network related commands. + +If you are manually building Nushell without default features (`cargo build --no-default-features`) you will now need to pass `--features network` to get access the network commands. + +### Improved error messages for binary literals ([#16688]) [[toc](#table-of-contents)] + +Previously, a generic shell error is thrown for invalid binary strings. Now, an improve error message is thrown for invalid binary, hexadecimal, and octal strings. + +```nushell +0b[121] +``` + +```ansi:no-line-numbers +Error: nu::parser::invalid_binary_string + + ร— Invalid binary string. + โ•ญโ”€[entry #3:1:1] + 1 โ”‚ 0b[121] + ยท โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€ + ยท โ•ฐโ”€โ”€ invalid binary string + โ•ฐโ”€โ”€โ”€โ”€ + help: binary strings may contain only 0 or 1. +``` + +### Polars 50.1 upgrade ([#16703]) [[toc](#table-of-contents)] + +- `polars fetch` has been removed due to no longer being supported on LazyFrame +- introduced flag `--drop-nulls` to `polars dummies` +- introduced flag `--separator` to `polars dummies` +- introduced flag `--strict` to `polars integer` +- introduced flag `--base` to `polars integer` +- introduced flag `--dtype` to `polars integer` +- introduced flag `--stable` to `polars pivot` +- polars pivot will no longer perform a stable pivot by default, the flag `--stable` must be passed in to perform a stable pivot. +- Introduced flag `--time-zone` to `polars as-datetime` +- Introduced flag `--time-unit` to `polars as-datetime` + +### Additional changes [[toc](#table-of-contents)] + +- The `which` command now lists all commands (internal and external) when no argument is passed to it ([#16551]) + +## Bug fixes [[toc](#table-of-contents)] + +### Aliases are now expanded before being sent to external completers ([#16640]) [[toc](#table-of-contents)] + +Before this change, when an external completer was invoked for an alias, the first argument sent to the completer would be the alias itself instead of the aliased command. + +For example, with an alias defined as `alias gl = git log`, typing `gl branch_name` and pressing `TAB` would send the arguments `gl`, `log`, `branch_name` to the external completer. + +After this change, the alias is expanded and the arguments sent to the external completer will be `git`, `log`, `branch_name`. + +### Discard `path add` input ([#16606]) [[toc](#table-of-contents)] + +Previously `path add` (from `std/util`) could fail if it was fed `any` input. + +```ansi:no-line-numbers +> use std/util 'path add' +> ls | each {} | path add +Error: nu::shell::incompatible_parameters + + ร— Incompatible parameters. + โ•ญโ”€[std/util/mod.nu:18:17] + 17 โ”‚ ]: [nothing -> nothing, nothing -> list] { + 18 โ”‚ let span = (metadata $paths).span + ยท  โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€ โ”€โ”€โ”€โ”ฌโ”€โ”€ + ยท โ”‚ โ•ฐโ”€โ”€ but a positional metadata expression was also given + ยท โ•ฐโ”€โ”€ pipeline input was provided + 19 โ”‚ let paths = $paths | flatten + โ•ฐโ”€โ”€โ”€โ”€ +``` + +Now any input to `path add` will be discarded. It's still possible to pass it with `$in`: + +```nushell +[a b c] | each {|p| $env.HOME | path join $p } | path add $in +``` + +### Fixed IR evaluation error caused by redirecting output of branched blocks ([#16676]) [[toc](#table-of-contents)] + +The following commands will no longer raise ir-eval errors: + +- `if true { echo "hey" } out> /dev/null` +- `if false { echo "hey" } else { echo "ho" } out> /dev/null` +- `try { 1/0 } catch { echo "hi" } out> /dev/null` + +### Dotnu completion refactor, fixes path with space for both dotnu module path and external executable ([#16715]) [[toc](#table-of-contents)] + +Module path completion for command `use`/`source` now behaviors in the same manner of basic file completion, which is less error prone when dealing with paths with spaces or other special characters. + +Fixed the bug of empty result of external executable path completion at the head of a pipeline when the path prefix contains spaces. + +### boolean coloring in light theme ([#16722]) [[toc](#table-of-contents)] + +When using `std/config light-theme`, booleans inside structures are now colored in dark cyan instead of white, which was very hard to read in combination with a light terminal background. + +### changed fallback for unknown color names ([#16722]) [[toc](#table-of-contents)] + +If some named color in `$env.config.color_config` is misspelled or otherwise unknown to nu, the corresponding element is now colored using the terminal's default (as in `ansi reset`) instead of white. + +### Improve collection type inference ([#16530]) [[toc](#table-of-contents)] + +Fixes order-dependent table type inference bugs and introduces similar type widening for lists: + +```nushell +def get_type [] { scope variables | where name == "$foo" | first | get type } + +let foo = [ [bar]; [ { baz: 1 } ], [ { baz: 1, extra: true } ] ] +get_type # table> -> table> + +let foo = [ [bar]; [ { baz: 1, extra: true } ], [ { baz: 1 } ] ] +get_type # table -> table> + +let foo = [ { baz: 1 }, { baz: 1, extra: true } ] +get_type # list -> list> +``` + +### Using `break`/`continue` outside loops raises a compile error ([#16740]) [[toc](#table-of-contents)] + +Previously this error wasn't caught during compilation, and manifested as a runtime error when the execution reached the invalid `break`/`continue` call. + +```ansi:no-line-numbers title="Before" +> let fn = { break } +> do $fn +Tried to execute 'run' for the 'break' command: this code path should never be reached in IR mode +Error: ร— Main thread panicked. + โ”œโ”€โ–ถ at crates/nu-cmd-lang/src/core_commands/break_.rs:45:9 + โ•ฐโ”€โ–ถ internal error: entered unreachable code + help: set the `RUST_BACKTRACE=1` environment variable to display a backtrace. +``` + +```ansi:no-line-numbers title="After" +> let fn = { break } +Error: nu::compile::not_in_a_loop + + ร— 'break' can only be used inside a loop + โ•ญโ”€[entry #4:1:12] + 1 โ”‚ let fn = { break } + ยท  โ”€โ”€โ”ฌโ”€โ”€ + ยท โ•ฐโ”€โ”€ can't be used outside of a loop + โ•ฐโ”€โ”€โ”€โ”€ +``` + +### Windows device path fixes ([#16775]) [[toc](#table-of-contents)] + +- On Windows, UNC and device paths no longer get a trailing `\` appended when being cast to `path` +- On Windows, `open`, `save` and `source` now work with device paths like `\\.\NUL` or `\\.\CON`, as well as reserved device names like `NUL` and `CON`. Using full device paths is recommended. + +### Clean up error handlers when jumping outside of `try` blocks ([#16838]) [[toc](#table-of-contents)] + +Previously, jumping out of a `try` block (possible with `break`/`continue` commands) did not clean up the error handler properly the way exiting it normally does. + +So when an error was thrown afterwards, the error handler would catch it and continue execution in the `catch` block... + +``` + do { + loop { + try { throwing an error jumps + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€break into the catch block!! + โ”‚ } catch {โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + break jumps out โ”‚ print 'jumped to catch block' โ”‚ + of the loop โ”‚ return โ”‚ + as expected โ”‚ } โ”‚ + โ””โ”€โ”€โ–บ} โ”‚ + error make -u {msg: "success"}โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + } +``` + +This was due to a miscompilation bug, which is now fixed. + +### Other fixes [[toc](#table-of-contents)] + +- `compact --empty` now recognizes 0 byte binary values as empty ([#16810]) + +- Fixed associative equality comparison for floats. ([#16549]) + +- The `**` (power) operator now parses as right-associative instead of left-associative, matching standard mathematical behavior. ([#16552]) + +- `port ` on Windows now properly finds open TCP ports. ([#16546]) + +- Fixed a panic when `duration`s were created with a value outside of the supported value range with certain unit suffixes. ([#16594]) + +- Fixes an issue in `std help externs` - it was using a column that is no longer present. ([#16590]) + +- The LSP should now work better with unsaved files and with overlays used as prefixes (ex. `overlay use foo as bar --prefix`) ([#16568]) + +- Variables defined as custom command arguments show now be available to autocomplete inside that command. ([#16531]) + +- Fixed building `nu-command` by itself. ([#16616]) + +- `for` and `while` loop blocks starting with a range literal no longer causes a compiler error ([#16764]) + +- Some `attr` subcommands had incorrect output signatures, which are now fixed. ([#16774]) + +- For commands expecting directory arguments, regular files will no longer be suggested as completions as a fallback for when no directory can be suggested. ([#16846]) + +# Notes for plugin developers [[toc](#table-of-contents)] + +### Allow saving `CustomValue`s ([#16692]) [[toc](#table-of-contents)] + +`CustomValue` now supports a `save` method. Implementors can use it to make their values savable to disk. + +### Pass optional and casing to follow path methods for `CustomValue` ([#16736]) [[toc](#table-of-contents)] + +Plugin authors that use `CustomValue` can now access the `optional` and `casing` fields in their `follow_path_int` and `follow_path_string` methods to add behavior for optional access or case sensitivity. + +::: warning + +This is a breaking change for the plugin signature so it needs an update. Simply ignoring these fields may be a valid solution. + +::: + +# Hall of fame [[toc](#table-of-contents)] + +Thanks to all the contributors below for helping us solve issues, improve documentation, refactor code, and more! :pray: + +| author | change | link | +| -------------- | ------------------------------------------------------------------------------------ | -------- | +| [@ayax79] | Added missing duration support | [#16566] | +| [@fdncred] | Update help to remove incorrect link | [#16585] | +| [@Bahex] | Add a `Cow`-like type with looser requirements that supports `Serialize/Deserialize` | [#16382] | +| [@blindFS] | Pitfall of redefining `def` | [#16591] | +| [@blindFS] | Empty span of unbalanced delimiter | [#16292] | +| [@132ikl] | Add area prefix to labeler bot labels | [#16609] | +| [@blindFS] | Duplicated testing code cleanup | [#16578] | +| [@132ikl] | Label bot: rename A:dataframe to A:plugin-polars | [#16612] | +| [@sholderbach] | Update labels in issue templates | [#16610] | +| [@fdncred] | Bump nushell to latest nu-ansi-term | [#16613] | +| [@cptpiepmatz] | Install prebuilt `cargo-audit` to speed up Security Audit workflow | [#16615] | +| [@sholderbach] | Rework signature flag parsing | [#16617] | +| [@Sheape] | Add integration test for associativity in power operator | [#16627] | +| [@132ikl] | Upload artifact during CI | [#16633] | +| [@sholderbach] | Bump `scc` to a non-yanked version | [#16631] | +| [@132ikl] | Add release notes devdocs | [#16614] | +| [@sholderbach] | Fix `mismatched_lifetime_syntaxes` lint | [#16618] | +| [@Bahex] | Set up ast-grep with some custom lints | [#16674] | +| [@Sheape] | Align `query db` description with other database commands | [#16680] | +| [@cptpiepmatz] | Bump `rusqlite` to 0.37 | [#16684] | +| [@Bahex] | Parser clean up. | [#16668] | +| [@sholderbach] | Update Rust to 1.88.0 and use let-chains | [#16671] | +| [@blindFS] | Check_call dedup | [#16596] | +| [@132ikl] | Nushell can now be built without pulling in SQLite as a dependency. | [#16682] | +| [@sholderbach] | Fix `ast-grep` config | [#16691] | +| [@cptpiepmatz] | Load experimental options before command context is loaded | [#16690] | +| [@Bahex] | Gate some plugin related tests behind the "plugin" feature | [#16698] | +| [@Bahex] | Cleaner api for embedded config files | [#16626] | +| [@132ikl] | Fix CI artifact upload on Windows runner | [#16702] | +| [@blindFS] | Add more test cases for recent fixes | [#16628] | +| [@blindFS] | Cleanup some unnecessary code introduced recently | [#16696] | +| [@132ikl] | The Nushell development toolkit is now a module rather than a single file. | [#16701] | +| [@cptpiepmatz] | Fix building `cargo check -p nu-cli --features sqlite` | [#16707] | +| [@Bahex] | Ast-grep rule improvements | [#16699] | +| [@blindFS] | Panic on goto std files | [#16694] | +| [@blindFS] | Missing span of incomplete math binary op | [#16721] | +| [@ysthakur] | Ignore XDG_CONFIG_HOME when getting default config path | [#16595] | +| [@Bahex] | Refactor `each` | [#16732] | +| [@fdncred] | Update nushell to use coreutils v0.2.2 crates | [#16737] | +| [@WindSoilder] | Set pipefail issue number | [#16761] | +| [@Bahex] | Add tracking issue of experimental reorder-cell-paths | [#16767] | +| [@ayax79] | MCP tweaks and fixes | [#16758] | +| [@cptpiepmatz] | Stop using `macos-13` in CI | [#16796] | +| [@Bahex] | Add tests for ast-grep rules | [#16817] | +| [@Tyarel8] | ### `cell-path`s can now be converted `into string`s | [#16809] | +| [@Bahex] | Increase timeout of `hover_on_external_command` | [#16818] | +| [@132ikl] | Remove all usages of `internal_span` | [#16799] | +| [@Bahex] | Mark `Value` variants as `#[non_exhaustive]` | [#16820] | +| [@Bahex] | Big testing refactor | [#16802] | +| [@Bahex] | Remove `pipeline` calls added after the testing refactor branched off | [#16835] | +| [@cablehead] | Http / metadata access examples '--allow-errors' flag required | [#16836] | +| [@cablehead] | Relay rich error formatting for LLM-friendly diagnostics | [#16839] | +| [@fdncred] | Update reedline to latest commit a274653 | [#16841] | +| [@cptpiepmatz] | Bump Windows crates | [#16843] | +| [@cablehead] | Disable ANSI coloring for error messages | [#16857] | +| [@sholderbach] | Add required fields for crate publish to `nu-mcp` | [#16862] | + +# Full changelog [[toc](#table-of-contents)] + +| author | title | link | +| ----------------- | -------------------------------------------------------------------------------------------------------------------- | -------- | +| [@132ikl] | Add area prefix to labeler bot labels | [#16609] | +| [@132ikl] | Label bot: rename A:dataframe to A:plugin-polars | [#16612] | +| [@132ikl] | Add release notes devdocs | [#16614] | +| [@132ikl] | Upload artifact during CI | [#16633] | +| [@132ikl] | Allow variables in columns of table literals | [#16669] | +| [@132ikl] | Gate SQLite history behind existing `sqlite` feature | [#16682] | +| [@132ikl] | Add `network` feature to top-level crate | [#16686] | +| [@132ikl] | Refactor toolkit.nu into module | [#16701] | +| [@132ikl] | Fix CI artifact upload on Windows runner | [#16702] | +| [@132ikl] | Add `run pr` and `download pr` to `toolkit` | [#16770] | +| [@132ikl] | Remove all usages of `internal_span` | [#16799] | +| [@Bahex] | feat: Add a `Cow`-like type with looser requirements that supports `Serialize/Deserialize` | [#16382] | +| [@Bahex] | feat: Add completions to built-in commands with a predetermined list of suggestions. | [#16383] | +| [@Bahex] | feat: `for` loops are lazy, don't collect their source | [#16593] | +| [@Bahex] | refactor: cleaner api for embedded config files | [#16626] | +| [@Bahex] | refactor: defer compiling blocks | [#16634] | +| [@Bahex] | Parser clean up. | [#16668] | +| [@Bahex] | Set up ast-grep with some custom lints | [#16674] | +| [@Bahex] | Gate some plugin related tests behind the "plugin" feature | [#16698] | +| [@Bahex] | ast-grep rule improvements | [#16699] | +| [@Bahex] | Refactor `each` | [#16732] | +| [@Bahex] | feat: `each` can flatten streams from the closure without collecting | [#16735] | +| [@Bahex] | refactor!: collecting a stream with an error raises an error | [#16738] | +| [@Bahex] | Using `break`/`continue` outside loops raises a compile error | [#16740] | +| [@Bahex] | Properly initialize register when compiling `while`, `for` | [#16764] | +| [@Bahex] | Command-wide completions | [#16765] | +| [@Bahex] | add tracking issue of experimental reorder-cell-paths | [#16767] | +| [@Bahex] | fix `attr *` command signatures | [#16774] | +| [@Bahex] | Add syntax for simple completions from const lists | [#16789] | +| [@Bahex] | big testing refactor | [#16802] | +| [@Bahex] | `compact` works on records too | [#16810] | +| [@Bahex] | Add tests for ast-grep rules | [#16817] | +| [@Bahex] | Increase timeout of `hover_on_external_command` | [#16818] | +| [@Bahex] | Mark `Value` variants as `#[non_exhaustive]` | [#16820] | +| [@Bahex] | Remove `pipeline` calls added after the testing refactor branched off | [#16835] | +| [@Bahex] | Clean up error handlers when jumping outside of `try` blocks | [#16838] | +| [@Jan9103] | mark LSP sessions as non-interactive | [#16580] | +| [@Sheape] | Use symmetric float comparison for large floats | [#16549] | +| [@Sheape] | Fix associativity when parsing with power operator | [#16552] | +| [@Sheape] | Add integration test for associativity in power operator | [#16627] | +| [@Sheape] | Align `query db` description with other database commands | [#16680] | +| [@Sheape] | Improve error messages for invalid binary strings | [#16688] | +| [@Sheape] | Bump `bytesize` to 2.1.0 | [#16689] | +| [@Tyarel8] | feat(into string): add cell-path input to `into string` | [#16809] | +| [@Tyarel8] | feat: add `not-starts-with` and `not-ends-with` operators | [#16852] | +| [@WindSoilder] | Try to implement pipefail feature | [#16449] | +| [@WindSoilder] | set pipefail issue number | [#16761] | +| [@Xylobyte] | Escape markdown characters to always output valid table, add new switches for that | [#16681] | +| [@andoalon] | Add `--endian` flag to `format bits` | [#16574] | +| [@app/dependabot] | build(deps): bump scraper from 0.23.1 to 0.24.0 | [#16479] | +| [@app/dependabot] | build(deps): bump crate-ci/typos from 1.35.5 to 1.36.0 | [#16571] | +| [@app/dependabot] | build(deps): bump hashbrown from 0.15.2 to 0.16.0 | [#16572] | +| [@app/dependabot] | build(deps): bump shadow-rs from 1.2.0 to 1.3.0 | [#16573] | +| [@app/dependabot] | build(deps): bump actions/setup-python from 5 to 6 | [#16619] | +| [@app/dependabot] | build(deps): bump crate-ci/typos from 1.36.0 to 1.36.2 | [#16620] | +| [@app/dependabot] | build(deps): bump actions/labeler from 5 to 6 | [#16621] | +| [@app/dependabot] | build(deps): bump tempfile from 3.21.0 to 3.22.0 | [#16623] | +| [@app/dependabot] | build(deps): bump plist from 1.7.0 to 1.8.0 | [#16704] | +| [@app/dependabot] | build(deps): bump strum_macros from 0.26.4 to 0.27.2 | [#16741] | +| [@app/dependabot] | build(deps): bump tempfile from 3.22.0 to 3.23.0 | [#16742] | +| [@app/dependabot] | build(deps): bump brotli from 7.0.0 to 8.0.2 | [#16743] | +| [@app/dependabot] | build(deps): bump quick-xml from 0.37.5 to 0.38.3 | [#16744] | +| [@app/dependabot] | build(deps): bump uuid from 1.16.0 to 1.18.1 | [#16745] | +| [@app/dependabot] | build(deps): bump crate-ci/typos from 1.36.2 to 1.37.0 | [#16776] | +| [@app/dependabot] | build(deps): bump rmcp from 0.6.4 to 0.7.0 | [#16777] | +| [@app/dependabot] | build(deps): bump indicatif from 0.17.11 to 0.18.0 | [#16779] | +| [@app/dependabot] | build(deps): bump nix from 0.29.0 to 0.30.1 | [#16780] | +| [@app/dependabot] | build(deps): bump rmcp from 0.7.0 to 0.8.1 | [#16823] | +| [@app/dependabot] | build(deps): bump shadow-rs from 1.3.0 to 1.4.0 | [#16824] | +| [@ayax79] | Added missing duration support | [#16566] | +| [@ayax79] | Introduction of the MCP server feature. | [#16693] | +| [@ayax79] | Polars 50.1 upgrade | [#16703] | +| [@ayax79] | MCP tweaks and fixes | [#16758] | +| [@ayax79] | Polars input/output types cleanup | [#16819] | +| [@blindFS] | fix(parser): empty span of unbalanced delimiter | [#16292] | +| [@blindFS] | fix(completion): missing local variables | [#16531] | +| [@blindFS] | fix(lsp): malfunctioning on unsaved files, empty `workspaceFolder` parameter, overlay use with prefixes | [#16568] | +| [@blindFS] | refactor(lsp): duplicated testing code cleanup | [#16578] | +| [@blindFS] | fix(parser): pitfall of redefining `def` | [#16591] | +| [@blindFS] | fix: panic on large duration number | [#16594] | +| [@blindFS] | refactor(parser): check_call dedup | [#16596] | +| [@blindFS] | test(lsp): add more test cases for recent fixes | [#16628] | +| [@blindFS] | fix(lsp): panic on goto std files | [#16694] | +| [@blindFS] | refactor(parser): cleanup some unnecessary code introduced recently | [#16696] | +| [@blindFS] | fix(completion): dotnu completion refactor, fixes path with space for both dotnu module path and external executable | [#16715] | +| [@blindFS] | fix(parser): missing span of incomplete math binary op | [#16721] | +| [@blindFS] | fix(completion): file completion for redirection target | [#16831] | +| [@cablehead] | feat: add custom metadata support and HTTP response metadata | [#16821] | +| [@cablehead] | fix: http / metadata access examples '--allow-errors' flag required | [#16836] | +| [@cablehead] | feat(mcp): relay rich error formatting for LLM-friendly diagnostics | [#16839] | +| [@cablehead] | fix(mcp): disable ANSI coloring for error messages | [#16857] | +| [@cptpiepmatz] | Add more infos to experimental options | [#16142] | +| [@cptpiepmatz] | Check for free TCP ports on Windows via TCP table | [#16546] | +| [@cptpiepmatz] | Install prebuilt `cargo-audit` to speed up Security Audit workflow | [#16615] | +| [@cptpiepmatz] | Fix building `nu-command` by itself | [#16616] | +| [@cptpiepmatz] | Add batch config for tables | [#16629] | +| [@cptpiepmatz] | Bump `rusqlite` to 0.37 | [#16684] | +| [@cptpiepmatz] | Load experimental options before command context is loaded | [#16690] | +| [@cptpiepmatz] | Allow saving `CustomValue`s | [#16692] | +| [@cptpiepmatz] | Replace `into value` with `detect type` | [#16697] | +| [@cptpiepmatz] | Fix building `cargo check -p nu-cli --features sqlite` | [#16707] | +| [@cptpiepmatz] | Pass optional and casing to follow path methods for `CustomValue` | [#16736] | +| [@cptpiepmatz] | Promote experimental option `reorder-cell-paths` to opt out | [#16795] | +| [@cptpiepmatz] | Stop using `macos-13` in CI | [#16796] | +| [@cptpiepmatz] | Bump Windows crates | [#16843] | +| [@fdncred] | update help to remove incorrect link | [#16585] | +| [@fdncred] | bump nushell to latest nu-ansi-term | [#16613] | +| [@fdncred] | add `$nu.is-lsp` to help with printing in lsp mode | [#16635] | +| [@fdncred] | update nushell to use coreutils v0.2.2 crates | [#16737] | +| [@fdncred] | add `--chars` to `str length` command | [#16768] | +| [@fdncred] | update reedline to the latest commit | [#16791] | +| [@fdncred] | update reedline to latest commit a274653 | [#16841] | +| [@fixerer] | Fix ir eval error on branched block redirection (Fixes #16582) | [#16676] | +| [@maxim-uvarov] | Add %J and %Q format specifiers for compact date/time formatting | [#16588] | +| [@mkatychev] | fix(engine, type-system)!: enforce assignment type annotations at runtime | [#16079] | +| [@nome] | Theming fix | [#16722] | +| [@nome] | Windows device path fixes | [#16775] | +| [@sgvictorino] | improve collection type inference | [#16530] | +| [@sholderbach] | Update labels in issue templates | [#16610] | +| [@sholderbach] | Rework signature flag parsing | [#16617] | +| [@sholderbach] | Fix `mismatched_lifetime_syntaxes` lint | [#16618] | +| [@sholderbach] | Bump `scc` to a non-yanked version | [#16631] | +| [@sholderbach] | Update Rust to 1.88.0 and use let-chains | [#16671] | +| [@sholderbach] | Fix `ast-grep` config | [#16691] | +| [@sholderbach] | Add required fields for crate publish to `nu-mcp` | [#16862] | +| [@simonborje] | Expand alias when sending command to external completion | [#16640] | +| [@simonborje] | Add configuration for columnar menu traversal direction | [#16724] | +| [@simonborje] | Completions for `directory`s won't fallback to regular files | [#16846] | +| [@weirdan] | Fix `std help externs` | [#16590] | +| [@weirdan] | Discard `path add` input | [#16606] | +| [@xolra0d] | `which` without application parameter now lists all internal and external executables | [#16551] | +| [@ysthakur] | test: Ignore XDG_CONFIG_HOME when getting default config path | [#16595] | + +[@132ikl]: https://github.com/132ikl +[@Bahex]: https://github.com/Bahex +[@Jan9103]: https://github.com/Jan9103 +[@Sheape]: https://github.com/Sheape +[@Tyarel8]: https://github.com/Tyarel8 +[@WindSoilder]: https://github.com/WindSoilder +[@Xylobyte]: https://github.com/Xylobyte +[@andoalon]: https://github.com/andoalon +[@app/dependabot]: https://github.com/app/dependabot +[@ayax79]: https://github.com/ayax79 +[@blindFS]: https://github.com/blindFS +[@cablehead]: https://github.com/cablehead +[@cptpiepmatz]: https://github.com/cptpiepmatz +[@fdncred]: https://github.com/fdncred +[@fixerer]: https://github.com/fixerer +[@maxim-uvarov]: https://github.com/maxim-uvarov +[@mkatychev]: https://github.com/mkatychev +[@nome]: https://github.com/nome +[@sgvictorino]: https://github.com/sgvictorino +[@sholderbach]: https://github.com/sholderbach +[@simonborje]: https://github.com/simonborje +[@weirdan]: https://github.com/weirdan +[@xolra0d]: https://github.com/xolra0d +[@ysthakur]: https://github.com/ysthakur +[#16079]: https://github.com/nushell/nushell/pull/16079 +[#16142]: https://github.com/nushell/nushell/pull/16142 +[#16292]: https://github.com/nushell/nushell/pull/16292 +[#16382]: https://github.com/nushell/nushell/pull/16382 +[#16383]: https://github.com/nushell/nushell/pull/16383 +[#16449]: https://github.com/nushell/nushell/pull/16449 +[#16479]: https://github.com/nushell/nushell/pull/16479 +[#16530]: https://github.com/nushell/nushell/pull/16530 +[#16531]: https://github.com/nushell/nushell/pull/16531 +[#16546]: https://github.com/nushell/nushell/pull/16546 +[#16549]: https://github.com/nushell/nushell/pull/16549 +[#16551]: https://github.com/nushell/nushell/pull/16551 +[#16552]: https://github.com/nushell/nushell/pull/16552 +[#16566]: https://github.com/nushell/nushell/pull/16566 +[#16568]: https://github.com/nushell/nushell/pull/16568 +[#16571]: https://github.com/nushell/nushell/pull/16571 +[#16572]: https://github.com/nushell/nushell/pull/16572 +[#16573]: https://github.com/nushell/nushell/pull/16573 +[#16574]: https://github.com/nushell/nushell/pull/16574 +[#16578]: https://github.com/nushell/nushell/pull/16578 +[#16580]: https://github.com/nushell/nushell/pull/16580 +[#16585]: https://github.com/nushell/nushell/pull/16585 +[#16588]: https://github.com/nushell/nushell/pull/16588 +[#16590]: https://github.com/nushell/nushell/pull/16590 +[#16591]: https://github.com/nushell/nushell/pull/16591 +[#16593]: https://github.com/nushell/nushell/pull/16593 +[#16594]: https://github.com/nushell/nushell/pull/16594 +[#16595]: https://github.com/nushell/nushell/pull/16595 +[#16596]: https://github.com/nushell/nushell/pull/16596 +[#16606]: https://github.com/nushell/nushell/pull/16606 +[#16609]: https://github.com/nushell/nushell/pull/16609 +[#16610]: https://github.com/nushell/nushell/pull/16610 +[#16612]: https://github.com/nushell/nushell/pull/16612 +[#16613]: https://github.com/nushell/nushell/pull/16613 +[#16614]: https://github.com/nushell/nushell/pull/16614 +[#16615]: https://github.com/nushell/nushell/pull/16615 +[#16616]: https://github.com/nushell/nushell/pull/16616 +[#16617]: https://github.com/nushell/nushell/pull/16617 +[#16618]: https://github.com/nushell/nushell/pull/16618 +[#16619]: https://github.com/nushell/nushell/pull/16619 +[#16620]: https://github.com/nushell/nushell/pull/16620 +[#16621]: https://github.com/nushell/nushell/pull/16621 +[#16623]: https://github.com/nushell/nushell/pull/16623 +[#16626]: https://github.com/nushell/nushell/pull/16626 +[#16627]: https://github.com/nushell/nushell/pull/16627 +[#16628]: https://github.com/nushell/nushell/pull/16628 +[#16629]: https://github.com/nushell/nushell/pull/16629 +[#16631]: https://github.com/nushell/nushell/pull/16631 +[#16633]: https://github.com/nushell/nushell/pull/16633 +[#16634]: https://github.com/nushell/nushell/pull/16634 +[#16635]: https://github.com/nushell/nushell/pull/16635 +[#16640]: https://github.com/nushell/nushell/pull/16640 +[#16668]: https://github.com/nushell/nushell/pull/16668 +[#16669]: https://github.com/nushell/nushell/pull/16669 +[#16671]: https://github.com/nushell/nushell/pull/16671 +[#16674]: https://github.com/nushell/nushell/pull/16674 +[#16676]: https://github.com/nushell/nushell/pull/16676 +[#16680]: https://github.com/nushell/nushell/pull/16680 +[#16681]: https://github.com/nushell/nushell/pull/16681 +[#16682]: https://github.com/nushell/nushell/pull/16682 +[#16684]: https://github.com/nushell/nushell/pull/16684 +[#16686]: https://github.com/nushell/nushell/pull/16686 +[#16688]: https://github.com/nushell/nushell/pull/16688 +[#16689]: https://github.com/nushell/nushell/pull/16689 +[#16690]: https://github.com/nushell/nushell/pull/16690 +[#16691]: https://github.com/nushell/nushell/pull/16691 +[#16692]: https://github.com/nushell/nushell/pull/16692 +[#16693]: https://github.com/nushell/nushell/pull/16693 +[#16694]: https://github.com/nushell/nushell/pull/16694 +[#16696]: https://github.com/nushell/nushell/pull/16696 +[#16697]: https://github.com/nushell/nushell/pull/16697 +[#16698]: https://github.com/nushell/nushell/pull/16698 +[#16699]: https://github.com/nushell/nushell/pull/16699 +[#16701]: https://github.com/nushell/nushell/pull/16701 +[#16702]: https://github.com/nushell/nushell/pull/16702 +[#16703]: https://github.com/nushell/nushell/pull/16703 +[#16704]: https://github.com/nushell/nushell/pull/16704 +[#16707]: https://github.com/nushell/nushell/pull/16707 +[#16715]: https://github.com/nushell/nushell/pull/16715 +[#16721]: https://github.com/nushell/nushell/pull/16721 +[#16722]: https://github.com/nushell/nushell/pull/16722 +[#16724]: https://github.com/nushell/nushell/pull/16724 +[#16732]: https://github.com/nushell/nushell/pull/16732 +[#16735]: https://github.com/nushell/nushell/pull/16735 +[#16736]: https://github.com/nushell/nushell/pull/16736 +[#16737]: https://github.com/nushell/nushell/pull/16737 +[#16738]: https://github.com/nushell/nushell/pull/16738 +[#16740]: https://github.com/nushell/nushell/pull/16740 +[#16741]: https://github.com/nushell/nushell/pull/16741 +[#16742]: https://github.com/nushell/nushell/pull/16742 +[#16743]: https://github.com/nushell/nushell/pull/16743 +[#16744]: https://github.com/nushell/nushell/pull/16744 +[#16745]: https://github.com/nushell/nushell/pull/16745 +[#16758]: https://github.com/nushell/nushell/pull/16758 +[#16761]: https://github.com/nushell/nushell/pull/16761 +[#16764]: https://github.com/nushell/nushell/pull/16764 +[#16765]: https://github.com/nushell/nushell/pull/16765 +[#16767]: https://github.com/nushell/nushell/pull/16767 +[#16768]: https://github.com/nushell/nushell/pull/16768 +[#16770]: https://github.com/nushell/nushell/pull/16770 +[#16774]: https://github.com/nushell/nushell/pull/16774 +[#16775]: https://github.com/nushell/nushell/pull/16775 +[#16776]: https://github.com/nushell/nushell/pull/16776 +[#16777]: https://github.com/nushell/nushell/pull/16777 +[#16779]: https://github.com/nushell/nushell/pull/16779 +[#16780]: https://github.com/nushell/nushell/pull/16780 +[#16789]: https://github.com/nushell/nushell/pull/16789 +[#16791]: https://github.com/nushell/nushell/pull/16791 +[#16795]: https://github.com/nushell/nushell/pull/16795 +[#16796]: https://github.com/nushell/nushell/pull/16796 +[#16799]: https://github.com/nushell/nushell/pull/16799 +[#16802]: https://github.com/nushell/nushell/pull/16802 +[#16809]: https://github.com/nushell/nushell/pull/16809 +[#16810]: https://github.com/nushell/nushell/pull/16810 +[#16817]: https://github.com/nushell/nushell/pull/16817 +[#16818]: https://github.com/nushell/nushell/pull/16818 +[#16819]: https://github.com/nushell/nushell/pull/16819 +[#16820]: https://github.com/nushell/nushell/pull/16820 +[#16821]: https://github.com/nushell/nushell/pull/16821 +[#16823]: https://github.com/nushell/nushell/pull/16823 +[#16824]: https://github.com/nushell/nushell/pull/16824 +[#16831]: https://github.com/nushell/nushell/pull/16831 +[#16835]: https://github.com/nushell/nushell/pull/16835 +[#16836]: https://github.com/nushell/nushell/pull/16836 +[#16838]: https://github.com/nushell/nushell/pull/16838 +[#16839]: https://github.com/nushell/nushell/pull/16839 +[#16841]: https://github.com/nushell/nushell/pull/16841 +[#16843]: https://github.com/nushell/nushell/pull/16843 +[#16846]: https://github.com/nushell/nushell/pull/16846 +[#16852]: https://github.com/nushell/nushell/pull/16852 +[#16857]: https://github.com/nushell/nushell/pull/16857 +[#16862]: https://github.com/nushell/nushell/pull/16862