nushell-plugins/updates/108/nushell_0.108.0_changes.nu

730 lines
33 KiB
Plaintext
Raw Permalink Normal View History

# Nushell 0.108.0 Complete Changes Data Structure
# This file contains all breaking changes, new features, and important changes
# in a structured Nushell record format for programmatic access
export def get-changes [] {
{
version: "0.108.0"
release_date: "2025-10-15"
previous_version: "0.107.x"
breaking_changes: [
{
id: 1
category: "command_rename"
name: "into value renamed to detect type"
old: "into value"
new: "detect type (for type detection) | into value (for custom value conversion)"
description: "Until version 0.107, 'into value' tried to detect the types of table cells. This command is now called 'detect type', but it doesn't operate on cells anymore. The 'into value' name is now used for converting custom values from plugins into native Nushell values."
impact: "high"
platform: "all"
migration_guide: "Replace '$data | into value' with '$data | update cells {detect type}' for table cell type detection, or '$value | detect type' for non-table type detection. The new 'into value' command is used for converting custom plugin values."
example_old: "$data | into value"
example_new: "$data | update cells {detect type} # For cells\n$value | detect type # For non-tables\n$custom_value | into value # For plugin values"
}
{
id: 2
category: "behavior_change"
name: "Stream error collection behavior"
old: "Collecting streams with errors would silently include or hide errors"
new: "Collecting a stream that contains errors now raises an error itself"
description: "Implemented by @Bahex to fix an issue where some errors hiding inside other commands weren't showing up. This makes error handling more explicit and prevents silent failures."
impact: "high"
platform: "all"
migration_guide: "Wrap stream collection in try-catch blocks to handle errors explicitly, or filter out errors before collection if appropriate."
example_old: "let results = $stream | collect # Might silently fail"
example_new: "let results = try { $stream | collect } catch { [] } # Explicit error handling"
}
{
id: 3
category: "behavior_change"
name: "format bits endian behavior"
old: "Used native endian (pre-0.107), then big endian in 0.107"
new: "Explicit --endian flag to choose behavior"
description: "format bits used to output in native endian until Nu 0.107.0 changed it to big endian. Now you can choose the behavior with --endian flag."
impact: "medium"
platform: "all"
migration_guide: "Use 'format bits --endian native' for original behavior, 'format bits --endian big' for 0.107 default, or 'format bits --endian little' for little endian."
example_old: "$value | format bits"
example_new: "$value | format bits --endian native # Original behavior\n$value | format bits --endian big # 0.107 default\n$value | format bits --endian little # Little endian"
}
{
id: 4
category: "api_change"
name: "Polars fetch removed and pivot changes"
old: "polars fetch available, polars pivot stable by default"
new: "polars fetch removed, polars pivot requires --stable flag"
description: "polars fetch has been removed due to no longer being supported on LazyFrame. polars pivot will no longer perform a stable pivot by default and requires --stable flag."
impact: "medium"
platform: "all"
migration_guide: "Remove all uses of 'polars fetch' (no direct replacement). Add --stable flag to 'polars pivot' if stable pivot is needed."
example_old: "$data | polars fetch\n$data | polars pivot"
example_new: "# polars fetch has no replacement\n$data | polars pivot --stable # Must be explicit"
plugin_affected: "nu_plugin_polars"
}
{
id: 5
category: "behavior_change"
name: "Windows UNC and device path handling"
old: "UNC paths got trailing backslash, device paths didn't work with open/save/source"
new: "No trailing backslashes, full device path support"
description: "On Windows, UNC and device paths no longer get a trailing \\ appended when being cast to path. open, save, and source now work with device paths like \\\\.\\NUL or \\\\.\\CON, as well as reserved device names."
impact: "low"
platform: "windows"
migration_guide: "Update code to not expect trailing backslashes on UNC paths. Device paths now work correctly with open/save/source commands."
example_old: "# open \\\\.\\NUL would fail\n# UNC paths: \\\\server\\share\\"
example_new: "open \\\\.\\NUL # Now works\nopen NUL # Also works\n# UNC paths: \\\\server\\share # No trailing backslash"
}
{
id: 6
category: "build_change"
name: "Network commands feature flag"
old: "Network commands included by default"
new: "Must explicitly enable with --features network when building without defaults"
description: "Nushell can now be compiled without network-related commands. When building manually without default features, must pass --features network to get network commands."
impact: "low"
platform: "all"
migration_guide: "Add '--features network' to custom builds that use cargo build --no-default-features"
example_old: "cargo build --no-default-features"
example_new: "cargo build --no-default-features --features network"
affects_default_build: false
}
{
id: 7
category: "behavior_change"
name: "Power operator associativity fix"
old: "** operator parsed left-to-right (incorrect)"
new: "** operator parses right-to-left (mathematically correct)"
description: "The ** (power) operator now parses as right-associative instead of left-associative, matching standard mathematical behavior."
impact: "low"
platform: "all"
migration_guide: "Review chained power operations. If you need left-to-right evaluation, use explicit parentheses: (2 ** 3) ** 4"
example_old: "2.0 ** 3.0 ** 4.0 # Evaluated as (2^3)^4 = 4096"
example_new: "2.0 ** 3.0 ** 4.0 # Evaluated as 2^(3^4) = 2.4178516392292583e+24\n(2.0 ** 3.0) ** 4.0 # Explicit left-to-right if needed"
}
]
new_features: [
{
id: 1
name: "MCP Server for AI Agents"
description: "Adds an MCP (Model Context Protocol) server for Nushell, allowing AI agents to run Nushell commands. When compiled with the 'mcp' feature, the nushell binary can be used as a local (stdio) MCP server."
category: "optional_feature"
added_by: "@ayax79"
status: "experimental"
how_to_enable: "Compile with: cargo build --features mcp"
compilation_flag: "mcp"
default_enabled: false
capabilities: [
"Execute native Nushell commands via MCP"
"Execute external commands via MCP"
"Secure command execution for AI agents"
]
community_channel: "#ai-with-nu on Discord"
}
{
id: 2
name: "Smarter Completions with Per-Command Completers"
description: "New, simpler way to define completions for command parameters with inline completion lists. Built-in commands that expect specific values now suggest these values automatically."
category: "enhancement"
added_by: "multiple contributors"
status: "stable"
how_to_enable: "Available by default"
features: [
{
name: "Inline completion lists"
example: "def go [direction: string@[left up right down]] { $direction }"
}
{
name: "Const variable completions"
example: "const directions = [left up right down]; def go [direction: string@$directions] { $direction }"
}
{
name: "Built-in command suggestions"
description: "Commands expecting specific values now suggest them"
}
{
name: "File completions for redirections"
description: "Added for command redirections (o>>, e>, ...)"
}
{
name: "Directory-only completions"
description: "Regular files no longer suggested for directory arguments"
}
]
}
{
id: 3
name: "Enhanced CustomValue Support"
description: "CustomValues let plugin authors introduce their own data types. They now behave much closer to regular Values with support for error propagation syntax, save command integration, and into value conversion."
category: "plugin_api"
added_by: "@cptpiepmatz"
status: "stable"
how_to_enable: "Available for plugin developers"
target_audience: "plugin_developers"
capabilities: [
{
name: "Error propagation syntax support"
description: "Supports both $value? (try) and $value! (unwrap) operators"
}
{
name: "Save command integration"
description: "CustomValues now work with the save command"
}
{
name: "Into value conversion"
description: "Convert custom plugin values to native Nushell values"
}
]
}
{
id: 4
name: "which command enhancement"
description: "The which command now lists all commands (internal and external) when no argument is passed to it."
category: "command_enhancement"
command: "which"
example: "which # Lists all available commands"
}
{
id: 5
name: "Enhanced HTTP commands metadata"
description: "All http commands now attach response data (previously only accessible with http * --full) as metadata to their output streams."
category: "command_enhancement"
commands: ["http get", "http post", "http delete", "http put", "http patch", "http head"]
example: "let response = http get $url; $response | metadata # Now includes headers"
}
{
id: 6
name: "New date/time format specifiers"
description: "The format date and into datetime commands now support two new format specifiers for creating compact, sortable date and time components."
category: "command_enhancement"
commands: ["format date", "into datetime"]
specifiers: [
{
specifier: "%J"
format: "YYYYMMDD"
description: "Compact dates"
example: "20250918"
}
{
specifier: "%Q"
format: "HHMMSS"
description: "Compact times"
example: "131144"
}
]
example: "date now | format date '%J' # 20251015\ndate now | format date '%Q' # 143022\ndate now | format date '%J%Q' # 20251015143022"
}
{
id: 7
name: "metadata set --merge"
description: "New --merge flag for metadata set command to attach arbitrary metadata fields."
category: "command_enhancement"
command: "metadata set"
example: "$value | metadata set --merge { custom_field: 'value', priority: 1 }"
}
{
id: 8
name: "each --flatten"
description: "New --flatten flag for each command for better streaming behavior with nested data."
category: "command_enhancement"
command: "each"
example: "$data | each --flatten { |item| process $item }"
}
]
experimental_features: [
{
id: 1
name: "pipefail"
status: "opt-in"
added_by: "@WindSoilder"
tracking_issue: "16760"
description: "When enabled, $env.LAST_EXIT_CODE will be set to the exit code of the rightmost command in a pipeline that exited with a non-zero status, or zero if all commands succeeded."
how_to_enable: "nu --experimental-options='pipefail'"
config_enable: "$env.config.experimental = { pipefail: true }"
behavior_change: {
before: "^false | echo ''; $env.LAST_EXIT_CODE # Returns 0 (incorrect)"
after: "^false | echo ''; $env.LAST_EXIT_CODE # Returns 1 (correct)"
}
enhanced_with: "$env.config.display_errors.exit_code = true"
use_cases: [
"Shell scripting requiring strict error checking"
"CI/CD pipelines where any failure should be caught"
"Bash-like pipeline error handling"
]
}
{
id: 2
name: "enforce-runtime-annotations"
status: "opt-in"
added_by: "@mkatychev"
description: "When enabled, Nushell catches errors at runtime when assigning values to type-annotated variables, providing stronger runtime type safety."
how_to_enable: "nu --experimental-options='enforce-runtime-annotations'"
config_enable: "$env.config.experimental = { enforce-runtime-annotations: true }"
behavior_change: {
without: "let x: int = 'not a number' # May pass parse time, fail silently"
with: "let x: int = 'not a number' # Throws cant_convert error at runtime"
}
breaking_reason: "Would break scripts where coercion/conversions previously ignored field constraints for records and tables"
use_cases: [
"Stricter type safety in production scripts"
"Catching type conversion errors early"
"More predictable behavior for typed variables"
]
}
{
id: 3
name: "reorder-cell-paths"
status: "opt-out"
previous_status: "opt-in"
tracking_issue: "16766"
promoted_in_version: "0.108.0"
description: "Improves cell-path accesses by reordering how the cell-path should be evaluated without modifying the output. Now enabled by default."
performance_impact: "positive"
how_to_disable: "nu --experimental-options='reorder-cell-paths=false'"
config_disable: "$env.config.experimental = { reorder-cell-paths: false }"
introduced_in: "0.106.0"
}
]
plugin_api_changes: [
{
id: 1
category: "CustomValue enhancements"
added_by: "@cptpiepmatz"
target: "plugin_developers"
changes: [
{
feature: "Error propagation support"
description: "Plugin authors can now implement both try (?) and unwrap (!) operators"
methods: ["follow_path_int", "follow_path_string"]
}
{
feature: "Save command integration"
description: "Define how custom value should be saved"
methods: ["to_base_value"]
}
{
feature: "Into value support"
description: "Custom values can be converted to native values via 'into value' command"
methods: ["to_base_value"]
}
]
compatibility: {
protocol_version: "0.108.0"
breaking: false
backward_compatible: true
recommendation: "Rebuild plugins against 0.108.0 to use new features"
}
}
]
command_changes: {
renamed: [
{
old_name: "into value"
new_name: "detect type"
purpose: "Type detection from strings"
note: "No longer operates on cells directly - use 'update cells {detect type}'"
}
]
removed: [
{
command: "polars fetch"
reason: "No longer supported on LazyFrame"
alternative: "Depends on use case - functionality removed upstream"
plugin: "nu_plugin_polars"
}
]
added: [
{
command: "detect type"
description: "Detect and convert string types to typed values"
category: "type_conversion"
replaces: "into value (old functionality)"
}
{
command: "into value"
description: "Convert custom plugin values to native Nushell values"
category: "plugin_integration"
new_purpose: true
}
]
modified: [
{
command: "format bits"
change: "Added --endian flag"
description: "Choose endian behavior (native, big, little)"
flags: ["--endian native", "--endian big", "--endian little"]
}
{
command: "polars pivot"
change: "Added --stable flag"
description: "Must explicitly request stable pivot"
breaking: true
}
{
command: "which"
change: "No args lists all commands"
description: "Lists all commands when called without arguments"
}
{
command: "http *"
change: "Metadata attachment"
description: "Response data attached as metadata without --full"
affected_commands: ["http get", "http post", "http delete", "http put", "http patch"]
}
{
command: "format date"
change: "New format specifiers"
description: "Added %J (compact date) and %Q (compact time)"
specifiers: ["%J", "%Q"]
}
{
command: "into datetime"
change: "New format specifiers"
description: "Added %J (compact date) and %Q (compact time)"
specifiers: ["%J", "%Q"]
}
{
command: "metadata set"
change: "Added --merge flag"
description: "Merge arbitrary metadata fields"
}
{
command: "each"
change: "Added --flatten flag"
description: "Better streaming behavior for nested data"
}
{
command: "compact"
change: "Improved --empty"
description: "Now recognizes 0 byte binary values as empty"
}
{
command: "open"
change: "Windows improvement"
description: "Now works with device paths"
platform: "windows"
}
{
command: "save"
change: "Windows improvement + CustomValue support"
description: "Works with device paths on Windows and custom plugin values"
platform: "all"
}
{
command: "source"
change: "Windows improvement"
description: "Now works with device paths"
platform: "windows"
}
]
}
behavior_changes: [
{
id: 1
name: "Error handling in try blocks"
description: "Clean up error handlers when jumping outside of try blocks with break/continue"
impact: "More predictable error handling behavior"
fixes: "Error handlers now properly clean up when using break/continue to exit try blocks"
}
{
id: 2
name: "Break/continue outside loops"
description: "Using break/continue outside loops now raises a compile error"
impact: "Catches logical errors at compile time"
detection: "compile_time"
}
{
id: 3
name: "Error context preservation"
description: "Errors inside each calls now keep their full context"
impact: "Better error messages and easier debugging"
}
{
id: 4
name: "Improved error messages"
description: "Better error messages for invalid binary, hexadecimal, and octal strings"
impact: "Clearer error messages when parsing number literals fails"
}
]
build_system_changes: [
{
id: 1
name: "Optional network commands"
feature_flag: "network"
default: true
description: "Network commands now optional via feature flag. Custom builds can exclude network functionality."
usage: "cargo build --no-default-features --features network"
}
{
id: 2
name: "Optional MCP server"
feature_flag: "mcp"
default: false
description: "MCP server support via feature flag for AI integration"
usage: "cargo build --features mcp"
}
]
bug_fixes: {
critical: [
{
id: 1
name: "Try block error handler cleanup"
description: "Fixed error handlers not cleaning up when jumping out of try blocks with break/continue"
impact: "More predictable error handling behavior"
}
{
id: 2
name: "Power operator associativity"
description: "Fixed ** operator being left-associative (incorrect)"
impact: "Mathematical expressions now compute correctly"
}
{
id: 3
name: "Stream error collection"
description: "Fixed errors in streams not being properly reported"
impact: "Errors now explicitly raised when collecting streams with errors"
}
]
platform_specific: [
{
id: 1
platform: "windows"
name: "Windows UNC and device paths"
fixes: [
"Trailing backslash on UNC paths removed"
"Device paths (\\\\.\\NUL, \\\\.\\CON) now work with open, save, source"
]
impact: "Better Windows compatibility"
}
]
command_specific: [
{
id: 1
command: "compact"
fix: "Now recognizes 0 byte binary values as empty"
impact: "More consistent empty value handling"
}
{
id: 2
command: "each"
fix: "Errors inside each calls now preserve full context"
impact: "Easier debugging of pipeline errors"
}
{
id: 3
description: "Break/continue compile-time checks"
fix: "Using break/continue outside loops now caught at compile time"
impact: "Better error detection during parsing"
}
]
}
impact_summary: {
high_impact: [
"into value → detect type rename"
"Stream error collection behavior"
"Polars fetch removal (if using polars)"
]
medium_impact: [
"format bits endian behavior"
"Network feature flag (custom builds only)"
"Power operator associativity (if using chained powers)"
"Polars pivot --stable flag (if using polars)"
]
low_impact: [
"Windows UNC/device path improvements (Windows users)"
"Inline completion syntax adoption"
"HTTP metadata access simplification"
"New date/time format specifiers"
"Enhanced CustomValue support (plugin developers)"
]
}
recommendations_for_best_practices: [
{
category: "Error Handling"
recommendation: "Always handle stream errors explicitly with try-catch blocks"
example: "try { $stream | collect } catch { |err| log error $err.msg; [] }"
}
{
category: "Type Safety"
recommendation: "Use explicit type annotations with runtime checks in production"
example: "$env.config.experimental = { enforce-runtime-annotations: true }"
}
{
category: "Completions"
recommendation: "Prefer inline completions for simple static cases, custom completers for dynamic values"
example: "def deploy [env: string@[dev staging prod]] { ... }"
}
{
category: "Platform Compatibility"
recommendation: "Use full device paths on Windows, don't assume trailing backslashes on UNC paths"
example: "if $nu.os-info.name == 'windows' { open \\\\.\\NUL }"
}
{
category: "Custom Values in Plugins"
recommendation: "Implement full CustomValue support for error propagation and save integration"
example: "Implement follow_path_int, to_base_value methods"
}
{
category: "Endian Handling"
recommendation: "Be explicit about endian when working with binary data interchange"
example: "$data | format bits --endian big # Network byte order"
}
{
category: "Pipeline Error Handling"
recommendation: "Use pipefail experimental feature for critical scripts"
example: "$env.config.experimental = { pipefail: true }"
}
{
category: "Migration Testing"
recommendation: "Test incrementally: update syntax, test with old flags, enable features one at a time"
steps: [
"Update syntax without logic changes"
"Test with old behavior flags"
"Enable new features one at a time"
"Run comprehensive test suite"
"Deploy to staging first"
]
}
{
category: "Documentation"
recommendation: "Document required Nushell version and experimental features in code"
example: "# @requires nushell >= 0.108.0\n# @experimental pipefail"
}
{
category: "Future-Proofing"
recommendation: "Write code that works with experimental features enabled to prepare for when they become default"
considerations: [
"Explicit error handling (pipefail-ready)"
"Type annotations (runtime-check-ready)"
"Explicit endian specifications"
"No reliance on removed commands"
]
}
]
contributors: [
"@132ikl", "@andoalon", "@app/dependabot", "@ayax79", "@Bahex",
"@blindFS", "@cablehead", "@cptpiepmatz", "@fdncred", "@fixerer",
"@Jan9103", "@maxim-uvarov", "@mkatychev", "@nome", "@sgvictorino",
"@Sheape", "@sholderbach", "@simonborje", "@Tyarel8", "@weirdan",
"@WindSoilder", "@xolra0d", "@Xylobyte", "@ysthakur"
]
resources: {
official_release_notes: "https://www.nushell.sh/blog/2025-10-15-nushell_v0_108_0.html"
github_release: "https://github.com/nushell/nushell/releases/tag/0.108.0"
discord_community: "#ai-with-nu (for MCP server discussions)"
experimental_tracking: {
pipefail: "Issue #16760"
reorder_cell_paths: "Issue #16766"
}
}
}
}
# Helper functions for accessing specific data
export def get-breaking-changes [] {
(get-changes).breaking_changes
}
export def get-high-impact-changes [] {
(get-changes).breaking_changes | where impact == "high"
}
export def get-new-features [] {
(get-changes).new_features
}
export def get-experimental-features [] {
(get-changes).experimental_features
}
export def get-plugin-api-changes [] {
(get-changes).plugin_api_changes
}
export def get-command-changes [] {
(get-changes).command_changes
}
export def get-recommendations [] {
(get-changes).recommendations_for_best_practices
}
export def get-impact-summary [] {
(get-changes).impact_summary
}
# Search for specific changes by keyword
export def search-changes [keyword: string] {
let changes = get-changes
{
breaking_changes: ($changes.breaking_changes | where { |c|
(($c.name | str contains -i $keyword) or
($c.description | str contains -i $keyword) or
($c.old | str contains -i $keyword) or
($c.new | str contains -i $keyword))
})
new_features: ($changes.new_features | where { |f|
(($f.name | str contains -i $keyword) or
($f.description | str contains -i $keyword))
})
experimental_features: ($changes.experimental_features | where { |e|
(($e.name | str contains -i $keyword) or
($e.description | str contains -i $keyword))
})
}
}
# Generate migration report
export def generate-migration-report [] {
let changes = get-changes
print $"# Nushell ($changes.version) Migration Report"
print $"Release Date: ($changes.release_date)\n"
print "## High Priority Changes (Must Address)"
for change in (get-high-impact-changes) {
print $"- ($change.name)"
print $" Old: ($change.old)"
print $" New: ($change.new)"
print $" Migration: ($change.migration_guide)\n"
}
print "\n## Experimental Features to Consider"
for feature in ($changes.experimental_features) {
print $"- ($feature.name): ($feature.description)"
if ($feature.how_to_enable? != null) {
print $" Enable: ($feature.how_to_enable)"
} else if ($feature.how_to_disable? != null) {
print $" Disable: ($feature.how_to_disable)"
}
print ""
}
print "\n## Recommendations"
for rec in ($changes.recommendations_for_best_practices | first 5) {
print $"- ($rec.category): ($rec.recommendation)"
}
}