12071 Commits
Author SHA1 Message Date
Darren Schroeder 68b79ea0d6 test(run): drop the shared short flag that #19271 made a parse error (#19274)
## Description

`run_binds_flags_by_their_long_name` has failed on main since 973c59091.
#19272 added it with a `main` that declares `-a` and `--bb(-a)`, and
#19271 made a repeated short flag a parse error
(`nu::parser::duplicate_parameter`). Each PR passed CI on the same base
and they merged 39 seconds apart, so main's CI was the first run to have
both.

This PR fixes the test.

## User-facing changes (Release notes)

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-17 16:33:19 -05:00
Darren Schroeder 973c590918 Fix the bugs found by the nu-conformance open questions (#19271)
## Description

The [nu-conformance](https://github.com/Fikoko/nu-conformance) suite
(#19206) recorded 35 behaviors as open questions. This PR fixes the ones
that are bugs, plus five that needed a decision (T2, T4, T8, T12 and
T13). The IDs are the question IDs in that repo's
[`open-questions.md`](https://github.com/Fikoko/nu-conformance/blob/master/open-questions.md).

### Before and after

| | Code | main | branch |
|---|---|---|---|
| S2 | `"\xFF"` | error `nu::parser::parse_mismatch`: expected any shape
| error `nu::parser::error`: invalid UTF-8 from `\x` escapes in string |
| S3 | `r#'abc` | error `nu::parser::unexpected_eof`: expected closing
'# | error `nu::parser::unclosed_delimiter`: expected `'#` here |
| T1 | `inf == 1` | `true` | `false` |
| T1 | `inf > 1` | `false` | `true` |
| T1 | `[1.0 inf] \| math max` | `1.0` | `inf` |
| T2 | `let x = 5; -$x` | `-$x` | `-5` |
| T2 | `let x = 5; 1 + -$x` | error
`nu::parser::operator_incompatible_types`: string | `-4` |
| T2 | `let x = 5sec; -$x` | `-$x` | `-5sec` |
| T2 | `-(2 + 3) \| describe` | `string` | `int` |
| T2 | `-(1)px` | `-1px` | `-1px` |
| T3 | `-0x10` | `-0x10` | `-16` |
| T3 | `+0b11` | error `nu::shell::external_command`: Command `+0b11`
not found | `3` |
| T4 | `9223372036854775808` | `9223372036854775808.0` | error
`nu::parser::error`: number too large (add `.0` for a float) in int |
| T4 | `9223372036854775808.0` | `9223372036854775808.0` |
`9223372036854775808.0` |
| T6 | `[INF Nan Infinity] \| to nuon` | `[inf, NaN, inf]` | `["INF",
"Nan", "Infinity"]` |
| T6 | `[inf nan NaN] \| to nuon` | `[inf, NaN, NaN]` | `[inf, NaN,
NaN]` |
| T7 | `9223372036854775808ns` | `15250wk 1day 23hr 47min 16sec 854ms
775µs 807ns` | error `nu::parser::literal_too_large`: duration too large
|
| T7 | `8EiB` | `9.2 EB` | error `nu::parser::literal_too_large`:
filesize too large |
| T8 | `[2023-02-29] \| to nuon` | `["2023-02-29"]` | error
`nu::parser::error`: not a valid date in datetime |
| T8 | `[2023-02-29.log] \| to nuon` | `["2023-02-29.log"]` |
`["2023-02-29.log"]` |
| T10 | `+5sec` | error `nu::shell::external_command`: Command `+5sec`
not found | `5sec` |
| T11 | `[1 2]] \| to nuon` | `[1, "2]"]` | error
`nu::parser::unbalanced_delimiter`: unexpected `]` (unbalanced with `[`)
|
| T12 | `{true: 1, null: 2} \| to nuon` | error
`nu::parser::parse_mismatch_with_full_string_msg`: expected string |
`{"true": 1, "null": 2}` |
| T12 | `[[1 2]; [3 4]] \| to nuon` | error `nu::parser::error`: must be
a string | `[["1", "2"]; [3, 4]]` |
| T13 | `print before; {a: 1, a: 2}` | error
`nu::shell::column_defined_twice`: field first defined here | error
`nu::parser::column_defined_twice`: field redefined here |
| O1 | `not "a" == "b"` | error `nu::shell::cant_convert`: can't convert
string to boolean | `true` |
| O1 | `let x = 1; not $x == 2` | error `nu::shell::cant_convert`: can't
convert int to boolean | `true` |
| O3 | `(-9223372036854775808) mod -1` | error
`nu::shell::operator_overflow`: modulo operation overflowed | `0` |
| O4 | `1 in [1.0]` | error `nu::parser::operator_incompatible_types`:
list<float> | `true` |
| D1 | `const x = 1; unlet $x; $x` | `1` | error
`nu::compile::invalid_literal`: constants cannot be deleted |
| D2 | `unlet $in` | `nothing` | error `nu::compile::invalid_literal`:
'$in' is a built-in variable and cannot be deleted |
| D3 | `mut x = 0; [1 2 3] \| where {\|v\| $x += 1; true } \| ignore;
$x` | `0` | error `nu::parser::expected_keyword`: capture of mutable
variable |
| F2 | `while false { } \| describe` | `nothing` | error
`nu::parser::unexpected_keyword`: not allowed in pipeline |
| F3 | `if 1 { }` | error `nu::shell::cant_convert`: can't convert int
to boolean | error `nu::shell::type_mismatch`: expected bool |
| F4 | `2.0 in 1.0..2.0` | `false` | `true` |
| F4 | `2.0 in 1.0..<2.0` | `true` | `false` |
| C1 | `def f [...r, a] { {r: $r, a: $a} }; f 1 2 3 \| to nuon` | `{r:
[2, 3], a: 1}` | error `nu::parser::positional_after_rest`: parameter a
after the rest parameter |
| C2 | `def f [a, a] { $a }; f 1 2` | `2` | error
`nu::parser::duplicate_parameter`: `a` uses a name that is already taken
|
| C2 | `def f [--x, --x] { $x }; f --x` | `false` | error
`nu::parser::duplicate_parameter`: `--x` uses a name that is already
taken |
| C2 | `def f [--help] { 'mine' }; f --help \| lines \| first` |
`Usage:` | error `nu::parser::error`: every command already has `--help`
|

C3, a script that calls two deprecated commands:

```nushell
$ nu two_deprecated.nu    # main
Warning: nu::parser::deprecated
   : `-- g is deprecated and will be removed in a future release.
```
```nushell
$ nu two_deprecated.nu    # branch
Warning: nu::parser::deprecated
   : `-- g is deprecated and will be removed in a future release.
Warning: nu::parser::deprecated
   : `-- k is deprecated and will be removed in a future release.
```
## User-facing changes (Release notes)

### Breaking changes

- `not` now has the precedence `help operators` lists: `not $a == $b`
means `not ($a == $b)`. Before, `not` applied to the next value only.
- `-$x` and `-(expr)` negate their value, also as a flag's value or an
argument after `--`. Before, `-$x` was the string `"-$x"` and `-(2 + 3)`
the string `"-5"`. Arguments to external commands are unchanged.
- An integer literal too large for 64 bits, such as
`9223372036854775808`, is an error. Add `.0` to write a float.
- Filesize and duration literals that don't fit are a parse error
(`nu::parser::literal_too_large`) instead of saturating to the largest
value.
- A word written like a date that isn't a valid date, such as
`2023-02-29`, is an error.
- `INF`, `Nan`, `Infinity` and other spellings of special floats are
strings. Use `inf`, `nan` or `NaN`. `from nuon` reads them the same way.
- A record or table literal that names a field twice is a parse error.
- `[1 2]]` is an error instead of `[1, "2]"]`.
- In a custom command, repeated parameter or flag names, repeated short
flags, a parameter after `...rest`, and a `--help` flag are errors.
- `while` and `loop` can't be piped, like `for`.
- `unlet` errors on constants and on `$in`.
- Assigning to a `mut` variable inside a `where` condition is an error;
the assignment never took effect.

### Fixes

- `inf` compares as larger than every finite number, and `[1.0 inf] |
math max` is `inf`.
- `2.0 in 1.0..2.0` is `true`, and `2.0 in 1.0..<2.0` is `false`.
- `-0x10`, `+0b11`, `+5sec` and `+1kB` are numbers.
- `1 in [1.0]` is `true`.
- `{true: 1}` and `[[1 2]; [3 4]]` parse, with the keys `"true"`, `"1"`
and `"2"`.
- `(-9223372036854775808) mod -1` is `0`.
- `if 1 { }` reports the same type mismatch as `while 1 { }`, and an
`if` or `while` condition that fails while it runs reports its own
error.
- `9223372036854775807ns` and `9223372036854775807b` are exact, and
integer filesize and duration literals no longer lose precision.
- A script or `nu -c` command shows every parse warning once, not only
the first.
- Clearer errors for invalid UTF-8 from `\x` escapes and for unclosed
raw strings.

## Additional notes
2026-10-17 14:54:47 -05:00
Darren Schroeder de4d33d410 fix(run): reject script arguments that main doesn't accept (#19272)
## Description

`run script.nu ...args` now checks the arguments after the script path
against the script's `main`, the way a call to `main` does. Before, it
dropped unknown flags and extra positional arguments, ignored
`--flag=value`, and never checked types.

`run`'s own flags (`--full-reparse`, `--help`) now only count before the
script path. Everything after the path goes to `main`.

`run` parses the arguments before it has seen `main`'s signature, so
unlike `nu script.nu` it doesn't convert values to the parameter's type.
`--foo 23` for a `string` flag is an error that tells you to quote the
value.

Fixes #19266

### Before and after

With `run-test.nu` from the issue, `def main [--foo(-f): string,
--bar(-b)]`:

| `run run-test.nu ...` | Before | After |
| --- | --- | --- |
| `--foo "23" --bar=true` | `bar` is `false` | `bar` is `true` |
| `--foo=$v` | `foo` is `null` | `foo` is the value of `$v` |
| `-f x` | `-f` goes to `run`, `foo` is `null` | `foo` is `x` |
| `-bf x` | `foo` is `null`, `bar` is `false` | `foo` is `x`, `bar` is
`true` |
| `...{foo: "23"}` | Error: unknown flag `foo` in spread record | `foo`
is `"23"` |
| `--help` | `run`'s help | `main`'s help |
| `--foo` | `foo` is `true` | Error: missing flag argument |
| `--foo "23" --huh? hello` | `--huh?` and `hello` are dropped | Error:
unknown flag `--huh?` |
| `--foo "23" hello` | `hello` is dropped | Error: extra positional
argument |
| `--foo 23` | `foo` is the int `23` | the error below |

```nushell
Error: nu::shell::cant_convert

  × Can't convert to string.
   ╭─[source:1:23]
 1 │ run run-test.nu --foo 23 | to nuon
   ·                       ─┬
   ·                        ╰── can't convert int to string
   ╰────
  help: `run` doesn't convert script arguments; quote the value to pass a
        string
```

More cases. `deploy.nu` is `def main [target?: string, --dry-run]`, and
`rec.nu` calls `run --full-reparse rec.nu ($n - 1)` until `$n` is 0:

| Command | Before | After |
| --- | --- | --- |
| `run --foo x run-test.nu` | Error: file not found `--foo` | Error:
`run` has no flag `--foo` |
| `run ...{full-reparse: true} run-test.nu` | Error: cannot find column
`block_id_name` | reparses and runs the script |
| `let args = [--bar]; run run-test.nu ...$args` | `bar` is `true` |
Error: `main` has no rest parameter for a list spread |
| `run deploy.nu -dry-run` | runs for real with `target` set to
`-dry-run` | Error: unknown flag `-d` |
| `run --full-reparse rec.nu 1000` | nu crashes with a stack overflow |
Error: recursion limit (50) reached |

## User-facing changes (Release notes)

- `run script.nu ...args` rejects arguments the script's `main` doesn't
accept: unknown flags, extra positional arguments, flags missing a
value, and values of the wrong type. `--flag=value` now works.
- `run` doesn't convert values to `main`'s parameter types the way `nu
script.nu` does. Quote a number you pass to a `string` parameter, as in
`run x.nu --name "23"`.
- `run`'s own flags must come before the script path. After the path,
`-f` and `--help` go to `main`.
- Flags inside a list spread now stay values, so `run x.nu ...$args` no
longer passes a `--foo` in `$args` as a flag. Use a record spread like
`...{foo: "23"}` instead.
- `run` counts toward `recursion_limit`, so a script that runs itself
too deeply stops with an error instead of crashing nu.

## Additional notes

- This can break scripts that relied on `run` ignoring arguments. For
example, `run x.nu build` used to run plain `main` and drop `build`.
`run` doesn't dispatch to `def "main build"` subcommands the way `nu
x.nu build` does, so this is now an extra positional error.
- Also fixed: with `def main [-a, -b]`, `run x.nu -b` failed with
"variable not found", and `run` didn't find a `main` that has an
attribute like `@example`.
- Not in this PR: completing `main`'s flags after the script path.
2026-10-17 14:54:07 -05:00
pickx 394445e89d feat(job spawn) auto-kill flag (#19141)
## Description
closes #18896

when calling `exit`, if the flag is passed, we suppress the warning for
quitting that job. if all remaining jobs have this flag enabled, we
don't emit a warning.
I chose the name `auto-kill` because we already use the terminology
"kill" for jobs

## User-facing changes (Release notes)
Allow using the flag `-k`/`--auto-kill` with `job spawn` for jobs that
are expected to stay alive. This suppresses warnings about that job
still running on `exit`.
`job list` now shows which jobs have this `auto-kill` flag set, and a
hint has been added to `exit`.
2026-10-17 09:59:06 -05:00
Darren Schroeder e5ebc68190 Ignore the zip extraction advisories in cargo audit, since calamine never extracts (#19273)
## Description

The `Security audit` job is failing on main and on every PR that touches
`Cargo.lock` (for example #19141). RustSec filed three advisories
against `zip 8.6.0` on 2026-10-09 and 2026-10-10, all fixed in `zip >=
9.0.0`:

| Advisory | Issue |
| --- | --- |
| RUSTSEC-2026-0367 | `extract()` keeps SUID/SGID/sticky bits from the
archive |
| RUSTSEC-2026-0368 | `ZipArchive::extract` creates symlinks that point
outside the destination |
| RUSTSEC-2026-0369 | `extract()` applies Unix permissions through
extracted symlinks |

A version bump is not possible yet. `calamine 0.36.1` is the latest
release and requires `zip = "^8.6"`, and the zip 9 upgrade
(tafia/calamine#741) is still an open PR. Using that branch would make
it a git dependency.

None of the three advisories can be reached from nushell. All three are
about writing an archive to disk (`ZipArchive::extract`,
`ZipStreamReader::extract`, symlink creation, permission bits). calamine
only opens the archive and reads entries into memory with
`ZipArchive::new`, `by_name` and `by_index`. A search of calamine
0.36.1's `src/` finds no `extract`, `ZipStreamReader`, `set_permissions`
or `symlink`.


## User-facing changes (Release notes)

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-17 08:16:49 -05:00
pickx 7b893cbad5 roundup of fixes for {hide,load,with}-env (#19098)
## Description
this is a roundup of fixes meant to address the following issues:
1. `$env.config`
- `load-env { config: {} }` and `hide-env config` can make `$env.config`
inaccessible. with the way nushell works, the config isn't gone, and a
simple `$env.config = {}` will fix this. but (imo) it's still weird.
- it can also give the impression that `load-env` is able to set
`$env.config`, which it couldn't.
    - therefore, I changed it so `hide-env` can't touch `config`.
- meanwhile, `load-env` and `with-env` (including the shorthand syntax
`FOO=bar command`) can now change `config`, which triggers a proper
config reload
2. automatic env vars
- automatic env vars like `PWD` are not supposed to be changed through
`load-env` and `hide-env`. a guard was implemented in `load-env` but not
`hide-env`. now both handle this.
- we had several manual impls of finding automatic env vars. changed to
use a shared impl.
- some env var-detecting logic still has the assumption that env vars
are case sensitive outside Windows, but `load-env` and `hide-env` don't
work like that. so although `load-env` tried to guard against changing
e.g. `$env.PWD` it would happily change `$env.PwD` so can still mess up
the environment.

## User-facing changes (Release notes)
Changes have been made around the interaction of `load-env`, `hide-env`
and `with-env` with some environment variables which are managed by
nushell.

Specifically:
* `load-env`, `hide-env` and `with-env` can no longer change `$env.PWD`,
regardless of casing (for example, `Pwd` is also rejected).
* `hide-env` can no longer hide `$env.FILE_PWD` or `$env.CURRENT_FILE`.
this was previously allowed.
* `load-env` and `with-env`, including the syntax `FOO=bar command`, can
now set `$env.config`.
* `hide-env` can no longer hide `$env.config`.
2026-10-17 07:13:58 -05:00
Miles Wirht ae34b06666 Fix completion match indices, cursor edits, and IDE output (#19258)
Fix Unicode completion match indices, UTF-8 cursor normalization,
command-head replacement spans, IDE JSON escaping, and execution of
tests selected with `--ignored`.
Regression tests reproduce the failures on main, and the relevant test
suites, workspace CI checks, formatting, and lint pass.
2026-10-17 07:00:12 -05:00
Gleb Chipiga 85aae22da8 Release plugin inputs on response completion or output drop (#19171)
## Description

A plugin can stop processing while its input reader is still blocked on
a connected, idle producer.

Have the SDK release a call's original list or byte input automatically
when its complete response finishes writing, or when the engine drops
its output stream. Returning lazy output does not itself release input.
Other calls and engine-call result streams are unaffected; no new public
plugin API is needed.

Defer both completion and output-drop cleanup while the SDK is
forwarding stream input to an engine call. An early response from
`call_decl` or `eval_closure_with_stream` must not truncate that input,
including redirected output that closes before its input consumer
finishes. The core reader owns a concrete hold, attached before
publishing the engine-call header and released when the forwarding
writer ends or its consumer sends `Drop`. Since `PipelineData` is
opaque, forwarding an unrelated stream conservatively holds the original
input too. Engine-call result readers remain outside this cleanup.

Skip completion cleanup while the plugin has disabled GC through
`set_gc_disabled(true)`, preserving background input reads after a
response. This follows the last successfully written and flushed
plugin-wide GC option, not Nushell's GC configuration. The setting is
shared by all calls, so overlapping calls must coordinate updates: the
last write wins for both GC and input retention. Completion reads the
setting without waiting for transport I/O; concurrent GC updates retain
their wire order. An early output `Drop` still requests input cleanup,
regardless of GC, but honors active SDK forwarding holds. Remove the
output/input association before sending `End`, so a normal EOF
acknowledgement does not cancel those background reads. Keep the
association in the output writer's signal, cancelling input before
waking a dropped writer so concurrent `End` cannot lose the cleanup.

Cancelled reads report `ShellError::Interrupted` once instead of
successful EOF, so a consumer can distinguish interrupted input from a
complete stream. The reader discards its local queue and sends `Drop`
once. Its registration remains until the producer sends `End`, allowing
in-flight messages to arrive safely. No wire protocol changes or new
dependencies are needed. The interruption retains the input stream's
span. A transport error dequeued by the current read takes precedence
over cancellation; errors behind that message are discarded with the
queue.

Association setup and local cleanup are infallible. A poisoned writer
mutex does not skip unlinking, releasing a hold, or the single terminal
`End` attempt; normal flow-control errors and actual write/flush errors
remain visible. Completion cleanup cannot introduce a second response
after a successful one.

Regression tests cover idle reads, cancellation races, late messages, GC
opt-out, call isolation, engine-call forwarding, and interruption versus
normal EOF, including both stream types through `serve_plugin_io`.

## User-facing changes (Release notes)

Fixed Rust plugin input readers remaining blocked after a response
finishes or its output is dropped. Background reads of original input
without an explicit call to `set_gc_disabled(true)` are now interrupted
when the complete response finishes, even if plugin GC is disabled in
Nushell's configuration. Cancelled input reads report
`ShellError::Interrupted`, not successful EOF.

Calling `set_gc_disabled(true)` preserves background input reads after
completion. This setting is plugin-wide and last write wins, so
overlapping calls must coordinate their GC updates. Both completion and
early output-drop cleanup preserve input forwarded by the SDK until
forwarding finishes or its consumer drops it. An early output drop still
requests cleanup when GC is disabled. Engine-call result readers are
unaffected.

## Additional notes

Related to #12129; this does not implement general pipeline
interruption.

Validated on Linux: 272 tests and 38 doctests across the five plugin
crates, plus 121 root plugin integration tests (one Windows-only test
ignored). The 40 SDK lifecycle tests also passed five repeated runs.
Formatting, `cargo nuclippy`, `cargo nuclippy-tests`, and `typos`
passed.

Full workspace runtime tests and Windows/macOS CI have not been run.
Cleanup wakes SDK-owned input reads; it does not interrupt arbitrary
iterators, blocked transport writes, or independent work such as HTTP
requests, or retract data already received. Output completion can still
wait for that independent work. A producer that never sends `End` can
leave a stream registration until the transport closes.

Developed with AI assistance.
2026-10-16 13:21:08 -05:00
Darren Schroeder 190471268e fix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes (#19270)
## Description

Follow-up to #19262. Three problems remain in how the MCP server's
`list_commands` and `command_help` tools, and the "Did you mean" hint
for an unknown command, describe the commands in scope.

- **Hidden commands are still offered.**
`EngineState::get_decls_sorted(false)` checks each overlay only against
that overlay's own visibility, but `hide` records the hide in the
overlay that is active when it runs. After `alias st = str trim`,
`overlay new x`, `hide st` (entered as separate lines), `st` can't be
called, yet MCP lists it, `command_help st` documents it, and `' a ' |
st` says "Did you mean `st`?". Module commands hidden the same way
behave the same.
- **`command_help` can describe the wrong command.** It searched the
listed signatures for a matching name instead of resolving the name the
way the parser does. When an overlay shadows `foo` and a later overlay
hides that `foo`, a call to `foo` runs the original, but `command_help
foo` documented the shadowing one. If a command was hidden and then
imported again from a later overlay, `foo` ran but `command_help foo`
said it didn't exist.
- **An alias lists the arguments it already passes.** An alias of an
internal command carries the wrapped command's full signature. `alias
home = cd ~` was listed as `home {flags} (path)`, and `def "foo bar" [x:
int] {}; alias fb = foo bar 1` as `fb <x>`. The parser starts matching
an alias call's arguments after the positionals the alias passes
(`parse_internal_call`), so `home /tmp` and `fb 2` fail.

## User-facing changes (Release notes)

- The MCP server's `list_commands` and `command_help` tools, and the
"Did you mean" hint for an unknown command, no longer offer a command
that was hidden with `hide` while another overlay was active.
- `command_help` now describes the command a name actually runs when
overlays shadow or hide commands.
- The MCP server's `list_commands` and `command_help` tools list an
alias that passes positional arguments with only the parameters left for
you to give. `alias home = cd ~` is listed as `home {flags}` instead of
`home {flags} (path)`. `help home` is unchanged and still shows the
expansion with `cd`'s usage.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-16 12:09:29 -05:00
Tino 2529074fc8 Fix some issues with how 'into string' handles ints/floats (#19265)
## Description

This PR fixes the three issues mentioned in
https://github.com/nushell/nushell/issues/19264.

Passing i64::MIN to 'into string' causes a crash since we're taking the
absolute of i64 and returning it as an i64. The absolute value of
i64::MIN is equal to i64::MAX + 1. unsigned_abs() gives us u64, which
can represent this value.

When grouping digits we check for the length of the value as a string
without taking into account the space the minus sign might take. Because
of this, a negative value such as "-123" is counted as four
numbers/characters instead of three. This goes above the threshold for
grouping, which results in a weirdly formatted output.

We correctly return early when a non-finite (infinite or NaN) value is
given in the `action` function, but we don't do the same after
formatting the input with the user-chosen amount of decimals. With some
inputs we can avoid the first early return due to the input being a
valid value, but still end up with a NaN after multiplying with
`precision` and rounding. This can be avoided by moving the early return
after the formatting.

Lastly, in format_duration_as_timeperiod, we now clamp the duration to
[-i64::MAX, i64::MAX] and then take the absolute value so that an error
isn't thrown when a value <= i64::MIN is passed to 'into duration'.

## User-facing changes (Release notes)

- Fixed multiple issues with how 'into string' handles ints/floats. Now
i64::MIN doesn't cause a crash, NaN is returned for negative values with
the `--decimal` argument set to a huge value and negative floats with
three integers are correctly formatted when `--group-digits` is passed.
- Fix an issue where 'into duration' overflows/panics when supplied with
a value <= i64::MIN

## Additional notes

Closes https://github.com/nushell/nushell/issues/19264
2026-10-16 11:57:21 -05:00
Darren Schroeder cf0c9a7734 fix(cli): correct the --mcp-host help text and example (#19268)
## Description

Three gaps in type aliases (#19223), plus a typo in `nu --help`.

- `hide` didn't know about type aliases. `hide Id` left the alias
usable, `hide <module> *` left the module's aliases in scope, and `hide
<module> Animal` failed with "Export not found."
- `help modules <name>` and `scope modules` didn't list the type aliases
a module exports, so the only way to find them was to read the module's
source.
- `type ls` is how Bash and cmd.exe show what a command is. In Nushell
it failed with "type missing sign", a label that pointed at nothing, and
no hint.
- `nu --help` described `--mcp-host` as the "host for MCP HTTP
transhost", and its example used `--mcp-transhost`, which isn't a flag.
The typo came in with #18952.

## User-facing changes (Release notes)

- `hide` now hides type aliases. `hide Name` hides the type alias `Name`
when no alias or command has that name, and `hide <module> Name`, `hide
<module> [Name ...]` and `hide <module> *` hide a module's exported type
aliases along with its commands.
- `help modules <name>` lists the type aliases a module exports, and
`scope modules` has a new `type_aliases` column with each alias's
`name`, `type` and `type_alias_id`.
- `type ls` and other `type` statements without `=` now explain how to
write a type alias, and for `type <name>` they point to `which <name>`
and `^type <name>`.
- Fixed the `--mcp-host` description and example in `nu --help`.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-16 11:47:49 -05:00
Monster-GM cfeea823ea fix: report missing closure blocks instead of panicking (#19159)
## Description

When a job is spawned before a later input is parsed, the job retains an
older `EngineState`. The later closure's `BlockId` is therefore
unavailable in that job, which previously panicked in
`EngineState::get_block`.

- remove the infallible `ClosureEval` / `ClosureEvalOnce` constructors
and make every `try_new*` constructor take a span pointing at the
failing call or closure value, so a stale `BlockId` can no longer panic
through any entry point (`do`, `each`, `zip`, `where`, …)
- add `EngineState::get_closure_block` as the single fallible lookup
with a span and actionable help (shared `MISSING_CLOSURE_BLOCK_HELP`
const); direct `get_block` callers on runtime closure values (`tee`,
`with-env`, `export-env`, `explain`, `view source`, `record where`, `job
spawn`, `debug profile`, the hook runner and the tui `closure_arity`)
now report the same error instead of panicking
- `debug profile` checks the block before installing the profiler, and
`job spawn` checks before registering the job, so the error reaches the
caller's `try`/`catch` instead of the background thread
- best-effort consumers degrade instead of panicking: `describe
--detailed` omits the `signature` key, `to text` / `to toml --serialize`
fall back to the existing placeholder string, `to yaml --serialize`
returns the `closure_block_not_found` error, and
`Closure::coerce_into_string` (`to msgpack`, `to kdl`) returns
`CantConvert`
- `par-each` builds the evaluator once in `run` (skipping empty input
like `each`) and clones it into the workers, returning a single error
instead of one error value per item
- `default` propagates the construction error instead of storing it as
the default value
- `generate` reads the signature from the evaluator's `block()` instead
of looking the block up twice
- `ClosureEval` / `ClosureEvalOnce` expose `block()`, removing the
remaining second lookups in `record where`, the tui `call_closure` and
`generate`
- convert the `record` commands from #19190 to the fallible constructors
- add regression tests that reproduce the interactive, multi-input `job
spawn` / `job send` flow from #19147 through `do`, `each`, `zip`, `tee`,
`par-each`, `record each`, `view source`, `describe --detailed`, `to
text --serialize`, `debug profile`, `job spawn`, and a combined test for
`with-env`, `explain`, `generate`, `record where`, `record walk` and
`sort-by`

Removing the infallible constructors is a breaking change to nu-engine's
public API without a deprecation step: a deprecated shim cannot avoid
the panic, which is what this PR removes, so the break is intentional.

## User-facing changes (Release notes)

- Fixed an issue where a closure created after a job was spawned
panicked the job when used (`do`, `each`, `zip`, `tee`, `par-each`,
`sort-by`, `explain`, `with-env`, `job spawn`, …). Nushell now reports
`Closure cannot be evaluated` with a span and a hint instead, and `job
spawn` / `debug profile` now surface the error to the caller.
- Serializing such a closure no longer crashes: `describe --detailed`
and `to text` / `to toml --serialize` degrade to the existing
placeholder, while `to yaml --serialize` and `to msgpack` report a
conversion error.

## Additional notes

- fixes #19147
- rebase note: this branch now includes the conversion of the `record`
commands merged in #19190, which called the removed constructors

## Validation

- `cargo test -p nu-command --test tests job` (44 passed; do / each /
zip / tee / par-each / record each / record where / record walk / view
source / describe / to text / debug profile / job spawn / with-env /
explain / generate / sort-by scenarios)
- `cargo test -p nu-command --test tests` (3438 passed; the 21 failures
are pre-existing Windows symlink-privilege environment failures,
confirmed identical on upstream main)
- `cargo test` for nu-engine, nu-cmd-lang, nu-protocol, nu-tui,
nu-cmd-base, nu-color-config, nu-heavy-utils, nu-cli, nu-cmd-extra,
nu-lsp, nu-dap, nu-plugin-engine (only the same symlink-privilege
failures, confirmed on upstream main)
- `cargo test -p nu-engine --doc`, `cargo test -p nu-protocol --doc`
- `cargo fmt --all -- --check`
- `cargo clippy -p nu-engine -p nu-cmd-lang -p nu-command -p nu-cli -p
nu-cmd-extra -p nu-color-config -p nu-plugin-engine -p nu-tui -p
nu-protocol -p nu-cmd-base -p nu-heavy-utils --tests --no-deps -- -D
warnings`
2026-10-16 11:12:58 -05:00
Tino f97cd76f21 Rename fetch_update to try_update (#19267)
## Description

`std::sync::atomic::Atomic::fetch_update` has been renamed to
`try_update` with the former working as a [deprecated
alias](https://github.com/rust-lang/rust/issues/135894) for the latter.
This PR renames each mention of `fetch_update` with `try_update` in
order to avoid displaying two warnings during each build.

## User-facing changes (Release notes)

n/a

## Additional notes
2026-10-16 09:26:55 -05:00
Darren Schroeder 430207e98e fix(mcp): list and look up commands by the name they're called by (#19262)
## Description

The MCP server's `list_commands` and `command_help` tools name each
command by its signature, and a signature's name isn't always a name you
can call.

Driving `nu --mcp` over stdio. The session first runs the `evaluate`
tool with `alias st = str trim` and with `module spam { export def "foo
bar" [] {} }; use spam`. Before is main at 07b01e2f3, after is this
branch.

`list_commands` with `find: "trim"`:

Before:

```nushell
str trim {flags} ...(rest)  - Alias for `str trim`
str trim {flags} ...(rest)  - Trim whitespace or specific character.
```

After:

```nushell
st {flags} ...(rest)  - Alias for `str trim`
str trim {flags} ...(rest)  - Trim whitespace or specific character.
```

`command_help` with `name: "st"`:

Before:

```nushell
command `st` not found
```

After:

```nushell
Command: st
Usage: st {flags} ...(rest)

Description: Alias for `str trim`
```

`command_help` with `name: "str trim"`:

Before:

```nushell
Command: str trim
Usage: str trim {flags} ...(rest)

Description: Alias for `str trim`
```

After:

```nushell
Command: str trim
Usage: str trim {flags} ...(rest)

Description: Trim whitespace or specific character.
```

`list_commands` with `find: "foo bar"`:

Before:

```nushell
foo bar  -
```

After:

```nushell
spam foo bar  -
```

`command_help` with `name: "spam foo bar"`:

Before:

```nushell
command `spam foo bar` not found
```

After:

```nushell
Command: spam foo bar
Usage: spam foo bar
```

`command_help` with `name: "foo bar"` used to work and now returns
``command `foo bar` not found``. You can't call the command by that name
after `use spam`.

"Did you mean" suggestions print the same on main and this branch. For
example, `use std/dirs; goto` still suggests `dirs goto`, `use std/dirs;
gt` still suggests `get`, and `^str-trimm` still suggests `str trim`.


## User-facing changes (Release notes)

The MCP server's `list_commands` and `command_help` tools now name each
command the way you call it. An alias such as `alias st = str trim` is
listed as `st` instead of as a second `str trim`, `command_help st`
works, and defining the alias no longer replaces `str trim`'s help with
the alias's. Module commands are listed under the name `use` gives them,
such as `spam foo bar` after `use spam`.


## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-16 08:20:49 -05:00
Darren Schroeder 6112446c3c fix(help): drop hidden subcommands and fix multi-line, backticked, and script alias entries (#19261)
## Description

Follow-up to #19253, which lists an alias in `help <command>` under its
own name, right after the subcommand it runs. Four cases are still wrong
on main:

- A hidden custom subcommand is still listed. #19253 only dropped hidden
aliases.
- An alias written over several lines splits its entry across lines.
- With color on, backticks inside an alias's expansion confuse the
highlighter. The inner backticks disappear and the outer ones stay.
- A script's `alias mb = main bar` is missing from `script.nu --help`,
though `mb` works inside the script.

With this PR, `help` leaves out a hidden subcommand of any kind, joins
an alias's expansion onto one line and highlights it as a whole, and
lists a script alias of a `main` subcommand right after that subcommand.

Each example shows the Subcommands section of `help`. Before is main at
776da6de4 (which includes #19253), after is this branch. Color is
stripped.

A hidden custom subcommand was still listed. You can't call it, so it's
left out now.

```nushell
def foo [] {}; def "foo bar" [] {}; def "foo qux" [] {}; hide "foo qux"; help foo
```

Before:

```nushell
Subcommands:
  foo bar (custom) -
  foo qux (custom) -
```

After:

```nushell
Subcommands:
  foo bar (custom) -
```

An alias written over several lines split its entry across lines. The
entry joins them now.

```nushell
def foo [] {}; def "foo bar" [x] {}
alias fm = foo bar (
  'a'
)
help foo
```

Before:

```nushell
Subcommands:
  foo bar (custom) -
  fm (alias) - Alias for `foo bar (
  'a'
)`
```

After:

```nushell
Subcommands:
  foo bar (custom) -
  fm (alias) - Alias for foo bar ( 'a' )
```

Backticks inside the expansion lost their place. The highlighter dropped
the inner pair and kept the outer one.

```nushell
def foo [] {}; def "foo bar" [x] {}; alias fq = foo bar `x y`; help foo
```

Before:

```nushell
Subcommands:
  foo bar (custom) -
  fq (alias) - Alias for `foo bar x y`
```

After:

```nushell
Subcommands:
  foo bar (custom) -
  fq (alias) - Alias for foo bar `x y`
```

A script alias of a `main` subcommand was missing from the script's
help.

```nushell
# script.nu
def "main bar" [] {}
alias mb = main bar
alias "main baz" = main bar
def main [] {}
```

```nushell
nu script.nu --help
```

Before:

```nushell
Subcommands:
  script.nu bar (custom) -
  script.nu baz (alias) - Alias for main bar
```

After:

```nushell
Subcommands:
  script.nu bar (custom) -
  mb (alias) - Alias for main bar
  script.nu baz (alias) - Alias for main bar
```

The other cases #19253 fixed print the same on main and this branch:
`fb` after `foo bar`, `st` after `str trim` (with or without a doc
comment), `spam fb` and `foo baz` from a module, and a top-level `alias
"foo baz" = foo bar`.


## User-facing changes (Release notes)

`help <command>` no longer lists hidden subcommands. An alias of a
subcommand written over several lines, or containing backticks, now
shows on one line with its full expansion. A script's `alias mb = main
bar` now appears in `script.nu --help`, right after `script.nu bar`.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-16 07:47:22 -05:00
Darren Schroeder 07b01e2f37 fix(parser): try string last in oneof so oneof<string, list<string>> parses [a b] as a list (#19238)
## Description

The order of the types in a `oneof` changed what a literal argument
parsed as:

```nushell
> def show [x: oneof<string, list<string>>] { $x | describe }
> show [foo bar]
string
> def show [x: oneof<list<string>, string>] { $x | describe }
> show [foo bar]
list<string>
```

`parse_oneof` returns the first shape that parses without error, and the
`string` shape accepts nearly any single token as a bare word. With
`string` listed first, every type after it was unreachable from a
literal:

| `oneof<string, X>` | literal | parsed as (before) | parsed as (after)
|
| --- | --- | --- | --- |
| `list<string>` | `[foo bar]` | `"[foo bar]"` | `[foo, bar]` |
| `table` | `[[a]; [1]]` | `"[[a]; [1]]"` | `table<a: int>` |
| `int` | `5` | `"5"` | `5` |
| `number` | `1.5` | `"1.5"` | `1.5` |
| `duration` | `5sec` | `"5sec"` | `5sec` |
| `filesize` | `5kb` | `"5kb"` | `5kb` |
| `range` | `1..5` | `"1..5"` | `1..5` |
| `datetime` | `2024-01-01` | `"2024-01-01"` | `2024-01-01` |
| `binary` | `0x[ff]` | `"0x[ff]"` | `0x[FF]` |

`oneof<path, list<path>>` and `oneof<glob, list<glob>>` had the same
problem, and so did parameter defaults and list elements: `[x:
oneof<string, int> = 5]` defaulted to the string `"5"`, and
`list<oneof<string, int>>` parsed `[1 a]` as `["1", a]`. Both now give
ints. The type check doesn't depend on order, so `let x = [foo bar];
show $x` already passed a list.

## User-facing changes (Release notes)

In `oneof<...>` parameter types, `string`, `path`, `directory`, `glob`,
`cell-path`, `external_arg` and `any` no longer claim a literal that
another listed type matches, whatever order the types are listed in.
`oneof<string, list<string>>` now parses `[foo bar]` as a list, and
`oneof<string, int>` parses `5` as the int `5` instead of the string
`"5"`. A bare word that no other listed type matches still parses as a
string, and arguments starting with `$`, `(` or `{` parse as before.

A literal that looks like one of the other types now gets that type, so
quote it if you need the text. With `oneof<string, int>`, `007` arrives
as `7` and `0x10` as `16`. With `oneof<string, number>`, `1.10` arrives
as `1.1` and `nan` as a float. With `oneof<string, list<string>>`, a
character class like `[0-9]` arrives as the list `["0-9"]`. This also
applies to `extern` parameters, which pass the converted value to the
external command.

Parameters declared as plain `string` are unchanged: `[foo bar]` passed
to one is still the string `"[foo bar]"`.

## Additional notes

closes https://github.com/nushell/nushell/issues/16445
2026-10-16 06:53:12 -05:00
赤坂理子 356e7bc02f Preserve REPL background jobs on Ctrl-C and clean up jobs on non-REPL exit (#19163)
## Summary

- Addresses #18989 by preserving REPL background and frozen jobs during
foreground `Ctrl-C`, while non-REPL commands and scripts clean up jobs
even when an interruption is caught
- Determine execution mode once (REPL, command, script, server) without
conflating `-i` with an interactive REPL; explicit `exit` in `-i -c` or
`-i` script preserves requested exit code, while REPL retains first-exit
warning and second-exit cleanup
- Serialize OS process creation and PID registration against `ThreadJob`
shutdown under the PID lock to eliminate an orphan-process race
- Clear cloned `is_repl` flag in background job engine clones so `exit`
terminates their closure instead of warning and continuing
- Centralize forced cleanup and lock-poison recovery, completing
non-REPL cleanup before publishing interrupts while preserving early
signal-handler initialization
- Windows combines `CREATE_NEW_PROCESS_GROUP` and `CREATE_NO_WINDOW`
inside `ForegroundChild` without an extra exported preparation helper;
new process groups isolate `Ctrl-C` but `Ctrl+Break` is NOT isolated
- Cross-platform lifecycle tests use Nu as the child, bounded handshakes
and Windows owned process handles opened before child exit to avoid PID
reuse
- Add tests for lock registration, chained spawns, explicit exit, REPL
two exits and background exit; remove fixed 500ms sleep
- Fix minimal-feature plugin-only import warning for `absolute_with`

## Testing

Verified on macOS on top of `ca323a65bdb7c945488b75a5f7bf5d90a8f3bff1`:
- 29 background job regressions, 3 `ThreadJob` tests, and 47 root unit
tests passed
- Shell suite: 320 passed, 6 ignored
- Related crate tests and doctests ran with `--no-fail-fast` for
`nu-protocol`, `nu-engine`, `nu-command`, `nu-system`, `nu-cli`; all
passed except one existing `cp` debug test
- Chained-spawn stress test produced 0/1000 leaks versus 5/50 on
original head; `-i -c "exit 3"` returns 3 without running subsequent
code
- `cargo fmt --all --check` passed
- Clippy passed with `-D warnings` on `--all-targets` for `nu`,
`nu-protocol`, `nu-engine`, `nu-command`, `nu-system`, `nu-cli`
- Minimal-feature check passed for `--bin nu`
- WASM target checks passed for `nu-command`, `nu-engine`,
`nu-protocol`, `nu-system`
- Windows cross-compilation check passed for `nu-engine`, `nu-protocol`,
`nu-system` libraries

## Remaining validation

Open verification limits and pending checks:
- Local `cp` debug test expects `reflink: unsupported` but this macOS
returns `reflink: yes`, confirmed identically on original published head
`ca323a65bdb7c945488b75a5f7bf5d90a8f3bff1`
- `cargo check --no-default-features --all-targets` fails on existing
`nu-plugin-engine` `ServerCommunicationIo::LocalSocket` non-exhaustive
match, reproduced in an isolated original-head source and target tree
- Windows real-console `GenerateConsoleCtrlEvent` integration test is
still missing and `ping -t` reproduction has not been performed;
compile-only Windows checks do not establish runtime behavior, so
Windows review remains open
- Updated GitHub CI validation is pending publication

---------

Signed-off-by: akasakariko <148060537+akasakariko@users.noreply.github.com>
2026-10-16 06:44:50 -05:00
Darren Schroeder 776da6de47 Let metadata <expr> and stor insert/update record flags ignore pipeline input instead of erroring (#19254)
## Description

`metadata` with an argument fails when the call also has pipeline input:

```nushell
[1] | each {|x| let s = (metadata $x).span; $s }
# Error: nu::shell::incompatible_parameters
#   pipeline input was provided / but a positional metadata expression was also given
```

The user never piped anything into `metadata` here. The first statement
of a block receives the block's input, which is intended (`"a" | do {
let x = (str uppercase); $x }` returns `A`), so `metadata` gets the
closure's input along with `$x` and refuses. The same check rejects `"a"
| metadata $in`, because `$in` stores the input in the variable and
still passes it to the call.

The check came in with another PR. A command can't tell implicit block
input from an explicit pipe at run time: both arrive as ordinary
`PipelineData` in the same register.

This PR removes the check. When `metadata` gets an argument, the result
describes only that argument: a record with its `span`. The input and
its pipeline metadata are ignored. Before #16049 the argument's span was
merged with the input's pipeline metadata, which attached the input's
metadata to an unrelated value:

```nushell
open Cargo.toml | metadata 5
# {span: ..., source: ".../Cargo.toml"}    <- input's source reported for the literal 5
ls | do { let m = (metadata $env.PWD); $m }
# {span: ..., path_columns: [name], ...}   <- ls's path columns reported for $env.PWD
```

`stor insert --data-record` and `stor update --update-record` had the
same input-versus-argument check and failed the same way inside a block:

```nushell
[{a: 1}] | each {|r| stor insert -t t -d $r }
# Error: Pipeline and Flag both being used
```

## User-facing changes (Release notes)

- `metadata <expression>` no longer errors when the call also has
pipeline input, such as the input a block's first statement receives
(`[1] | each {|x| let s = (metadata $x).span; $s }`) or `"a" | metadata
$in`. With an argument, `metadata` returns that argument's span and
ignores the input; `metadata` without an argument still reports the
input's pipeline metadata.
- `stor insert --data-record` and `stor update --update-record` no
longer error with "Pipeline and Flag both being used" when the call also
has pipeline input. The flag's record takes precedence and the input is
ignored.

## Additional notes

- Since the input is ignored whenever an argument is given, an explicit
pipe into these calls is now dropped without an error too (`ls |
metadata $x`, `ls | stor insert -t t -d {a: 1}`). Erroring only on an
explicit pipe would need the compiler to mark implicit block input,
which no command can see today.
- `metadata $in` returns only the span. The input's `path_columns`,
`content_type` and custom keys are not included; use `metadata` without
an argument for those. (`source` from `open` is already removed when the
input is collected into `$in`.)
2026-10-16 06:13:55 -05:00
Darren Schroeder 9398108ce7 fix(help): list an alias in a command's subcommands under its own name (#19253)
## Description

`help <command>` lists aliases of the command's subcommands, which makes
`help str` a place to discover `st` after `alias st = str trim`. On main
the entry used the wrong name. It showed the alias under the name of the
command it wraps, so `str trim` appeared twice and `st` appeared
nowhere. A hidden alias stayed listed, and a script alias named like a
`main` subcommand was missing.

With this PR an alias is listed under the name you call it by, right
after the subcommand it runs, and its entry always says what it runs:
``st (alias) - Alias for `str trim` ``.


Each example shows the Subcommands section of `help`. Before is main at
f443a4fbe, after is this branch. Color is stripped; in a terminal the
backticked part of ``Alias for `str trim` `` is shown as highlighted
code.

An alias of a custom subcommand showed up as a second `foo bar`.

```nushell
def foo [] {}; def "foo bar" [] {}; alias fb = foo bar; help foo
```

Before:

```nushell
Subcommands:
  foo bar (alias) - Alias for foo bar
  foo bar (custom) -
```

After:

```nushell
Subcommands:
  foo bar (custom) -
  fb (alias) - Alias for foo bar
```

A hidden alias was still listed. You can't call it, so it's left out
now.

```nushell
def foo [] {}; def "foo bar" [] {}; alias fb = foo bar; hide fb; help foo
```

Before:

```nushell
Subcommands:
  foo bar (alias) - Alias for foo bar
  foo bar (custom) -
```

After:

```nushell
Subcommands:
  foo bar (custom) -
```

Builtins behaved the same way. `str trim` was listed twice.

```nushell
alias st = str trim; help str
```

Before:

```nushell
Subcommands:
  ...
  str trim - Trim whitespace or specific character.
  str trim (alias) - Alias for str trim
  str upcase - Convert text to uppercase.
  ...
```

After:

```nushell
Subcommands:
  ...
  str trim - Trim whitespace or specific character.
  st (alias) - Alias for str trim
  str upcase - Convert text to uppercase.
  ...
```

A doc comment on the alias replaced its description, so the entry no
longer said what the alias runs. The entry now always does. The comment
still shows in `help st`.

```nushell
# trim both ends
alias st = str trim; help str
```

Before:

```nushell
Subcommands:
  ...
  str trim - Trim whitespace or specific character.
  str trim (alias) - trim both ends
  str upcase - Convert text to uppercase.
  ...
```

After:

```nushell
Subcommands:
  ...
  str trim - Trim whitespace or specific character.
  st (alias) - Alias for str trim
  str upcase - Convert text to uppercase.
  ...
```

An alias exported from a module is listed under the name `use` gives it.

```nushell
module spam { export def foo [] {}; export def "foo bar" [] {}; export alias fb = foo bar }
use spam
help spam foo
```

Before:

```nushell
Subcommands:
  foo bar (alias) - Alias for foo bar
  foo bar (custom) -
```

After:

```nushell
Subcommands:
  foo bar (custom) -
  spam fb (alias) - Alias for foo bar
```

A module alias named like a subcommand was listed under the wrapped
command's name, `foo bar`, instead of its own, `foo baz`.

```nushell
module spam { export def foo [] {}; export def "foo bar" [] {}; export alias "foo baz" = foo bar }
use spam
help spam foo
```

Before:

```nushell
Subcommands:
  foo bar (alias) - Alias for foo bar
  foo bar (custom) -
```

After:

```nushell
Subcommands:
  foo bar (custom) -
  foo baz (alias) - Alias for foo bar
```

A script alias named like a `main` subcommand was missing from the
script's help, even though `nu script.nu baz` runs it.

```nushell
# script.nu
def "main bar" [] {}
alias "main baz" = main bar
def main [] {}
```

```nushell
nu script.nu --help
```

Before:

```nushell
Subcommands:
  script.nu bar (custom) -
```

After:

```nushell
Subcommands:
  script.nu bar (custom) -
  script.nu baz (alias) - Alias for main bar
```
## User-facing changes (Release notes)

`help <command>` now lists an alias of one of its subcommands under the
alias's own name, right after the subcommand it runs, with ``Alias for
`...` `` as its description. After `alias st = str trim`, `help str`
shows ``st (alias) - Alias for `str trim` `` below `str trim`, where it
used to show a second `str trim` line. A hidden alias is no longer
listed, and a script's `alias "main baz" = main bar` now appears in
`script.nu --help` as `script.nu baz (alias)`.

## Additional notes
2026-10-16 06:13:14 -05:00
Darren Schroeder c8095a3d10 fix(each): report the closure's error instead of "Eval block failed with pipeline input" (#19252)
## Description


The commands `each`, `par-each`, and `items` wrap an error raised by
their closure in `ShellError::EvalBlockWithInput`. That variant had its
own message, "Eval block failed with pipeline input", its own code,
`nu::shell::eval_block_with_input`, and kept the closure's error in
`#[related]`. So `catch` saw the wrapper's text, and the report printed
the generic wrapper first and the error that mattered second:

```nushell
> try { [1] | each { error make {msg: inner} } } catch {|e| $e.msg }
Eval block failed with pipeline input
> try { for x in [1] { error make {msg: inner} } } catch {|e| $e.msg }
inner
```

The variant now holds an `EvalBlockWithInputError`, a struct with a
hand-written `Diagnostic` impl in
`crates/nu-protocol/src/errors/shell_error/eval_block_with_input.rs`. It
forwards to the wrapped error the same way `ChainedError` does for a
single source, and adds one label.

## User-facing changes (Release notes)

When a closure passed to `each`, `par-each`, or `items` fails, Nushell
now reports the closure's error. The input value it was processing is
shown as an extra `source value` label. `$e.msg` in `catch` is the
closure's message, and the error code is the closure error's code
instead of `nu::shell::eval_block_with_input`.

Before:

```nushell
> [1 2] | each {|x| $x / 0 }
Error: nu::shell::eval_block_with_input

  × Eval block failed with pipeline input
   ╭─[source:1:2]
 1 │ [1 2] | each {|x| $x / 0 }
   ·  ┬
   ·  ╰── source value
   ╰────

Error: nu::shell::division_by_zero

  × Division by zero.
   ╭─[source:1:22]
 1 │ [1 2] | each {|x| $x / 0 }
   ·                      ┬
   ·                      ╰── division by zero
   ╰────
```

After:

```nushell
> [1 2] | each {|x| $x / 0 }
Error: nu::shell::division_by_zero

  × Division by zero.
   ╭─[source:1:2]
 1 │ [1 2] | each {|x| $x / 0 }
   ·  ┬                   ┬
   ·  │                   ╰── division by zero
   ·  ╰── source value
   ╰────
```


## Additional notes

Two fixes for code running inside these closures:

- `exit` works. `[1] | each { exit 4 }` exits with 4, and `try { [1] |
each { exit 4 } } catch { ... }` no longer runs the `catch` block.
- An external's exit code survives. `try { [1] | each { ^sh -c 'exit 42'
} } catch {|e| $e.exit_code }` is `42`, and so is `$env.LAST_EXIT_CODE`.

Scripts that matched the code `nu::shell::eval_block_with_input`, or
read `$e.details.inner.0` to reach the closure's error, should use
`$e.msg` / `$e.details.msg` instead
2026-10-16 06:12:44 -05:00
Darren Schroeder b1bf5c4739 fix(parser): treat a bare word after and/or/xor in a row condition as a column (#19251)
## Description

In a row condition, a bare word on the right of `and`, `or` or `xor`
parsed as a string instead of a column:

```nushell
> [{a: false, b: false}] | where not a and not b
Error: nu::shell::cant_convert
  × Can't convert to boolean.
```
```nushell
> [{a: true, b: true}] | where a and b
Error: nu::shell::operator_unsupported_type
  × The 'and' operator does not work on values of type 'string'.
```

## User-facing changes (Release notes)

Fixed row conditions (`where`, `any`, `all`, `take while` and the
others) so a bare column name after `and`, `or` or `xor` refers to the
column, the same as the first term:

```nushell
[{a: false, b: false}] | where not a and not b   # was a "can't convert string to boolean" error
[{a: true, b: true}] | where a and b             # was "'and' does not work on values of type 'string'"
```

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-16 06:12:11 -05:00
Darren Schroeder b862a8121b Add type aliases with a type keyword (#19223)
## Description

This PR adds `type Name = <type>` (#13484, and the type-alias part of
#11108). A type alias gives a name to a type, and the parser replaces
the name with that type wherever it appears.

```nushell
type LsType = table<name: string, type: string, size: filesize, modified: datetime>

def my-ls []: nothing -> LsType { ls }
def process-files [files: LsType] { $files | where size > 1mb }
```

How it works:

- An alias is pure expansion. The parser stores the right-hand side as a
`SyntaxShape` and copies it at every use. `Type`, `SyntaxShape`,
`describe` and the plugin protocol don't change, and `help`, `scope
commands` and error messages show the expanded type.
- An alias works in parameters, flags, rest parameters, closure
parameters, input/output types, `let`/`mut`/`const` annotations, inside
generic types such as `list<Point>`, and on the right-hand side of
another `type`.
- A completer stays on the parameter, unlike the `string@animals` sketch
in #13484: `def paint [c: Color@[red green blue]]`. `type Color =
string@[red green blue]` is an error, "Unexpected custom completer in
type spec", as in a `let` annotation. Most places an alias can appear
have no completer, such as `list<Color>`, input/output types and `let`,
so one stored on the alias would apply in some uses and silently not in
others.
- Aliases are defined in order, like `alias` and `const`. Using one
above its definition is an error that points at both places, and an
alias can't refer to itself.
- Scoping follows `alias` and `const`: local to a block, private in a
module unless exported, and kept across REPL lines.
- `export type` exports an alias. `use mod Name`, `use mod [Name]`, `use
mod *`, `export use` and an unprefixed `overlay use` import it. A bare
`use mod` doesn't, because a type name can't take the `mod ` prefix that
commands get.
- `type` and `export type` are reserved like `def`, `alias` and `const`.
A `def type`, `extern "type"` or `alias type = ...` fails with "Can't
use parser keyword `type` as command name", and `alias ty = type` is an
error. #13484 asked for existing `type` commands to keep working;
reserving the name breaks them, but at the definition, with an error
that names it. A keyword that a `type` command could shadow fails later:
every `type Foo = int` after it becomes "Assignment operations require a
variable". nu_scripts' generated
`custom-completions/auto-generate/completions/type.nu` declares `extern
"type"`, so `source`-ing it is one way to hit that.

## User-facing changes (Release notes)

You can now name a type with `type`:

```nushell
type Point = record<x: float, y: float>
type Polygon = list<Point>

def first-x [poly: Polygon]: nothing -> float { $poly.0.x }
```

A type alias can be used anywhere a type annotation can, including
inside other types. A parameter of an aliased type takes a completer
like any other: `def paint [color: Color@[red green blue]]`. Export an
alias from a module with `export type`, and import it by name, in a
list, or with `*`.

`type` is now a reserved word, like `def` and `let`. A script that
defines its own `type` command, alias or extern stops with "Can't use
parser keyword `type` as command name" until that definition is renamed.
On macOS, a bare `type ls` no longer runs `/usr/bin/type`. Use `^type`,
or nushell's `which`.

## Additional notes
2026-10-16 06:10:27 -05:00
draconacht 818d4ac064 update eml-parser version to 0.1.6 (#19257)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description
<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->
eml-parser updated from v0.1.5 to v0.1.6.
this includes a bugfix for parsing mail addresses in email headers in
the `from eml` command (From: To: etc.)
https://github.com/aeshirey/EmlParser/pull/18

## User-facing changes (Release notes)
<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->

emails with unquoted names are now parsed into name-address records
instead of plain strings.

## Additional Info

input / output behaviour:

| Input | Current behavior | New behavior |
|---|---|---|
| `"john doe" <john.doe@johnmail.com>` | `{ name: "john doe", address:
"john.doe@johnmail.com" }` | `{ name: "john doe", address:
"john.doe@johnmail.com" }` (unchanged) |
| `john.doe@johnmail.com` | `{ name: "", address:
"john.doe@johnmail.com" }` | `{ name: "", address:
"john.doe@johnmail.com" }` (unchanged) |
| `john doe <john.doe@johnmail.com>` | `"john.doe
<john.doe@johnmail.com>"` (plain string) | `{ name: "john doe", address:
"john.doe@johnmail.com" }` |

while the new behaviour is "correct", it may be a breaking change for
many users (including my own scripts) which expect senders / recipients
to be parsed as plain strings. i still think this to be the correct
thing to do.
2026-10-15 15:53:18 -05:00
Akshit Joshi 701dc77c9e fix(cli): accept /c as commands flag (#19148)
## Description

Windows programs that use `ComSpec` commonly call the configured shell
with `/c` to run a command. When `ComSpec` points to `nu.exe`, Nushell
treated `/c` as a script path and reported that it could not open `/c`.

On Windows, `/c` and `/C` are now recognized during CLI argument parsing
as the ComSpec command switch. The text after `/c` is read from the raw
process command line (`GetCommandLineW`) so the original quoting is
preserved, and that text is run as Nushell code. This mirrors how `cmd
/c` runs the rest of the command line, rather than Nushell's `-c`, which
takes a single code argument. When the raw command line is unavailable,
the remaining argv entries are joined with spaces as a best effort.

This behavior is Windows-only. On other platforms `/c` remains a normal
path, and `/c` after the `--` end-of-options delimiter is always treated
as a script name.

## User-facing changes (Release notes)

On Windows, Nushell now accepts `/c` and `/C` as the ComSpec command
switch and runs the following command line as Nushell code, improving
compatibility when `nu.exe` is used as `ComSpec`. This change does not
affect other platforms.

## Additional notes

Fixes #7993

Tests:
- `cargo test -p nu --bin nu slash_c`
- `cargo test -p nu --test tests log_`
2026-10-15 14:39:28 -05:00
Akshit Joshi 684d24b0ba fix(std/help): preserve external help arguments (#19149)
## Description

`std/help` falls back to an external helper, usually `man` or
`$env.NU_HELPER`, when the requested help target is not an internal
command, alias, or module.

Before this change, the fallback joined all requested words into one
string and stripped every `^` and `%` from the target name. That broke
multi-word external help targets and changed names such as `test-%.nu`
into `test-.nu`.

This change keeps the command target as separate words and strips only
one leading `^` or `%` sigil from the first word.

## User-facing changes (Release notes)

Fixed `std/help` external fallback so multi-word help targets are passed
as separate arguments and `%` or `^` characters inside command names are
preserved.

## Additional notes

Fixes #18939

Tests:
- `cargo run -- -c 'use crates/nu-std/testing.nu; testing run-tests
--path crates/nu-std/tests --test external_help'`
2026-10-15 14:36:47 -05:00
Jan Klass 6a4027ff14 Fix conditional tutor text typos (#19218)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description
<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->

`tutor conditional` was introduced in 0.116.0 with these description
text typos, which are now fixed.

## User-facing changes (Release notes)
<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->

`tutor conditional` description text no longer has wording typos.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->

The 0.116.0 release notes list the command output. IMO it can stay
"wrong" to match the version behavior.
2026-10-15 07:39:19 -05:00
dependabot[bot] f443a4fbe4 build(deps): bump uuid from 1.27.0 to 1.28.0 (#19245)
Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.27.0 to 1.28.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/uuid-rs/uuid/releases">uuid's
releases</a>.</em></p>
<blockquote>
<h2>v1.28.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add optional serde format adapters by <a
href="https://github.com/RanaPriyansh"><code>@​RanaPriyansh</code></a>
in <a
href="https://redirect.github.com/uuid-rs/uuid/pull/916">uuid-rs/uuid#916</a></li>
<li>Prepare for 1.28.0 release by <a
href="https://github.com/KodrAus"><code>@​KodrAus</code></a> in <a
href="https://redirect.github.com/uuid-rs/uuid/pull/918">uuid-rs/uuid#918</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/RanaPriyansh"><code>@​RanaPriyansh</code></a>
made their first contribution in <a
href="https://redirect.github.com/uuid-rs/uuid/pull/916">uuid-rs/uuid#916</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/uuid-rs/uuid/compare/v1.27.0...v1.28.0">https://github.com/uuid-rs/uuid/compare/v1.27.0...v1.28.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/uuid-rs/uuid/commit/276c23628a669ca9fca637f3326c21b114e88049"><code>276c236</code></a>
Merge pull request <a
href="https://redirect.github.com/uuid-rs/uuid/issues/918">#918</a> from
uuid-rs/cargo/v1.28.0</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/4b3b9f55260d402ed3184577bc35a054ba9a28f4"><code>4b3b9f5</code></a>
prepare for 1.28.0 release</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/cbf9c818b89754a83d4ca54f2a9bf809e2476f67"><code>cbf9c81</code></a>
Merge pull request <a
href="https://redirect.github.com/uuid-rs/uuid/issues/916">#916</a> from
RanaPriyansh/fix/optional-serde-adapters-840</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/784a0229388c3df8d729eb212f0580d2617191b2"><code>784a022</code></a>
Inline expected tokens in optional compact serde test</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/a5678c3156831969fbd4573b7afdd0585d88e3a1"><code>a5678c3</code></a>
Simplify optional serde adapter tests to option tokens</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/638a5180ba347d52cd7eb60518dc751b1dfb2f80"><code>638a518</code></a>
Refactor optional serde adapter tests and share byte wrapper</li>
<li><a
href="https://github.com/uuid-rs/uuid/commit/654fa5b891d0346055d9d234599f80b06cf03a1c"><code>654fa5b</code></a>
Add optional serde format adapters</li>
<li>See full diff in <a
href="https://github.com/uuid-rs/uuid/compare/v1.27.0...v1.28.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 07:34:07 -05:00
dependabot[bot] 4dd122d388 build(deps): bump lean_string from 0.7.0 to 0.8.0 (#19241)
Bumps [lean_string](https://github.com/ryota2357/lean_string) from 0.7.0
to 0.8.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ryota2357/lean_string/blob/main/CHANGELOG.md">lean_string's
changelog</a>.</em></p>
<blockquote>
<h2>[0.8.0] - 2026-10-11</h2>
<h3>Added</h3>
<ul>
<li>Case conversion methods: <code>to_lowercase()</code>,
<code>to_uppercase()</code>, <code>to_ascii_lowercase()</code> and
<code>to_ascii_uppercase()</code> for <code>LeanString</code> and
<code>LeanStr</code>, and <code>make_ascii_lowercase()</code> and
<code>make_ascii_uppercase()</code> for <code>LeanString</code>. The
ASCII ones have fallible <code>try_</code> variants. If no character
changes, they don't allocate: the <code>to_</code> methods return a
clone, and the <code>make_</code> methods leave the string untouched,
even if it is shared with its clones.</li>
<li><code>LeanString::replace_range()</code>,
<code>LeanString::extend_from_within()</code> and
<code>LeanString::reserve_exact()</code>, with their fallible
<code>try_</code> variants.</li>
<li><code>LeanStr::repeat()</code> and
<code>LeanStr::try_repeat()</code>.</li>
<li><code>from_utf16le()</code>, <code>from_utf16be()</code>,
<code>from_utf16le_lossy()</code> and <code>from_utf16be_lossy()</code>
for <code>LeanString</code> and <code>LeanStr</code>, to decode UTF-16
from bytes.</li>
<li><code>as_static_str()</code> for <code>LeanString</code> and
<code>LeanStr</code>, which returns the underlying <code>&amp;'static
str</code> if the string holds one.</li>
<li>Conversions from and to more types:
<ul>
<li><code>From&lt;&amp;mut str&gt;</code> for <code>LeanString</code>
and <code>LeanStr</code>.</li>
<li><code>From&lt;&amp;LeanString&gt;</code> for <code>LeanStr</code>
and <code>From&lt;&amp;LeanStr&gt;</code> for
<code>LeanString</code>.</li>
<li><code>From&lt;LeanString&gt;</code>,
<code>From&lt;LeanStr&gt;</code>,
<code>From&lt;&amp;LeanString&gt;</code> and
<code>From&lt;&amp;LeanStr&gt;</code> for <code>Cow&lt;'_,
str&gt;</code>. A string holding a <code>&amp;'static str</code>
converts into <code>Cow::Borrowed</code> without allocating.</li>
<li><code>FromIterator&lt;LeanStr&gt;</code> for
<code>LeanString</code>, <code>FromIterator&lt;LeanString&gt;</code> for
<code>LeanStr</code>, and <code>FromIterator&lt;LeanString&gt;</code>
and <code>FromIterator&lt;LeanStr&gt;</code> for
<code>String</code>.</li>
<li><code>AsRef&lt;Path&gt;</code> for <code>LeanString</code> and
<code>LeanStr</code>, with the <code>std</code> feature.</li>
</ul>
</li>
</ul>
<h3>Changed</h3>
<ul>
<li>The MSRV is now Rust 1.88.0 (was 1.85.1).</li>
<li><strong>Breaking:</strong> <code>to_lowercase()</code>,
<code>to_uppercase()</code>, <code>to_ascii_lowercase()</code> and
<code>to_ascii_uppercase()</code> of <code>LeanString</code> and
<code>LeanStr</code>, and <code>LeanStr::repeat()</code>, now return
<code>LeanString</code> or <code>LeanStr</code> instead of
<code>String</code>. They were previously resolved to the
<code>str</code> methods through <code>Deref</code>.</li>
<li><strong>Breaking:</strong> <code>FromUtf16Error</code> now matches
<code>std</code>'s <code>FromUtf16Error</code>: it can no longer be
constructed outside this crate, and its message tells a lone surrogate
from an odd number of bytes.</li>
<li>Added <code>#[must_use]</code> to constructors, getters and methods
that return a new string, which may produce new warnings where their
result is discarded.</li>
<li>Modifying a string that shares its heap buffer with its clones now
copies it into the inline storage, rather than a new heap buffer, if its
contents fit there (e.g. after <code>truncate()</code>).</li>
<li><code>retain()</code> no longer copies a string shared with its
clones or created from a <code>&amp;'static str</code> when the
predicate keeps every character.</li>
<li>Creating a string short enough to be stored inline is even faster on
64-bit little-endian targets, as it is now assembled in registers
instead of copied with <code>memcpy</code> (about 2x for lengths near
the inline limit on aarch64, and about 5x for most lengths on
x86_64).</li>
<li>Creating a string from a <code>char</code> is several times faster,
as it is also built in registers.</li>
<li><code>push()</code> and <code>insert()</code> of a
<code>char</code>, and creating a heap-allocated string slightly over
the inline limit from a <code>&amp;str</code>, no longer call
<code>memcpy</code> to copy the bytes.</li>
<li><code>repeat()</code> fills the result by doubling the copied part
instead of appending the string <code>n</code> times, which is much
faster for a short string repeated many times.</li>
<li>With the <code>serde</code> feature, deserializing
<code>LeanString</code> and <code>LeanStr</code> asks the deserializer
for a <code>&amp;str</code> rather than an owned <code>String</code>,
which may save an intermediate allocation with some formats.</li>
</ul>
<h3>Fixed</h3>
<ul>
<li><code>try_to_lean_string()</code> and <code>try_to_lean_str()</code>
panicked on allocation failure for values converted through their
<code>Display</code> implementation, instead of returning an error.</li>
<li>A panic in <code>From&lt;Cow&lt;'_, str&gt;&gt;</code> for
<code>LeanString</code> and <code>LeanStr</code> now reports the
caller's location.</li>
<li>Corrected the documentation of <code>capacity()</code>,
<code>shrink_to_fit()</code>, <code>shrink_to()</code> and
<code>clear()</code> for strings created from a <code>&amp;'static
str</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/ryota2357/lean_string/commit/bf326fa5d9dfb848860ed46b1618fec51076d187"><code>bf326fa</code></a>
v0.8.0</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/023ff048de562274f8f5a53f3aa97af65b27a9e9"><code>023ff04</code></a>
chore: update deps</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/99b2573274bcadf10ab222723cc8c052151fdc4c"><code>99b2573</code></a>
perf: outline grow path in push_str</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/8d0868ad7a2304c5c22bcd3b45e86d190cc8e9b1"><code>8d0868a</code></a>
perf: add from_char benchmark</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/1fedeb4713a51e5ee23ca8ee18d9cb35b3d78234"><code>1fedeb4</code></a>
docs: add performance mention to README Properties</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/acd13ba30194dd80ee8235394189f9816fc9a7dd"><code>acd13ba</code></a>
docs: explain why Repr::as_bytes is compiled to a branch on x86</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/c2c6ff56ec6762428ea05c3724f0771d868369b5"><code>c2c6ff5</code></a>
feat: add LeanString::{try_,}extend_from_within</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/479ce9113577c6e62cbdc877cdf3ef4c542fc129"><code>479ce91</code></a>
docs: fix inaccurate statements in README and API docs</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/12948a658d9ce3a6b2e021ed1541064198ea19e7"><code>12948a6</code></a>
perf: copy text just over the inline size without going through memcpy
in Hea...</li>
<li><a
href="https://github.com/ryota2357/lean_string/commit/5b98e5b4265b3b809c42beb9c318efeec717c0bb"><code>5b98e5b</code></a>
perf: insert a char without going through memcpy</li>
<li>Additional commits viewable in <a
href="https://github.com/ryota2357/lean_string/compare/v0.7.0...v0.8.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 07:33:52 -05:00
dependabot[bot] 8739de4fd5 build(deps): bump similar from 3.1.0 to 3.2.0 (#18905)
Bumps [similar](https://github.com/mitsuhiko/similar) from 3.1.0 to
3.2.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/mitsuhiko/similar/blob/main/CHANGELOG.md">similar's
changelog</a>.</em></p>
<blockquote>
<h2>3.2.0</h2>
<ul>
<li>Added structured, line-oriented three-way merging through
<code>TextMerge</code>, with
merge and diff3 conflict output, configurable labels and marker sizes,
owned
and borrowed inputs, byte output, and whitespace-insensitive
comparison.</li>
<li>Added <code>WhitespaceMode</code> and
<code>TextDiffConfig::whitespace_mode</code> for Git-style
line comparisons that ignore changes in whitespace (<code>-b</code>) or
all whitespace
(<code>-w</code>).</li>
<li>Changed <code>Algorithm::Myers</code> to reduce unmatched/confusing
records and use
Git-style bounded, non-minimal splits on expensive searches, and added
<code>Algorithm::RawMyers</code> for the previous shortest-edit-script
behavior without
output-changing heuristics.</li>
<li>Improved heuristics and performance for most algorithms other than
LCS.</li>
<li>Improved large-input performance by avoiding quadratic Histogram
scans.</li>
</ul>
<h2>3.1.2</h2>
<ul>
<li>Fixed <code>Algorithm::Lcs</code> deadline fallback emitting edits
twice, which produced
out-of-bounds <code>DiffOp</code> ranges and panics when consuming
timed-out diffs. <a
href="https://redirect.github.com/mitsuhiko/similar/issues/97">#97</a></li>
<li>Fixed <code>Algorithm::Lcs</code> reporting identical subranges with
zero-based indices
instead of preserving the supplied range offsets. <a
href="https://redirect.github.com/mitsuhiko/similar/issues/98">#98</a></li>
<li>Fixed <code>Algorithm::Lcs</code> and <code>Algorithm::Hunt</code>
emitting zero-length delete
operations when both inputs are empty. <a
href="https://redirect.github.com/mitsuhiko/similar/issues/99">#99</a></li>
</ul>
<h2>3.1.1</h2>
<ul>
<li>Fixed <code>DiffOp</code> cursor positions when compacting adjacent
inserts/deletes and
in <code>Algorithm::Histogram</code> full-replacement output, ensuring
operations form
contiguous ranges. <a
href="https://redirect.github.com/mitsuhiko/similar/issues/95">#95</a></li>
<li>Renamed sample diff input files to a lexicographic
<code>caseNN.01.before_*</code> / <code>caseNN.02.after_*</code>
scheme.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/mitsuhiko/similar/commit/e3804055b844f5d0c3cb111f5f6276f60e07459a"><code>e380405</code></a>
chore(release): prepare 3.2.0</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/9133b3d1e4799f984d178f6bda28806f910ddd1e"><code>9133b3d</code></a>
ref: Update changelog</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/a56a53f4408cf50a0b3dd875d15f5075e187ae7d"><code>a56a53f</code></a>
feat(merge): add three-way text merging</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/7130d064d5ed5f27bf8e9a8c5594e754f21405db"><code>7130d06</code></a>
docs(examples): demonstrate whitespace-insensitive diffs</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/a635843e774d28f32778b4c0fe77f6485dab9a9f"><code>a635843</code></a>
feat(text): add whitespace-insensitive line diffs</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/6301178fc0bf7f19af93b87cf270433f5f712580"><code>6301178</code></a>
perf(myers): preserve sparse matches with record reduction</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/f16b309a57cba043570a5a1426bd5c17de2f544a"><code>f16b309</code></a>
perf(myers): add bounded heuristic search</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/accea7d2ffb976515b21931a3a465e9082249c65"><code>accea7d</code></a>
chore(clippy): resolve lint warnings</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/3a5162b43e3841350de703f67aef159ae74c00be"><code>3a5162b</code></a>
perf(algorithms): fast-path nearly disjoint ranges</li>
<li><a
href="https://github.com/mitsuhiko/similar/commit/fc32411398e13d30ab3d45852a2bb9c2f9a056b9"><code>fc32411</code></a>
feat(fuzzing): add isolated performance campaign runner</li>
<li>Additional commits viewable in <a
href="https://github.com/mitsuhiko/similar/compare/3.1.0...3.2.0">compare
view</a></li>
</ul>
</details>
<br />


> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 07:33:34 -05:00
dependabot[bot] c4c1aebfc2 build(deps): bump unicase from 2.9.0 to 2.10.0 (#19240)
Bumps [unicase](https://github.com/seanmonstar/unicase) from 2.9.0 to
2.10.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/seanmonstar/unicase/releases">unicase's
releases</a>.</em></p>
<blockquote>
<h2>v2.10.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Miscellaneous code cleanups by <a
href="https://github.com/Jules-Bertholet"><code>@​Jules-Bertholet</code></a>
in <a
href="https://redirect.github.com/seanmonstar/unicase/pull/84">seanmonstar/unicase#84</a></li>
<li>fix: yield three-character case folds in order by <a
href="https://github.com/yuxi-liu-wired"><code>@​yuxi-liu-wired</code></a>
in <a
href="https://redirect.github.com/seanmonstar/unicase/pull/85">seanmonstar/unicase#85</a></li>
<li>update to Unicode v18.0.0 by <a
href="https://github.com/seanmonstar"><code>@​seanmonstar</code></a> in
<a
href="https://redirect.github.com/seanmonstar/unicase/pull/86">seanmonstar/unicase#86</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/Jules-Bertholet"><code>@​Jules-Bertholet</code></a>
made their first contribution in <a
href="https://redirect.github.com/seanmonstar/unicase/pull/84">seanmonstar/unicase#84</a></li>
<li><a
href="https://github.com/yuxi-liu-wired"><code>@​yuxi-liu-wired</code></a>
made their first contribution in <a
href="https://redirect.github.com/seanmonstar/unicase/pull/85">seanmonstar/unicase#85</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/seanmonstar/unicase/compare/v2.9.0...v2.10.0">https://github.com/seanmonstar/unicase/compare/v2.9.0...v2.10.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/seanmonstar/unicase/commit/1e739ff80fe2297c52efda9d05f0bea1038a7eb9"><code>1e739ff</code></a>
v2.10.0</li>
<li><a
href="https://github.com/seanmonstar/unicase/commit/8813777f65b604b8b82022c5b05be83f29638260"><code>8813777</code></a>
update to Unicode v18.0.0 (<a
href="https://redirect.github.com/seanmonstar/unicase/issues/86">#86</a>)</li>
<li><a
href="https://github.com/seanmonstar/unicase/commit/afc3c16219c9720839f2f4c16a3ede52274df7d7"><code>afc3c16</code></a>
fix: yield three-character case folds in order (<a
href="https://redirect.github.com/seanmonstar/unicase/issues/85">#85</a>)</li>
<li><a
href="https://github.com/seanmonstar/unicase/commit/a8cbb74c20f05b2d5a89b3e43c89591a1871be4b"><code>a8cbb74</code></a>
Miscellaneous code cleanups (<a
href="https://redirect.github.com/seanmonstar/unicase/issues/84">#84</a>)</li>
<li>See full diff in <a
href="https://github.com/seanmonstar/unicase/compare/v2.9.0...v2.10.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 06:59:17 -05:00
dependabot[bot] a58b75827c build(deps): bump vedantmgoyal2009/winget-releaser from 4ffc7888bffd451b357355dc214d43bb9f23917e to b7370d4d152efdce803a26cc6ca9eee58cb2ad54 (#19244)
Bumps
[vedantmgoyal2009/winget-releaser](https://github.com/vedantmgoyal2009/winget-releaser)
from 4ffc7888bffd451b357355dc214d43bb9f23917e to
b7370d4d152efdce803a26cc6ca9eee58cb2ad54.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/b7370d4d152efdce803a26cc6ca9eee58cb2ad54"><code>b7370d4</code></a>
docs(funding): remove patreon</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/f29ed1ffd34f91223a2aebaa71beaab0901ff9fd"><code>f29ed1f</code></a>
docs: add Gedochao as a contributor for bug, code, and ideas (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/350">#350</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/c3648cc8cb02c1c6e612d8e87f7699142a34f1fe"><code>c3648cc</code></a>
fix: add missing shell property, rm undefined variable (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/346">#346</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/8e1180065275ff8d815d981788ee8592c8735b8c"><code>8e11800</code></a>
docs: add ReenigneArcher as a contributor for ideas (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/344">#344</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/d381fbbc8929b1fd92abcdd031ee0cff7bd517cd"><code>d381fbb</code></a>
feat: mv action logic to pwsh, pr url output, support repos across
owners (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/343">#343</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/a8fff44b123f115ce4c21543edf8b677376fc7e0"><code>a8fff44</code></a>
docs: update required permissions (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/341">#341</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/b3a5dae0047c6180023acba3f548c55fdf6b7193"><code>b3a5dae</code></a>
docs: fix allcontributors.com emoji key link (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/340">#340</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/7bd472be23763def6e16bd06cc8b1cdfab0e2fd5"><code>7bd472b</code></a>
docs: add description to inputs (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/335">#335</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/a43926ed822e5a076ac8a81e0a794915cbad51d1"><code>a43926e</code></a>
fix: cargo command not found in <code>ubuntu-slim</code> runner (<a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/334">#334</a>)</li>
<li><a
href="https://github.com/vedantmgoyal9/winget-releaser/commit/19e706d4c9121098010096f9c495a70a7518b30f"><code>19e706d</code></a>
fix: pwsh doesn't sort sometimes (resolves <a
href="https://redirect.github.com/vedantmgoyal2009/winget-releaser/issues/323">#323</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vedantmgoyal2009/winget-releaser/compare/4ffc7888bffd451b357355dc214d43bb9f23917e...b7370d4d152efdce803a26cc6ca9eee58cb2ad54">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 06:49:31 -05:00
dependabot[bot] fc518c96d5 build(deps): bump actions/upload-artifact from 7.0.1 to 7.0.2 (#19242)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 7.0.1 to 7.0.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Improves artifact download retries when the service returns HTTP 429
(rate limiting), including honoring valid Retry-After headers.</li>
<li>Updates <code>@​actions/artifact</code> to v6.3.1.</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tunc-d"><code>@​tunc-d</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/821">actions/upload-artifact#821</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v7.0.1...v7.0.2">https://github.com/actions/upload-artifact/compare/v7.0.1...v7.0.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/cf430e030ddbb5b0abf93d22962f4752f3646cd9"><code>cf430e0</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/822">#822</a>
from actions/tunc-d-prepare-upload-v7-0-2</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/c2acdedd35a8824a1552c7137f8c18288c3ea469"><code>c2acded</code></a>
chore: prepare v7.0.2 release</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/4687c1bbaa0a58abb517d90b4bbade6754c80c1a"><code>4687c1b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/821">#821</a>
from actions/tunc-d-upload-artifact-package-bump</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/8cbe1bebdb858105d8fdd88f81404d4de4595719"><code>8cbe1be</code></a>
Bump <code>@​actions/artifact</code> to 6.3.1</li>
<li>See full diff in <a
href="https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=7.0.1&new-version=7.0.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 06:33:51 -05:00
dependabot[bot] 46042eced5 build(deps): bump taiki-e/install-action from 2.87.24 to 2.87.27 (#19243)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.87.24 to 2.87.27.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.87.27</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.32.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.12.24.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.51.1.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.7.3.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.54.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.170.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.4.</p>
</li>
<li>
<p>Update <code>kingfisher@latest</code> to 2.11.1.</p>
</li>
<li>
<p>Update <code>hyperfine@latest</code> to 2.0.0.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.61.1.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.148.</p>
</li>
<li>
<p>Update <code>cargo-neat@latest</code> to 0.6.0.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.25.2.</p>
</li>
</ul>
<h2>2.87.26</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 1.7.2.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.5.5.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.3.</p>
</li>
<li>
<p>Update <code>kache@latest</code> to 1.0.0.</p>
</li>
<li>
<p>Update <code>hyperfine@latest</code> to 1.21.0.</p>
</li>
</ul>
<h2>2.87.25</h2>
<ul>
<li>
<p>Update <code>uv@latest</code> to 0.12.23.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.2.</p>
</li>
<li>
<p>Update <code>kingfisher@latest</code> to 2.10.0.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.60.1.</p>
</li>
<li>
<p>Update <code>cargo-semver-checks@latest</code> to 0.51.0.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.25.1.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.87.28] - 2026-10-12</h2>
<ul>
<li>
<p>Update <code>dprint@latest</code> to 0.62.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.33.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.13.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.8.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.171.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.75.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.7.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.25.3.</p>
</li>
</ul>
<h2>[2.87.27] - 2026-10-09</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.32.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.12.24.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.51.1.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.7.3.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.54.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.170.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.4.</p>
</li>
<li>
<p>Update <code>kingfisher@latest</code> to 2.11.1.</p>
</li>
<li>
<p>Update <code>hyperfine@latest</code> to 2.0.0.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/taiki-e/install-action/commit/ab6895351a88b908e96a4697860d4ffea5e57dbe"><code>ab68953</code></a>
Release 2.87.27</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/62530fde5eae2d21742c80f8d06d4ddc2e1fc849"><code>62530fd</code></a>
Update <code>vacuum@latest</code> to 0.32.0</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/f684ea4ef45b30adbd27018b3a8c8eff832d693e"><code>f684ea4</code></a>
Update <code>uv@latest</code> to 0.12.24</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/8aa87a079f6df0fefe32ea81cbf89957adfc4fb2"><code>8aa87a0</code></a>
Update <code>typos@latest</code> to 1.51.1</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/5ffcf4325f316f6461163dbceae21814184cc867"><code>5ffcf43</code></a>
Update <code>tombi@latest</code> to 1.7.3</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/99266369a536fa5485f3e5b59913a332a0af45ff"><code>9926636</code></a>
Update <code>syft@latest</code> to 1.54.1</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/4647f42698f08ac3c2a60181bceea72db3556908"><code>4647f42</code></a>
Update <code>release-plz@latest</code> to 0.3.170</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/df0256079f1b5aae055d9e9826e16e43e37734d1"><code>df02560</code></a>
Update rclone manifest</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/d7c82f4c669484f523dfcd90e184702c32babdb1"><code>d7c82f4</code></a>
Update <code>mise@latest</code> to 2026.10.4</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/a6142d0c42332af2f8b733abb6a554272b9f5880"><code>a6142d0</code></a>
Update <code>kingfisher@latest</code> to 2.11.1</li>
<li>Additional commits viewable in <a
href="https://github.com/taiki-e/install-action/compare/e407f7bafb71fd004bc5c2da3032e5470cbb6ef0...ab6895351a88b908e96a4697860d4ffea5e57dbe">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.87.24&new-version=2.87.27)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 06:33:31 -05:00
dependabot[bot] 462f3f1436 build(deps): bump crate-ci/typos from 1.50.3 to 1.51.1 (#19246)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.50.3 to
1.51.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.51.1</h2>
<h2>[1.51.1] - 2026-10-06</h2>
<h3>Features</h3>
<ul>
<li>Add ARM Windows builds</li>
</ul>
<h2>v1.51.0</h2>
<h2>[1.51.0] - 2026-10-06</h2>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>bimap</code></li>
</ul>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1610">September
2026</a> changes</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/main/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.51.1] - 2026-10-06</h2>
<h3>Features</h3>
<ul>
<li>Add ARM Windows builds</li>
</ul>
<h2>[1.51.0] - 2026-10-06</h2>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>bimap</code></li>
</ul>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1610">September
2026</a> changes</li>
</ul>
<h2>[1.50.3] - 2026-09-25</h2>
<h3>Fixes</h3>
<ul>
<li>Don'y panicwhen case-converting non-ASCII corrections</li>
</ul>
<h2>[1.50.2] - 2026-09-15</h2>
<h3>Fixes</h3>
<ul>
<li>Don't panic when files being examined are removed</li>
</ul>
<h2>[1.50.1] - 2026-09-01</h2>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>asend</code> in Python code</li>
</ul>
<h2>[1.50.0] - 2026-08-28</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1587">August
2026</a> changes</li>
</ul>
<h2>[1.49.1] - 2026-08-27</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/crate-ci/typos/commit/7f9d0819ca1c008ade73f4b41fa9d258d48f605b"><code>7f9d081</code></a>
chore: Release</li>
<li><a
href="https://github.com/crate-ci/typos/commit/4fc41d700195865b784ee2e1c7fc2edbf0af1620"><code>4fc41d7</code></a>
docs: Update changelog</li>
<li><a
href="https://github.com/crate-ci/typos/commit/eb4f2990517f8eaa0ed4c38c9d30287a52d9a8af"><code>eb4f299</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1602">#1602</a>
from meop/ci/platform-release-matrix</li>
<li><a
href="https://github.com/crate-ci/typos/commit/762326537dd08a8022c4491e5c21eccc582e74b9"><code>7623265</code></a>
ci: release a win-arm64-msvc artifact</li>
<li><a
href="https://github.com/crate-ci/typos/commit/cf01e3f0560d97f2bc216d8dc04781d9a2c9f655"><code>cf01e3f</code></a>
ci: match any windows runner when staging the release archive</li>
<li><a
href="https://github.com/crate-ci/typos/commit/dcea7116aaf94953292ab6ce0907fe483ef15406"><code>dcea711</code></a>
chore: Release</li>
<li><a
href="https://github.com/crate-ci/typos/commit/73ce3427c24c4aceeb6d79e912a5b75b08fd862d"><code>73ce342</code></a>
chore: Release</li>
<li><a
href="https://github.com/crate-ci/typos/commit/58d970f1aa80cfe709a3a3c33c3927ed433f8508"><code>58d970f</code></a>
docs: Update changelog</li>
<li><a
href="https://github.com/crate-ci/typos/commit/d59c567de648226a873e409ba64c7d0b98f254cc"><code>d59c567</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1634">#1634</a>
from epage/bimap</li>
<li><a
href="https://github.com/crate-ci/typos/commit/3689e3c1985b6911bd0748cd2c72648906b65a68"><code>3689e3c</code></a>
fix(dict): Remove bimap from being corrected</li>
<li>Additional commits viewable in <a
href="https://github.com/crate-ci/typos/compare/00f422f3b19c57bc6338715ebfe3316d38768461...7f9d0819ca1c008ade73f4b41fa9d258d48f605b">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.50.3&new-version=1.51.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-15 06:17:14 -05:00
Darren Schroeder 49ec1fbfc8 Bump rustls to 0.23.46 to clear the RustSec audit (#19249)
## Description

The `Security audit` job fails again. On 2026-10-14 RustSec filed four
advisories against `rustls 0.23.45`, and `rustls 0.23.46` fixes all of
them:

| Advisory | Issue |
| --- | --- |
| RUSTSEC-2026-0346 | `Debug` impls for client session values print TLS
secrets |
| RUSTSEC-2026-0347 | Buffered application data goes to the outer server
after an ECH rejection |
| RUSTSEC-2026-0348 | Brotli certificate decompression can allocate up
to 1 GiB before authentication |
| RUSTSEC-2026-0349 | An unauthenticated ServerHello can downgrade later
connections to classical key exchange |

This PR raises the workspace floor from `~0.23.45` to `~0.23.46`, the
same way #19026 did for the last rustls advisory, and runs `cargo update
-p rustls`. In `Cargo.lock` only the version and checksum of `rustls`
change. Its dependency list stays the same.

## User-facing changes (Release notes)

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-15 06:06:23 -05:00
bfren f5affecddc Optimize module reloading check (#19228)
Check each module once when deciding whether to reload a cached module

## Description

When a module that has already been parsed is imported again,
`parse_module_file` calls `module_needs_reloading` to check whether any
file in the module's tree has changed on disk. That walk recurses
through `submodules` and `imported_modules` without tracking which
modules it has visited, so a module reachable through several paths is
re-read once per *path*.

That's common in practice: a `mod.nu` that `export use`s its sibling
files, where most siblings also `use` a few shared helpers. In the repro
from the issue, every extra `use nested` of a 9-file module re-reads its
files ~133 times; with a real 22-file library it's ~412 reads per
import. Linux mostly hides this because file opens are cheap, but on
Windows it dominates parse time, and the LSP pays it on every keystroke.

This PR adds a `seen` set for the duration of the walk, so each
reachable module's file is read at most once per check. Skipping an
already-seen module is safe: `any()` short-circuits on the first change,
so a module seen again has already been found unchanged. I also
extracted the read-and-compare into a separate `module_file_changed`
function.

Measured on Windows with the repro script from the issue (`nu -n
repro.nu`):

| importers | before | after |
| --------: | -----: | ----: |
| 1 | 34.9 ms | 28.4 ms |
| 2 | 51.2 ms | 29.2 ms |
| 5 | 97.5 ms | 32.4 ms |
| 10 | 179.0 ms | 38.3 ms |

Per extra importer: **16.0 ms → 1.1 ms**. In my real-world case (a
13-file module importing a 22-file library from most of its files),
parsing on Windows went from ~3.1 s to the point where the LSP is
responsive again.

## User-facing changes (Release notes)

Improved performance when the same module is imported from many places.
Nushell no longer re-reads a module's files once for every import path
when checking whether a cached module has changed. This especially
speeds up parsing and the language server on Windows for libraries whose
files import each other.

## Additional notes

- fixes #19226
- `cargo test -p nu-parser` and `cargo test --test tests -- modules::`
pass; the second runs the module reload tests, including the new
`reload_module_reached_through_several_imports`.
- Behaviour is unchanged: a modified file anywhere in the tree still
triggers a reload. Only repeat visits of the same module within one
check are skipped.
2026-10-14 16:16:01 -05:00
Darren Schroeder d88d4fe0e1 Faster startup: chained fixups on Apple silicon, a cheaper banner, and async prompt pushes that survive (#19236)
## Description

Three independent changes make the REPL ready to type into sooner. With
the default config, launching `nu` until the first prompt is drawn drops
from 15.7 ms to 13.1 ms (−17%). `$nu.startup-time` is measured the same
way as before.

Measurements:
| default config, from `~` | main | this PR |
| --- | --- | --- |
| launch to first prompt | 15.70 ms | 13.10 ms |
| `$nu.startup-time` | 8.03 ms | 7.36 ms |
| instructions retired by the first prompt | 149.3M | 119.8M |


1. Change the linker on Apple silicon to
`"cargo:rustc-link-arg-bins=-Wl,-fixup_chains"`
2. Make `banner` cheaper (all architectures)
3. Keep prompt pushes that land before the prompt is rebuilt (all
architectures)

## User-facing changes (Release notes)

- Improved startup time. On Apple silicon Macs, `nu` is now linked with
chained fixups, so less work happens before Nushell's own code starts
and each `nu` process uses about 3 MiB less memory. The startup banner
no longer computes the welcome message when it only prints the startup
time.
- `date to-timezone` (all architectures) now accepts IANA time zone
names in any letter case, for example `date now | date to-timezone
america/new_york`. Before, some lowercase names were rejected as
invalid.
- Background jobs that update the prompt with `commandline set-prompt`
(all architectures), started from a `pre_prompt` or `env_change` hook or
from a prompt closure such as `$env.PROMPT_COMMAND`, no longer lose that
update when they finish before the prompt is drawn. A `commandline
set-prompt` called directly inside one of those hooks or prompt closures
now also shows on that prompt, in place of the value the prompt
variables give that segment. Before, the prompt evaluation that follows
the hooks always replaced it.


## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-14 16:15:25 -05:00
Darren Schroeder d211796628 fix: count closure calls toward recursion_limit so infinite closure recursion errors instead of crashing (#19229)
## Description

A closure that calls itself crashes Nushell:

```nushell
> let M = {|x| do $x $x}
> do $M $M
thread 'main' has overflowed its stack
fatal runtime error: stack overflow, aborting
```

`$env.config.recursion_limit` (default 50) exists for this, but only
custom command calls added to `Stack::recursion_count`. A closure call
copied the caller's count unchanged, so the check at the top of
`eval_ir_block` never fired for closures. The recursion ran until the
Rust stack overflowed and the process aborted.

## User-facing changes (Release notes)

Fixed a crash when a closure recursed without end, for example `let M =
{|x| do $x $x}; do $M $M`. Closure calls (`do`, `each`, `where`, hooks,
and so on) now count toward `$env.config.recursion_limit` the same way
custom command calls do. Deep recursion raises a
`nu::shell::recursion_limit_reached` error instead of overflowing the
stack.

A recursive custom command that calls itself from inside a closure now
uses two levels of the limit per recursion. With the default limit of
50, it stops at 25 levels instead of 50. Raise
`$env.config.recursion_limit` in your config file if you need deeper
recursion.

```nushell
Error: nu::shell::recursion_limit_reached

  × Recursion limit (50) reached
   ╭─[source:1:9]
 1 │ let M = {|x| do $x $x}
   ·         ───────┬──────
   ·                ╰── This called itself too many times
 2 │ do $M $M
   ╰────
```

## Additional notes
2026-10-14 08:51:33 -05:00
Darren Schroeder 4b60dee2f6 fix(gstat): stop wrapping counts and reporting unreadable status as clean, fill ignored and wt_renamed, link libgit2 statically (#19233)
## Description

`gstat` gave wrong answers in several situations, all from the plugin's
own code rather than from libgit2. I compared it with `git status` on
fixture repos (built with git 2.56) and confirmed each case on the 0.116
plugin.

## User-facing changes (Release notes)

- `gstat` no longer wraps its counts above 65,535. A repository with
70,000 untracked files used to report 4,464.
- When `gstat` can't read a repository's status (a split or sparse
index, a damaged index, or a bare repository), the status counts
(`idx_*`, `wt_*`, `ignored`, `conflicts`) are now -1 instead of 0, so
the repository no longer looks clean. The other fields are still filled.
- `gstat` now fills `ignored` (an ignored directory counts once) and
`wt_renamed`. A file renamed without `git mv` now counts as one
`wt_renamed` instead of one `wt_deleted` plus one `wt_untracked`, and
also as `wt_modified` if it was edited after the move.
- In a repository with no commits yet, `branch` shows the branch `HEAD`
points to instead of `master` or `HEAD`.
- `repo_name` is now the name of the working directory in linked
worktrees and submodules (it used to be `worktrees` or `modules`) and
the repository's own directory name for bare repositories.
- The gstat plugin starts faster on systems where it used to link a
system libgit2, such as a `cargo install` on macOS with Homebrew's
libgit2.


## Additional notes

Replacing git2 with gitoxide (`gix`) would make each call about 2x
faster, but it adds 60 crates. I measured it separately and left it out
of this PR.
2026-10-14 07:48:27 -05:00
Matt Van HornandMatt Van Horn 92165027ce fix: clarify empty-content access diagnostics (#19234)
## Description

AccessEmptyContent now reports "Cannot access empty content." under
nu::shell::access_empty_content, labels the span "content is empty", and
its resolution note asks the caller to confirm the content has items and
try again. Strict-mode tests for first and last assert that code,
message, and label for an empty list, an empty list stream, and empty
binary, and they reject wording that calls the row or index too large.

first and last on empty input report nu::shell::access_beyond_end with
the message "Row number too large (empty content)." and a span label
"index too large (empty content)." The failure is presented as an index
past the end of the input. ShellError::AccessEmptyContent was defined
with that beyond-end code, message, and span label. Its docs described
the case as an index access on an empty value and told the caller to
check lengths.

Closes #16034

## User-facing changes (Release notes)

Covered in the summary above.

## Additional notes

Nothing beyond what is described above.

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-10-14 07:02:20 -05:00
Darren Schroeder 3a4e666326 Bump locked dependencies to clear the RustSec audit (#19235)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description

The `Security audit` job fails on every PR that touches `Cargo.toml` or
`Cargo.lock`, because the advisory database now flags five
vulnerabilities in `quinn-proto 0.11.15`. It also raises warnings for
unsound and yanked crates. This PR only changes `Cargo.lock`. `cargo
update -p` moves each flagged crate to its latest release that is
compatible with Rust 1.97.1, and every one of those releases contains
the fix:

| Crate | Old | New | Advisory |
| --- | --- | --- | --- |
| `quinn-proto` | 0.11.15 | 0.11.19 | RUSTSEC-2026-0338, -0339, -0340,
-0341, -0342 (vulnerabilities) |
| `event-listener` | 5.4.1 | 5.4.2 | RUSTSEC-2026-0221 (unsound) |
| `memmap2` | 0.9.10 | 0.9.11 | RUSTSEC-2026-0186 (unsound) |
| `rand` | 0.8.5 | 0.8.8 | RUSTSEC-2026-0097 (unsound) |
| `rand` | 0.9.2 | 0.9.5 | RUSTSEC-2026-0097 (unsound) |
| `chacha20` | 0.10.0 | 0.10.2 | yanked |
| `der` | 0.8.0 | 0.8.2 | yanked |
<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->

## User-facing changes (Release notes)
<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-14 07:01:54 -05:00
Justin Ma 3752732c0e fix(ci): preserve warnings in nightly release builds (#19232)
fixes: https://github.com/nushell/nushell/issues/19168

Restore the warning policy used before setup-rust-toolchain v2.

- Set build-warnings to warn while retaining the pinned v2 action.
- Keep static glibc linker warnings visible without failing release
builds.

Upgrading setup-rust-toolchain to v2 introduced
CARGO_BUILD_WARNINGS=deny by default. The existing rustflags: '' no
longer disables this policy, causing LoongArch GNU builds to fail on
glibc static-linking warnings.

Explicitly setting build-warnings: warn restores the previous behavior:
warnings remain visible, while actual compilation and linking errors
still fail the build.
2026-10-14 06:04:13 -05:00
F4LCON b23af9f490 open/save: give a clear error suggesting def when the from/to converter is an alias (#19205)
## Description

`open` and `save` pick a converter by name at runtime: `open file.jsonc`
looks up `from jsonc`, and `save file.jsonc` looks up `to jsonc`. When
that name is an alias, for example `alias "from jsonc" = from json`,
both commands call the alias itself. Aliases only exist while parsing,
so this ends in an internal error that asks the user to file an issue:

```
Error: nu::shell::nushell_failed_spanned
  × Nushell failed: Can't run alias directly. Unwrap it first.
  help: This shouldn't happen. Please file an issue
```

As discussed in this PR, aliases aren't supported as converters. Both
commands now check whether the converter they found is an alias, and if
it is they return a normal error that suggests a `def` instead. The
suggestion reuses the text the alias wraps, so the alias's flags are
kept:

```
Error: nu::shell::error

  x Can't open file with alias `from jsonc`
   ,-[source:1:38]
 1 | alias "from jsonc" = from json; open deno.jsonc
   :                                      ^^^^^|^^^^
   :                                           `-- `from jsonc` is an alias, not a command
   `----
  help: `open` can only use a command as a converter. Define one with `def`
        instead: `def 'from jsonc' [] { from json }`
```

`save` gives the same error. It's raised before anything is written, so
no file is created.

Tests:
- `commands::open::open_with_a_from_alias_suggests_def`: a plain `from`
alias, and one with `--noheaders` to check that the suggested `def`
keeps the flag.
- `commands::save::save_with_a_to_alias_suggests_def`: `alias "to jsonc"
= to json --raw` suggests `def 'to jsonc' [] { to json --raw }` and
doesn't create the file.

`cargo fmt --all`, `cargo nuclippy` and `typos` are clean.

## User-facing changes (Release notes)

`open` and `save` no longer fail with an internal "Nushell failed: Can't
run alias directly" error when the converter for a file's extension is
an alias, such as `alias "from jsonc" = from json`. They now explain
that the converter must be a command and suggest the matching `def`, for
example `def 'from jsonc' [] { from json }`.

## Additional notes

Fixes #18725

---

Reply to fdncred (comment on the PR):

Done. Switched to option 2: `open`/`save` now give a normal error when
the converter is an alias and suggest the equivalent `def` (e.g. `def
'from jsonc' [] { from json }`). I updated the description and tests
too.
2026-10-13 12:46:40 -05:00
Darren Schroeder afc9a5d49f fix(tui): error when a closure has no table, tree, or select to follow (#19220)
## Description

A closure on `tui log`, `tui table`, `tui tree`, `tui progress`, or `tui
label` runs on the highlighted row of a table, tree, or select. `--from`
names which one. Without `--from`, the widget follows the focused one,
else the nearest. When there was none, the widget drew empty and the
piped data disappeared.

The closure wasn't ignored. With no row to run on,
`Session::refresh_one` stored `nothing` as the widget's derived value,
and `data_for` returns that before it falls back to the piped data. So
the closure hid the stream.

## User-facing changes (Release notes)

A `tui` widget with a closure and nothing to follow used to draw empty
and hide the piped data. `tui run` and `tui debug` now report an error
that points at that widget's builder: for example when `tui log {|row|
...}` has no `tui table`, `tui tree`, or `tui select` to follow, when
`--from` names a widget that has no rows or names the widget itself, or
when followers could only follow each other. `--data`, and `--value` on
`tui progress`, can no longer be combined with `--from` or a closure,
because the closure's output never showed. A closure now follows a
table, tree, or select on another `tui tab` page when the shown page has
none. Inside a child list such as `tui split [([a b] | tui table | tui
log {|row| ...})]`, the log now shows the closure's output instead of
the piped data.

```nushell
Error: nu::shell::error

  × nothing for the closure to follow
   ╭─[source:1:65]
 1 │ 1..5 | each {|n| $"tick ($n)"} | tui label --titlebar "ticks" | tui log { $in } | tui run
   ·                                                                 ───┬───
   ·                                                                    ╰── `log-0` runs its closure on the highlighted row of a table, tree, or select, but none can be followed: a widget never follows its own row, or one that follows it. Add one, or drop the closure
   ╰────
```

```nushell
Error: nu::shell::incompatible_parameters

  × Incompatible parameters.
   ╭─[source:1:9]
 1 │ tui log --data [a b] {|x| $x }
   ·         ──────┬─────
   ·               ╰── use either --data or --from/a closure, not both
   ╰────
```

## Additional notes

closes https://github.com/nushell/nushell/issues/19217
2026-10-13 08:44:19 -05:00
Tino 60c9ed7471 Don't let lifted columns overwrite normal columns while flattening (#19201)
During flattening we check if the nested records can be lifted straight
to the root level. If that's not possible due to a colliding column
name, we rename the lifted column with a name containing the nested
record's name. After this rename, the column is added to the table
without checking if the new name collides with any of its elements. This
allows silently overwriting existing elements, which is not ideal.

I fixed the issue by checking if the entry added to "out" overwrote an
entry or not. Since "out" is an IndexMap, we can easily obtain this
information by checking if the return value is Some. This check is done
after each insert unless we've explicitly verified that the column name
we're adding doesn't exist in the table. If an entry would be
overwritten, an error is thrown.

Before merging, could someone verify whether the error type, the tag and
the span are correct?

## User-facing changes (Release notes)

Fixed an issue where lifting a column from a nested record collided with
the existing columns, but was nevertheless added to the table by
overwriting the existing column.

## Additional notes

Closes https://github.com/nushell/nushell/issues/19200
2026-10-13 07:56:39 -05:00
skyfireandJarvis-AI-42 687d7bcac5 fix: support IPv6 zone IDs in http commands (#19213)
Fixes #9065

## Description

`http get 'http://[fe80::13%eth0]'` (and the other `http *` commands)
fail because `url::Url::parse` does not support IPv6 zone IDs (e.g.
`%eth0`), per the WHATWG URL standard. `curl` handles these URLs fine.

The fix now validates and drives requests with `http::Uri`, the same
parser ureq uses, so nushell and ureq agree on which URLs are valid.

1. **`crates/nu-command/src/network/http/client.rs`**
- `http_parse_url` validates with `http::Uri` instead of `url::Url`
(which rejects zone IDs). It returns the raw URL string; the
`strip_ipv6_zone_id` helper and the returned `Url` are gone.
- A new `authority_is_well_formed` check rejects URLs that `http::Uri`
would otherwise accept leniently, e.g. trailing garbage after an IPv6
literal (`[fe80::13%eth0]foo`) or non-numeric/out-of-range ports
(`host:abc`, `host:99999`). These would silently send the request to a
different host or port.
- `request_set_host_header` sets the `Host` header without the zone ID
(matching curl) when the authority contains one, so strict servers don't
reject the request. A user-provided `Host` header is left untouched.
- `transform_response_using_content_type` derives the `text/plain` file
extension from `http::Uri::path()` so zone-ID URLs no longer fail after
the request has been sent.
2. **`crates/nu-command/src/network/http/resolver.rs`**
- `uri.host()` returns IPv6 addresses wrapped in square brackets (e.g.
`[fe80::13%eth0]`), which `dns_lookup::getaddrinfo` cannot resolve. The
brackets are stripped before resolution, so `getaddrinfo` handles the
zone ID natively (converting the interface name to a scope ID).
- The RFC 6874 `%25` form (e.g. `[fe80::1%25lo0]`) is decoded to a
literal `%` before `getaddrinfo`.
   - `host` stays an `Option` and is passed to `getaddrinfo` as-is.

## User-facing changes (Release notes)

`http get`, `http post`, and the other `http *` commands now accept
**`http://`** URLs with IPv6 literals and link-local zone IDs, e.g.
`http get 'http://[fe80::13%eth0]'`. Plain IPv6 literals (e.g. `http get
'http://[::1]:8080/a.txt'`) work as well. Previously these URLs failed
to parse or resolve.

Note: `https://` URLs with a zone ID are **not** supported. ureq builds
the rustls `ServerName` from the bracket-stripped host, and
`fe80::13%eth0` is neither a valid IP nor a valid DNS name, so TLS
handshakes fail. This is a ureq/rustls limitation and cannot be fixed
from nushell.

## Tests

- `cargo check -p nu-command` passes
- `cargo test -p nu-command --lib network::http` — 20 tests pass,
including:
  - `test_http_parse_url_with_ipv6_zone_id`
  - `test_http_parse_url_rejects_invalid_ipv6_with_zone_id`
  - `test_authority_is_well_formed`
  - `test_request_set_host_header_strips_zone_id`
  - `test_request_set_host_header_leaves_other_urls_alone`
- `cargo test -p nu-command --test tests -- commands::network::http` —
87 tests pass, including the new `http_get_ipv6_literal`, which binds
`[::1]` and makes a real `text/plain` request through
`DnsLookupResolver`.
- `cargo fmt --all -- --check`, `cargo clippy -p nu-command
--all-targets -D warnings` and `typos` are clean.

## Review feedback

All findings from the review have been addressed:

1. **Text/plain responses fail after the request is sent** —
`transform_response_using_content_type` now uses `http::Uri::path()`
instead of `url::Url::parse`.
2. **Zone ID ends up in the `Host` header** — `request_set_host_header`
strips it (like curl); a user-set `Host` header is respected.
3. **Validate with `http::Uri` instead of strip-and-reparse** — done;
`strip_ipv6_zone_id` and the returned `Url` are removed. URLs that ureq
rejects (e.g. `http://[fe80::1%lo 0]:18913/`) are now rejected up front
by `http_parse_url`.
4. **RFC 6874 `%25` form can't resolve** — the resolver decodes `%25` to
`%` before `getaddrinfo`.
5. **No test makes a real request to an IPv6 literal** — added
`http_get_ipv6_literal`.
6. **Keep `host` as an `Option`** — done.
7. **HTTPS zone-ID URLs still fail** — a ureq/rustls limitation; the
release notes above are now scoped to `http://`.

---------

Co-authored-by: Jarvis-AI-42 <skyfireitdiy@gmail.com>
2026-10-13 07:54:55 -05:00
Darren Schroeder af58d1426b fix(join): error when a table has no rows with the join column (#19219)
## Description

`join` accepted a join column that its tables don't have. Depending on
the join type, it returned an empty list or rows padded with `null`:

```nushell
> [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d | to nuon
[]
> [[a b]; [1 2] [3 4]] | join --left [[a c]; [1 3] [4 5]] a z | to nuon
[[a, b, a_, c]; [1, 2, null, null], [3, 4, null, null]]
```

`join_rows` returned early when the table it was iterating had no row
with the key, and the lookup table built from the other side came out
empty when that side lacked the key. Neither path reported anything.

## User-facing changes (Release notes)

`join` now raises a `column_not_found` error when the input table or the
right table has rows but none of them contain the join column. Before, a
misspelled column name silently produced an empty result or rows full of
`null`. Empty tables and tables where only some rows lack the column
behave as before.

```nushell
Error: nu::shell::column_not_found

  × Cannot find column 'd'
   ╭─[source:1:1]
 1 │ [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d
   · ──────────┬─────────                             ┬
   ·           │                                      ╰── column 'd' is missing in one or more values
   ·           ╰── value originates here
   ╰────
  help: If some rows have this column, try using 'd?' for optional access, or
        pre-fill using the `default` command
```

## Additional notes

closes https://github.com/nushell/nushell/issues/19215
2026-10-13 07:51:30 -05:00
Evgeny fab6af9c2b Use builtin command sigil to avoid bugs when user aliases shadow builtin (#19224)
## Description

User aliases should have no effect on nu's STD, but if you alias `alias
metadata = /non/exist/bin` you'll get a load error `Command
`/non/exist/bin` not found

This PR fixes that smaller issue by adding `%`, but doesn't resolve the
more general issue of other commands potentially having the same
conflict

## User-facing changes (Release notes)

- Fixed an issue where aliasing `metadata` would break its use in `std`

## Additional notes


Ideally there should be some linter that forces `%` to all .nu scripts
used in nushell
2026-10-13 06:33:12 -05:00
Sidney 4faa823718 anti join (#19208)
## Description

Add a new `Join` kind with the following semantics: in `Inner` mode,
append no rows. In non-inner mode, append all rows and include no new
columns from `rhs` table.

## User-facing changes (Release notes)

Add `join --anti`, which selects rows not present in the right table by
the join column. `$lhs | join --anti $rhs ref` is equivalent in behavior
to `$lhs | where ref not-in $rhs`.

## Additional notes

Closes #19207
2026-10-12 09:05:30 -05:00
Sidney 09eae32199 strict clocktime regex (#19210)
## Description

Instead of binding the clock time parsing to `str.contains(":")`, add a
dedicated regex. Note: the regex does not _validate_ clock strings. It
just defines the pattern for strings that we want to parse.

## User-facing changes (Release notes)

`into duration` rejects odd-length composite fields in the clock format,
such as `11:0:22` or `11:000:2`

This PR depends on #19209
2026-10-11 14:29:37 -05:00