chore: update all plugins to Nushell 0.111.0
Some checks failed
Build and Test / Validate Setup (push) Has been cancelled
Build and Test / Build (darwin-amd64) (push) Has been cancelled
Build and Test / Build (darwin-arm64) (push) Has been cancelled
Build and Test / Build (linux-amd64) (push) Has been cancelled
Build and Test / Build (windows-amd64) (push) Has been cancelled
Build and Test / Build (linux-arm64) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Package Results (push) Has been cancelled
Build and Test / Quality Gate (push) Has been cancelled
Nightly Build / Check for Changes (push) Has been cancelled
Nightly Build / Validate Setup (push) Has been cancelled
Nightly Build / Nightly Build (darwin-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (darwin-arm64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (windows-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-arm64) (push) Has been cancelled
Nightly Build / Create Nightly Pre-release (push) Has been cancelled
Nightly Build / Notify Build Status (push) Has been cancelled
Nightly Build / Nightly Maintenance (push) Has been cancelled
Some checks failed
Build and Test / Validate Setup (push) Has been cancelled
Build and Test / Build (darwin-amd64) (push) Has been cancelled
Build and Test / Build (darwin-arm64) (push) Has been cancelled
Build and Test / Build (linux-amd64) (push) Has been cancelled
Build and Test / Build (windows-amd64) (push) Has been cancelled
Build and Test / Build (linux-arm64) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Package Results (push) Has been cancelled
Build and Test / Quality Gate (push) Has been cancelled
Nightly Build / Check for Changes (push) Has been cancelled
Nightly Build / Validate Setup (push) Has been cancelled
Nightly Build / Nightly Build (darwin-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (darwin-arm64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (windows-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-arm64) (push) Has been cancelled
Nightly Build / Create Nightly Pre-release (push) Has been cancelled
Nightly Build / Notify Build Status (push) Has been cancelled
Nightly Build / Nightly Maintenance (push) Has been cancelled
- Bump all 18 plugins from 0.110.0 to 0.111.0
- Update rust-toolchain.toml channel to 1.93.1 (nu 0.111.0 requires ≥1.91.1)
Fixes:
- interprocess pin =2.2.x → ^2.3.1 in nu_plugin_mcp, nu_plugin_nats, nu_plugin_typedialog
(required by nu-plugin-core 0.111.0)
- nu_plugin_typedialog: BackendType::Web initializer — add open_browser: false field
- nu_plugin_auth: implement missing user_info_to_value helper referenced in tests
Scripts:
- update_all_plugins.nu: fix [package].version update on minor bumps; add [dev-dependencies]
pass; add nu-plugin-test-support to managed crates
- download_nushell.nu: rustup override unset before rm -rf on nushell dir replace;
fix unclosed ) in string interpolation
This commit is contained in:
parent
b6eeaee4da
commit
d9ef2f0d5b
153
CHANGELOG.md
153
CHANGELOG.md
@ -1,10 +1,99 @@
|
||||
# Changelog
|
||||
|
||||
## [0.111.0] - 2026-03-11 (NUSHELL 0.111.0 COMPATIBILITY)
|
||||
|
||||
### 🔧 Version Update
|
||||
|
||||
- Nushell 0.111.0 compatibility — all 18 plugins updated
|
||||
- `rust-toolchain.toml` channel updated to `1.93.1` (nushell 0.111.0 requires rustc ≥1.91.1)
|
||||
- Removed stale `rustup override` for `nushell/` directory from update toolchain
|
||||
|
||||
### 🐛 Fixes
|
||||
|
||||
- `interprocess` pin updated `=2.2.x` → `^2.3.1` in `nu_plugin_mcp`, `nu_plugin_nats`,
|
||||
`nu_plugin_typedialog` — required by `nu-plugin-core 0.111.0`
|
||||
- `nu_plugin_typedialog`: `BackendType::Web` initializer updated with new `open_browser: false`
|
||||
field added in `typedialog-core`
|
||||
- `nu_plugin_auth`: implemented missing `user_info_to_value` helper referenced in tests
|
||||
- `download_nushell.nu`: fixed unclosed interpolation delimiter in version mismatch warning
|
||||
- `update_all_plugins.nu`: fixed version update to also cover `[package].version` on minor bumps
|
||||
and `[dev-dependencies]` section (`nu-plugin-test-support`); added `nu-plugin-test-support`
|
||||
to managed crates list
|
||||
- `download_nushell.nu`: `rustup override unset` before `rm -rf` on nushell directory replace —
|
||||
prevents stale toolchain overrides surviving source replacement
|
||||
|
||||
---
|
||||
|
||||
## [0.110.0] - 2026-02-10 (TYPEDIALOG + MCP CLIENT PLUGINS)
|
||||
|
||||
### ✨ New Plugins
|
||||
|
||||
#### nu_plugin_typedialog
|
||||
|
||||
- Replaces `provisioning/core/shlib/` bash TTY wrappers with a native Nushell plugin
|
||||
- `typedialog form <path> [--backend cli|web] [--port] [--initial <record>]` — execute
|
||||
interactive form from TOML definition, returns record of results
|
||||
- `typedialog nickel-roundtrip <ncl> <toml> <ncl> [--no-validate]` — read Nickel → form
|
||||
→ write back, returns `{output_nickel, validation_passed, form_results, changed}`
|
||||
- `typedialog text/confirm/select/multi-select/password` — direct prompt primitives
|
||||
- ESC/cancel returns `null` (Value::nothing), never an error
|
||||
- Backed by `typedialog-core` crate with CLI and Web backends
|
||||
- Fixed `interprocess` API break via `=2.2.2` pin (nushell 0.110.0 compat)
|
||||
|
||||
#### nu_plugin_mcp
|
||||
|
||||
- MCP client plugin — spawns `provisioning-mcp-server` as child process
|
||||
- Session state held in `Arc<Mutex<Option<McpSession>>>` on plugin struct (persists across
|
||||
command calls within plugin process lifetime)
|
||||
- `mcp connect <binary> [--provisioning-path]` — MCP handshake (initialize + initialized)
|
||||
- `mcp tools list` — returns table `{name, description, required_args}`
|
||||
- `mcp tool call <name> [--payload <record>]` — dispatches tool, maps content envelope
|
||||
to Nu values (JSON-parsed text or `{error: true, message: ...}` record)
|
||||
- `mcp disconnect` — kills child process, clears session
|
||||
|
||||
### 🔧 Infrastructure
|
||||
|
||||
- `provisioning-mcp-server/src/simple_main.rs` — raw JSON-RPC 2.0 stdio transport
|
||||
replaces broken `rust-mcp-sdk` dependency; 37 tools restored from `main.rs.disabled`
|
||||
- `plugin_registry.toml` — added entries for `nu_plugin_typedialog` and `nu_plugin_mcp`
|
||||
|
||||
---
|
||||
|
||||
## [0.109.0] - 2025-12-15 (KCL & NICKEL PLUGINS WITH CACHING)
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
#### Configuration Loading Plugins with Caching
|
||||
|
||||
- **nu_plugin_kcl** - Enhanced with automatic caching support
|
||||
- Added `kcl-eval` command for primary config loading with cache
|
||||
- Added `kcl-cache-status` command for cache diagnostics
|
||||
- SHA256-based cache keys: `~/.cache/provisioning/config-cache/`
|
||||
- Expected performance: 20-50x improvement (cache hit ~5ms vs CLI ~300ms)
|
||||
|
||||
- **nu_plugin_nickel** - New independent plugin for Nickel configs
|
||||
- Complete implementation with identical caching architecture
|
||||
- Added `nickel-eval` command for primary config loading with cache
|
||||
- Added `nickel-cache-status` command for cache diagnostics
|
||||
- Shared cache directory with KCL plugin
|
||||
- Commands: `nickel-eval`, `nickel-export`, `nickel-format`, `nickel-validate`, `nickel-cache-status`
|
||||
|
||||
### 🔧 Plugin Registry Enhancements
|
||||
|
||||
- Restructured registry format: `[plugins.*]` nested structure
|
||||
- Added `local_path` field for all plugins
|
||||
- Added `upstream_branch` field for upstream tracking
|
||||
- Added `[settings]` section for managed dependencies
|
||||
- Updated nu_plugin_nickel registry entry with complete metadata
|
||||
|
||||
---
|
||||
|
||||
## [0.109.0] - 2025-12-11 (COMPREHENSIVE DOCUMENTATION & COMMIT PREPARATION)
|
||||
|
||||
### 📚 Documentation Updates
|
||||
|
||||
#### Repository Documentation
|
||||
|
||||
- **CHANGES.md** (provisioning/core): Complete summary of core system updates
|
||||
- CLI, libraries, plugins, and utilities changes
|
||||
- File-by-file breakdown organized by directory
|
||||
@ -16,6 +105,7 @@
|
||||
- Ready for: `git commit -F provisioning/core/COMMIT_MESSAGE.md`
|
||||
|
||||
#### Repository Documentation (provisioning/)
|
||||
|
||||
- **CHANGES.md**: Summary of configuration and documentation updates
|
||||
- Configuration files (config/, kcl/, core/, extensions/, platform/)
|
||||
- Documentation updates across all modules
|
||||
@ -41,6 +131,7 @@ All repositories now have:
|
||||
### 🎯 Plugin Exclusion System (2025-12-03)
|
||||
|
||||
#### Architecture Implementation
|
||||
|
||||
- **Configuration-Driven Plugin Exclusion**:
|
||||
- Central registry in `etc/plugin_registry.toml` for managing exclusions
|
||||
- Single source of truth for which plugins excluded from distributions
|
||||
@ -48,23 +139,27 @@ All repositories now have:
|
||||
- Future-proof design supporting profiles and conditional exclusions
|
||||
|
||||
#### Collection System Enhancement (`scripts/collect_full_binaries.nu`)
|
||||
|
||||
- Added `get_excluded_plugins()` helper function to load exclusion list
|
||||
- Updated `get_workspace_plugins_info()` to filter excluded workspace plugins
|
||||
- Updated `get_custom_plugins_info()` to filter excluded custom plugins
|
||||
- Distribution collections now exclude specified plugins automatically
|
||||
|
||||
#### Packaging System Enhancement (`scripts/create_distribution_packages.nu`)
|
||||
|
||||
- Added `get_excluded_plugins_dist()` helper function
|
||||
- Updated `get_plugin_components()` to filter both custom and workspace excluded plugins
|
||||
- Distribution packages now exclude specified plugins automatically
|
||||
- Consistent filtering with collection system
|
||||
|
||||
#### Installation Configuration (`scripts/templates/default_config.nu`)
|
||||
|
||||
- Removed excluded plugins from auto-load plugin list
|
||||
- Added documentation explaining why plugins are excluded
|
||||
- Users won't see missing plugin errors in fresh installations
|
||||
|
||||
#### Documentation - Complete Coverage
|
||||
|
||||
- **User Guide**: `docs/PLUGIN_EXCLUSION_GUIDE.md` (400+ lines)
|
||||
- Quick start for users, developers, release managers
|
||||
- Common tasks with step-by-step instructions
|
||||
@ -107,6 +202,7 @@ All repositories now have:
|
||||
- Testing validation
|
||||
|
||||
#### Configuration Updates
|
||||
|
||||
- **Registry**: `etc/plugin_registry.toml`
|
||||
- Added `[distribution]` section with `excluded_plugins` list
|
||||
- Marked `nu_plugin_example` as excluded with reason documentation
|
||||
@ -114,12 +210,14 @@ All repositories now have:
|
||||
#### Files Modified (9 files total)
|
||||
|
||||
**Implementation** (4 files):
|
||||
|
||||
- `etc/plugin_registry.toml` - Config: Added `[distribution]` section
|
||||
- `scripts/collect_full_binaries.nu` - Feature: Added filtering functions
|
||||
- `scripts/create_distribution_packages.nu` - Feature: Added filtering functions
|
||||
- `scripts/templates/default_config.nu` - Config: Removed excluded from auto-load
|
||||
|
||||
**Documentation** (5 files):
|
||||
|
||||
- `docs/PLUGIN_EXCLUSION_GUIDE.md` - NEW: User guide
|
||||
- `docs/architecture/README.md` - NEW: Navigation index
|
||||
- `docs/architecture/PLUGIN_EXCLUSION_SYSTEM.md` - NEW: Technical spec
|
||||
@ -128,6 +226,7 @@ All repositories now have:
|
||||
- `docs/PROVISIONING_PLUGINS_SUMMARY.md` - UPDATED: Added links
|
||||
|
||||
#### Impact & Behavior Changes
|
||||
|
||||
- ✅ Build system UNCHANGED - all plugins still built
|
||||
- ✅ Test system UNCHANGED - all plugins still tested
|
||||
- ✅ Dev workflows UNCHANGED - developers can use excluded plugins
|
||||
@ -136,6 +235,7 @@ All repositories now have:
|
||||
- ❌ Auto-load NOW excludes specified plugins from user configs
|
||||
|
||||
#### Example: nu_plugin_example
|
||||
|
||||
- ✅ Still built with `just build`
|
||||
- ✅ Still tested with `just test`
|
||||
- ✅ Still available in build output for reference
|
||||
@ -144,6 +244,7 @@ All repositories now have:
|
||||
- ❌ NOT auto-loaded in user installations
|
||||
|
||||
#### Testing & Verification
|
||||
|
||||
- ✅ Registry parses correctly
|
||||
- ✅ Collection system excludes plugins
|
||||
- ✅ Packaging system excludes plugins
|
||||
@ -154,6 +255,7 @@ All repositories now have:
|
||||
- ✅ All 1,400+ lines of documentation complete
|
||||
|
||||
#### Quality Metrics
|
||||
|
||||
- **Code Changes**: 40 lines added, 1 line removed (net +39)
|
||||
- **Documentation**: 1,400+ lines of comprehensive coverage
|
||||
- **Error Handling**: 100% graceful degradation
|
||||
@ -168,6 +270,7 @@ All repositories now have:
|
||||
### 🚀 Bootstrap Installer & Distribution Improvements (2025-10-19)
|
||||
|
||||
#### Install Script Architecture (DRY Design)
|
||||
|
||||
- **Implemented Symlink-Based DRY Architecture**:
|
||||
- Single source of truth: `installers/bootstrap/install.sh` (1,247 lines)
|
||||
- Symlinks: `./install.sh` → `installers/bootstrap/install.sh`
|
||||
@ -176,6 +279,7 @@ All repositories now have:
|
||||
- No code duplication across installation paths
|
||||
|
||||
#### Archive Extraction Fixes (Critical)
|
||||
|
||||
- **Fixed Archive Binary Detection (Version-Agnostic)**:
|
||||
- Root cause: `find` command returning parent directory itself in results
|
||||
- Solution: Added `-not -path "$extract_dir"` to exclude starting directory
|
||||
@ -191,6 +295,7 @@ All repositories now have:
|
||||
- Validates binaries exist before using them
|
||||
|
||||
#### Plugin Registration Error Handling
|
||||
|
||||
- **Improved Plugin Registration with Version Mismatch Detection**:
|
||||
- Captures both stdout and stderr from plugin add commands
|
||||
- Detects version incompatibility errors: "is not compatible with version"
|
||||
@ -202,6 +307,7 @@ All repositories now have:
|
||||
- Installation continues successfully even with version mismatches
|
||||
|
||||
#### Shell Configuration PATH Update Messaging
|
||||
|
||||
- **Fixed Confusing PATH Update Messages**:
|
||||
- Root cause: Script conflated "PATH found" with "PATH needs updating"
|
||||
- Solution: Track two separate states:
|
||||
@ -213,6 +319,7 @@ All repositories now have:
|
||||
- ⚠️ "Could not find..." (when file doesn't exist)
|
||||
|
||||
#### Installation Features
|
||||
|
||||
- **`--source-path` Option for Local Installation**:
|
||||
- Install from local archive: `--source-path archive.tar.gz`
|
||||
- Install from local directory: `--source-path /path/to/binaries`
|
||||
@ -226,6 +333,7 @@ All repositories now have:
|
||||
- Preserves user choice (keep or remove config)
|
||||
|
||||
#### Documentation Updates
|
||||
|
||||
- **Updated CLAUDE.md** with:
|
||||
- Install Script Architecture (DRY Design) section
|
||||
- Source of truth location and symlink structure
|
||||
@ -241,6 +349,7 @@ All repositories now have:
|
||||
- How DRY Works (3-step explanation)
|
||||
|
||||
#### Files Modified
|
||||
|
||||
- `installers/bootstrap/install.sh` - All fixes (1,247 lines, +3 lines)
|
||||
- `./install.sh` - Auto-updated via symlink
|
||||
- `./scripts/templates/install.sh` - Auto-updated via symlink
|
||||
@ -248,6 +357,7 @@ All repositories now have:
|
||||
- `README.md` - Added install script section
|
||||
|
||||
#### Testing & Verification
|
||||
|
||||
- ✅ Archive extraction works with version-agnostic detection
|
||||
- ✅ Installation to `~/.local` successful (16 binaries)
|
||||
- ✅ Installation to `~/.local/bin` successful (21 plugins loaded)
|
||||
@ -256,6 +366,7 @@ All repositories now have:
|
||||
- ✅ Clean uninstall followed by fresh reinstall works perfectly
|
||||
|
||||
#### Impact
|
||||
|
||||
- ✅ Users can install from any version of nushell-full archive
|
||||
- ✅ Clear error messages if binaries not found in archive
|
||||
- ✅ Version mismatch plugins skipped without breaking installation
|
||||
@ -270,6 +381,7 @@ All repositories now have:
|
||||
### 🎯 Help System & Build Process Fixes (2025-10-19)
|
||||
|
||||
#### Help System Improvements
|
||||
|
||||
- **Added Version Update Module to Help System**:
|
||||
- Version-update module now discoverable via `just help modules`
|
||||
- Added to `just help` main output with key commands
|
||||
@ -277,11 +389,13 @@ All repositories now have:
|
||||
- Full integration into help system navigation
|
||||
|
||||
#### New Help Commands
|
||||
|
||||
- **`just commands`**: New recipe showing all commands organized by group (alias for `just --list`)
|
||||
- Shows [version-update] group with all 30+ update recipes
|
||||
- Replaces need to manually run `just --list`
|
||||
|
||||
#### Build Process Fixes
|
||||
|
||||
- **Fixed Plugin Archive Creation Bug**:
|
||||
- Phase 3 "No plugins found" warning fixed
|
||||
- Root cause: `each` command returns null, breaking count logic
|
||||
@ -301,6 +415,7 @@ All repositories now have:
|
||||
- Properly calculates archive file size in MB
|
||||
|
||||
#### Plugin Dependency Update Optimization
|
||||
|
||||
- **Fixed Unnecessary Plugin Rebuilds**:
|
||||
- Root cause: `update_all_plugins.nu` always touched all Cargo.toml files
|
||||
- Solution: Only save if content actually changed
|
||||
@ -309,6 +424,7 @@ All repositories now have:
|
||||
- Result: Only plugins with real changes trigger rebuilds (hashes, highlight)
|
||||
|
||||
#### Files Modified
|
||||
|
||||
- `justfiles/help.just` - Added version-update module to help system
|
||||
- `scripts/create_full_distribution.nu` - Fixed plugin collection filtering (exclude .d files)
|
||||
- `scripts/create_distribution_packages.nu` - Fixed get_plugin_components to look in correct directories
|
||||
@ -316,6 +432,7 @@ All repositories now have:
|
||||
- `CHANGELOG.md` - Documented all fixes
|
||||
|
||||
#### Archive Content & Structure Fixes (Critical Fix)
|
||||
|
||||
- **Fixed nushell-full archive missing plugins**:
|
||||
- Root cause: `get_plugin_components` looked in distribution directory (staging output)
|
||||
- Solution: Look in `nu_plugin_*/target/release/` (actual binaries)
|
||||
@ -343,6 +460,7 @@ All repositories now have:
|
||||
- Reduces archive size and keeps distribution focused
|
||||
|
||||
#### Impact
|
||||
|
||||
- ✅ Version-update commands now fully discoverable
|
||||
- ✅ Phase 3 bin archive creation works correctly
|
||||
- ✅ nushell-full archive contains nu + all plugins
|
||||
@ -357,23 +475,27 @@ All repositories now have:
|
||||
### 🎯 Nushell Core Update: 0.107.1 → 0.108.0
|
||||
|
||||
#### Major Changes
|
||||
|
||||
- **Updated Nushell to 0.108.0** with MCP (Model Context Protocol) support
|
||||
- **Fixed critical documentation bugs** in `best_nushell_code.md` affecting all code generation
|
||||
- **Created comprehensive automation framework** for future version updates
|
||||
- **Built complete distribution** with nushell 0.108.0 + all plugins
|
||||
|
||||
#### Critical Bug Fixes
|
||||
|
||||
- **Rule 16 (Function Signatures)**: Fixed incorrect syntax `]: type {` → `]: nothing -> type {`
|
||||
- **Rule 17 (String Interpolation)**: Fixed non-working syntax `[$var]` → `($var)`
|
||||
- Both bugs were in documentation and caused all generated code to fail parsing
|
||||
|
||||
#### New Features
|
||||
|
||||
- ✅ **MCP Support**: Model Context Protocol for AI agent integration
|
||||
- ✅ **Enhanced SQLite**: Improved database operations
|
||||
- ✅ **System Clipboard**: Native clipboard integration
|
||||
- ✅ **Trash Support**: Safe file deletion to trash
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
- **`into value` → `detect type`**: Command deprecated (still works with warning)
|
||||
- Shows helpful migration message
|
||||
- Recommends `update cells {detect type}` instead
|
||||
@ -382,6 +504,7 @@ All repositories now have:
|
||||
- Requires explicit error handling with `try`/`catch`
|
||||
|
||||
#### New Automation Scripts (8 scripts created)
|
||||
|
||||
1. **`download_nushell.nu`** (285 lines) - Download from GitHub tags
|
||||
2. **`analyze_nushell_features.nu`** (350 lines) - Parse and validate features
|
||||
3. **`audit_crate_dependencies.nu`** (390 lines) - Audit plugin dependencies
|
||||
@ -392,18 +515,21 @@ All repositories now have:
|
||||
8. **`complete_update.nu`** (NEW) - All-in-one update script
|
||||
|
||||
#### Documentation Created
|
||||
|
||||
- **`updates/108/NUSHELL_0.108_UPDATE_SUMMARY.md`** - Complete update summary
|
||||
- **`updates/108/MIGRATION_0.108.0.md`** - Step-by-step migration guide
|
||||
- **`updates/108/NUSHELL_UPDATE_AUTOMATION.md`** - Automation documentation
|
||||
- **`guides/COMPLETE_VERSION_UPDATE_GUIDE.md`** - Comprehensive update guide
|
||||
|
||||
#### Build System Improvements
|
||||
|
||||
- **Build Time**: Optimized to 2m 55s (from 15+ minutes)
|
||||
- **Features**: All desired features validated and included
|
||||
- **Workspace**: Proper `--workspace` flag for system plugins
|
||||
- **Artifacts**: Complete binary collection system
|
||||
|
||||
#### Validation & Testing
|
||||
|
||||
- ✅ All syntax patterns tested against actual 0.108.0 binary
|
||||
- ✅ Function signatures validated
|
||||
- ✅ String interpolation validated
|
||||
@ -412,12 +538,14 @@ All repositories now have:
|
||||
- ✅ Breaking changes verified
|
||||
|
||||
#### Impact
|
||||
|
||||
- **Developer Experience**: 80% reduction in update time with automation
|
||||
- **Code Quality**: All future code will use correct syntax
|
||||
- **Maintainability**: Semi-automated updates with 3 manual checkpoints
|
||||
- **Documentation**: Comprehensive guides for all future updates
|
||||
|
||||
#### Files Modified
|
||||
|
||||
- `best_nushell_code.md` - Fixed Rules 16 & 17, Quick Reference, Summary
|
||||
- `nushell/` - Updated to 0.108.0
|
||||
- `nu_plugin_*/Cargo.toml` - Dependency versions updated
|
||||
@ -426,6 +554,7 @@ All repositories now have:
|
||||
- `guides/` - New comprehensive guide
|
||||
|
||||
#### Migration Notes
|
||||
|
||||
- Old `into value` usage still works but shows deprecation warning
|
||||
- Update to `detect type` or `update cells {detect type}` to remove warnings
|
||||
- Stream collection operations may need `try`/`catch` for error handling
|
||||
@ -438,6 +567,7 @@ All repositories now have:
|
||||
### 🚀 Major Feature: Complete Nushell Distribution System
|
||||
|
||||
#### Full Distribution Infrastructure
|
||||
|
||||
- **Complete Nushell binary distribution**: Added capability to build, package, and distribute Nushell itself alongside plugins
|
||||
- **Zero-prerequisite installation**: Users can install complete Nushell environment without having Rust, Cargo, or Nushell pre-installed
|
||||
- **Cross-platform bootstrap installers**: Universal POSIX shell installer (`install.sh`) and Windows PowerShell installer (`install.ps1`)
|
||||
@ -445,6 +575,7 @@ All repositories now have:
|
||||
- **Self-contained distribution packages**: Complete packages including binaries, configuration, documentation, and installers
|
||||
|
||||
#### New Build System
|
||||
|
||||
- **`scripts/build_nushell.nu`**: Comprehensive script to build nushell with all workspace plugins
|
||||
- **`scripts/collect_full_binaries.nu`**: Advanced binary collection system for nushell + all plugins
|
||||
- **`scripts/create_distribution_packages.nu`**: Multi-platform package creator with manifest generation
|
||||
@ -452,6 +583,7 @@ All repositories now have:
|
||||
- **Enhanced justfile**: Added 40+ new recipes in `justfiles/full_distro.just` for complete distribution workflows
|
||||
|
||||
#### Installation and Configuration System
|
||||
|
||||
- **`scripts/install_full_nushell.nu`**: Advanced nu-based installer with plugin selection and configuration options
|
||||
- **`scripts/verify_installation.nu`**: Comprehensive installation verification with detailed reporting
|
||||
- **`scripts/templates/default_config.nu`**: Complete 500+ line Nushell configuration with optimizations
|
||||
@ -459,6 +591,7 @@ All repositories now have:
|
||||
- **`etc/distribution_config.toml`**: Central distribution configuration management
|
||||
|
||||
#### Bootstrap Installers (Zero Prerequisites)
|
||||
|
||||
- **`installers/bootstrap/install.sh`**: 900+ line universal POSIX installer for Linux/macOS
|
||||
- Automatic platform detection and binary download
|
||||
- Build from source fallback capability
|
||||
@ -468,12 +601,15 @@ All repositories now have:
|
||||
- **Complete documentation**: Installation guides, troubleshooting, and security considerations
|
||||
|
||||
#### Uninstall System
|
||||
|
||||
- **`scripts/templates/uninstall.sh`** and **`uninstall.ps1`**: Clean removal scripts for all platforms
|
||||
- **Complete cleanup**: Removes binaries, configurations, PATH entries with optional backup
|
||||
- **Plugin unregistration**: Clean removal from nushell registry
|
||||
|
||||
#### Key Distribution Workflows
|
||||
```bash
|
||||
|
||||
```nushell
|
||||
bash
|
||||
# Build complete distribution
|
||||
just build-full # Build nushell + all plugins
|
||||
|
||||
@ -489,6 +625,7 @@ just release-full-cross # Full cross-platform release
|
||||
```
|
||||
|
||||
#### Installation Experience
|
||||
|
||||
- **One-liner installation**: `curl -sSf https://your-url/install.sh | sh`
|
||||
- **Multiple installation modes**: User (~/.local/bin), system (/usr/local/bin), portable
|
||||
- **Automatic plugin registration**: All plugins registered and verified with `nu -c "plugin list"`
|
||||
@ -497,6 +634,7 @@ just release-full-cross # Full cross-platform release
|
||||
### 🎯 Major Updates
|
||||
|
||||
#### Documentation and Repository Structure
|
||||
|
||||
- **Enhanced README.md**: Significantly expanded documentation with 682 new lines covering:
|
||||
- Comprehensive plugin collection overview
|
||||
- Detailed development workflows and automation
|
||||
@ -505,12 +643,14 @@ just release-full-cross # Full cross-platform release
|
||||
- Complete command reference and usage examples
|
||||
|
||||
#### Script and Automation Cleanup
|
||||
|
||||
- **Removed legacy scripts**: Cleaned up old bash scripts (build-all.sh, collect-install.sh, make_plugin.sh)
|
||||
- **Streamlined automation**: Consolidated script system in favor of unified approach via justfile and nushell scripts
|
||||
|
||||
### 🔧 Plugin Updates and Dependency Management
|
||||
|
||||
#### Nushell Core Updates
|
||||
|
||||
- **Updated nushell submodule**: Comprehensive update to latest nushell version (0.107.1)
|
||||
- **Synchronized dependencies**: Updated all nu-* dependencies across all plugins for version consistency
|
||||
- **Updated Cargo.lock files**: Refreshed dependency lock files for all plugins
|
||||
@ -518,25 +658,30 @@ just release-full-cross # Full cross-platform release
|
||||
#### Plugin-Specific Changes
|
||||
|
||||
##### nu_plugin_clipboard
|
||||
|
||||
- Updated Cargo.toml with new dependency versions
|
||||
- Refreshed Cargo.lock with 253 dependency changes
|
||||
|
||||
##### nu_plugin_desktop_notifications
|
||||
|
||||
- Updated Cargo.toml for nushell 0.107.1 compatibility
|
||||
- Refreshed Cargo.lock with 218 dependency updates
|
||||
|
||||
##### nu_plugin_hashes
|
||||
|
||||
- **Enhanced functionality**: Updated hasher.rs implementation
|
||||
- **Build system improvements**: Modified build.rs configuration
|
||||
- Updated Cargo.toml with 24 configuration changes
|
||||
- Refreshed Cargo.lock with 283 dependency updates
|
||||
|
||||
##### nu_plugin_highlight
|
||||
|
||||
- **Code improvements**: Enhanced highlight.rs and plugin.rs implementations
|
||||
- Updated for new nushell plugin API compatibility
|
||||
- Refreshed Cargo.lock with 476 dependency updates
|
||||
|
||||
##### nu_plugin_image
|
||||
|
||||
- **Major code refactoring**: Comprehensive updates to image processing modules
|
||||
- **Removed deprecated code**: Deleted ansi_to_image.rs (replaced with modular approach)
|
||||
- **Enhanced modules**:
|
||||
@ -548,21 +693,25 @@ just release-full-cross # Full cross-platform release
|
||||
- Refreshed Cargo.lock with 494 dependency updates
|
||||
|
||||
##### nu_plugin_kcl and nu_plugin_tera
|
||||
|
||||
- Updated submodule references
|
||||
- Synchronized with latest upstream changes
|
||||
|
||||
##### nu_plugin_port_extension and nu_plugin_qr_maker
|
||||
|
||||
- Updated Cargo.toml for version consistency
|
||||
- Refreshed Cargo.lock files
|
||||
|
||||
#### API KCL Plugin
|
||||
|
||||
- Updated Cargo.lock with 266 dependency changes
|
||||
|
||||
### 🏗️ Repository Infrastructure Updates
|
||||
|
||||
#### Git Tracking Cleanup
|
||||
|
||||
- **Removed nushell directory from tracking**: The nushell submodule directory is now properly ignored
|
||||
- **Updated .gitignore**: Added patterns for nushell directory, nushell-* files, and *.tar.gz archives
|
||||
- **Updated .gitignore**: Added patterns for nushell directory, nushell-*files, and*.tar.gz archives
|
||||
|
||||
### 📊 Statistics Summary
|
||||
|
||||
|
||||
91
README.md
91
README.md
@ -1,20 +1,19 @@
|
||||
# 🚀 Nushell Plugins Repository
|
||||
|
||||
**Current Nushell Version**: 0.108.0 | **Last Updated**: 2025-10-18
|
||||
**Current Nushell Version**: 0.111.0 | **Last Updated**: 2026-03-11
|
||||
|
||||
A comprehensive collection of nushell plugins with automated upstream tracking, dependency management, development workflows, **complete Nushell distribution system**, and **semi-automated version update framework**.
|
||||
|
||||
## 🎯 Latest Update: Nushell 0.108.0
|
||||
## 🎯 Latest Update: Nushell 0.111.0
|
||||
|
||||
**Major highlights of the 0.108.0 update:**
|
||||
- ✅ **MCP Support**: Model Context Protocol for AI agent integration
|
||||
- ✅ **Critical Bug Fixes**: Fixed documentation syntax errors affecting all code generation
|
||||
- ✅ **Automation Framework**: 8 new scripts for semi-automated version updates
|
||||
- ✅ **Complete Documentation**: Migration guides, automation docs, and validation reports
|
||||
- ✅ **80% Faster Updates**: Automated workflows with strategic manual checkpoints
|
||||
**Highlights of the 0.111.0 update:**
|
||||
|
||||
**→ [START HERE: UPDATE.md](UPDATE.md)** for version update instructions
|
||||
See [`CHANGELOG.md`](CHANGELOG.md) for complete details | Read [`updates/108/`](updates/108/) for full documentation
|
||||
- ✅ **18 plugins updated** to Nushell 0.111.0
|
||||
- ✅ **Rust toolchain** bumped to 1.93.1 (nushell 0.111.0 requires ≥1.91.1)
|
||||
- ✅ **interprocess ^2.3.1** — resolved conflict with nu-plugin-core 0.111.0 across mcp/nats/typedialog
|
||||
- ✅ **Update script fixes** — `[package].version` and `[dev-dependencies]` now correctly updated on minor version bumps
|
||||
|
||||
See [`CHANGELOG.md`](CHANGELOG.md) for complete details.
|
||||
|
||||
## 🆕 NEW: Full Nushell Distribution System
|
||||
|
||||
@ -23,6 +22,7 @@ See [`CHANGELOG.md`](CHANGELOG.md) for complete details | Read [`updates/108/`](
|
||||
This repository provides **complete Nushell distributions** that include Nushell itself plus all plugins, offering zero-prerequisite installation for end users:
|
||||
|
||||
### 🎯 End User Installation (Zero Prerequisites)
|
||||
|
||||
```bash
|
||||
# One-liner installation (Linux/macOS)
|
||||
curl -sSf https://your-url/install.sh | sh
|
||||
@ -36,6 +36,7 @@ tar -xzf nushell-full-*.tar.gz && cd nushell-full-* && ./install.sh
|
||||
```
|
||||
|
||||
### 🚀 Developer Distribution Commands
|
||||
|
||||
```bash
|
||||
just build-full # Build nushell + all plugins
|
||||
just pack-full # Create distribution package
|
||||
@ -45,6 +46,7 @@ just release-full-cross # Complete release workflow
|
||||
```
|
||||
|
||||
### ✨ Key Features
|
||||
|
||||
- **Zero Prerequisites**: No Rust, Cargo, or Nu installation required
|
||||
- **Cross-Platform**: Linux, macOS, Windows support
|
||||
- **Complete Environment**: Nushell + all plugins + configuration
|
||||
@ -83,6 +85,7 @@ tar -xzf nushell-full-*.tar.gz && cd nushell-full-* && ./install.sh
|
||||
### For Developers
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install required tools
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Rust
|
||||
@ -91,6 +94,7 @@ cargo install just # Just (optional
|
||||
```
|
||||
|
||||
#### Development Workflow
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone <repository-url>
|
||||
@ -130,6 +134,7 @@ The Full Distribution System transforms this repository from a **development-foc
|
||||
### End User Experience
|
||||
|
||||
**Before**: Complex development setup required
|
||||
|
||||
```bash
|
||||
# Users needed to:
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Install Rust
|
||||
@ -139,6 +144,7 @@ just validate-nushell && just build # Build everythin
|
||||
```
|
||||
|
||||
**After**: Zero-prerequisite installation
|
||||
|
||||
```bash
|
||||
# Users now only need:
|
||||
curl -sSf https://your-url/install.sh | sh # Done!
|
||||
@ -149,6 +155,7 @@ curl -sSf https://your-url/install.sh | sh # Done!
|
||||
#### Building Complete Distributions
|
||||
|
||||
**Step 1: Build Nushell + System Plugins**
|
||||
|
||||
```bash
|
||||
# Build Nushell with built-in system plugins (uses cargo build --workspace)
|
||||
just build-nushell # Builds: nu + nu_plugin_formats, nu_plugin_inc, nu_plugin_gstat,
|
||||
@ -159,6 +166,7 @@ just build-nushell-target linux-arm64 # Cross-compile system plugins
|
||||
```
|
||||
|
||||
**Step 2: Build Everything (System + Custom Plugins)**
|
||||
|
||||
```bash
|
||||
# Build nushell + system plugins + custom plugins from this repo
|
||||
just build-full # Native build (calls build-nushell + build custom plugins)
|
||||
@ -167,6 +175,7 @@ just build-full-all # All platforms
|
||||
```
|
||||
|
||||
**Step 3: Collect Built Binaries**
|
||||
|
||||
```bash
|
||||
# Collect nushell binary + all plugins for distribution
|
||||
just collect # Current platform (darwin-arm64)
|
||||
@ -175,6 +184,7 @@ just collect-platform PLATFORM # Specific platform
|
||||
```
|
||||
|
||||
**Step 4: Create Distribution Packages**
|
||||
|
||||
```bash
|
||||
# Create distribution packages
|
||||
just pack-full # Current platform
|
||||
@ -187,6 +197,7 @@ just test-install-full # Test complete installation process
|
||||
```
|
||||
|
||||
#### Cross-Platform Release
|
||||
|
||||
```bash
|
||||
# Complete release workflow
|
||||
just release-full-cross # Build → Pack → Verify for all platforms
|
||||
@ -200,6 +211,7 @@ just release-full-windows # Windows distributions
|
||||
#### Installation Modes
|
||||
|
||||
**System Installation** (recommended for end users):
|
||||
|
||||
```bash
|
||||
# Install to system paths with proper integration
|
||||
./install.sh
|
||||
@ -212,6 +224,7 @@ just release-full-windows # Windows distributions
|
||||
```
|
||||
|
||||
**Local Installation** (development/testing):
|
||||
|
||||
```bash
|
||||
# Install to user directory without system integration
|
||||
./install.sh --local
|
||||
@ -223,6 +236,7 @@ just release-full-windows # Windows distributions
|
||||
### Distribution Architecture
|
||||
|
||||
#### Components Included
|
||||
|
||||
- **Nushell Binary**: Complete nushell installation
|
||||
- **All Plugins**: Every plugin in the repository
|
||||
- **Configuration**: Optimized default configuration
|
||||
@ -231,6 +245,7 @@ just release-full-windows # Windows distributions
|
||||
- **Verification**: Installation integrity checks
|
||||
|
||||
#### Platform Support
|
||||
|
||||
| Platform | Architecture | Status | Installation Method |
|
||||
|----------|-------------|--------|-------------------|
|
||||
| **Linux** | x86_64 | ✅ Full | `curl` installer + manual |
|
||||
@ -240,6 +255,7 @@ just release-full-windows # Windows distributions
|
||||
| **Windows** | x86_64 | ✅ Full | PowerShell installer + manual |
|
||||
|
||||
#### Bootstrap Installers
|
||||
|
||||
- **Smart Detection**: Automatically detects platform and architecture
|
||||
- **Conflict Resolution**: Handles existing Nushell installations
|
||||
- **Path Management**: Configures PATH and shell integration
|
||||
@ -249,18 +265,21 @@ just release-full-windows # Windows distributions
|
||||
### Use Cases
|
||||
|
||||
#### For End Users
|
||||
|
||||
- **Simple Installation**: Get Nushell + all plugins with one command
|
||||
- **No Prerequisites**: No need for Rust, Git, or development tools
|
||||
- **Professional Experience**: Clean installation/uninstallation
|
||||
- **Immediate Productivity**: Pre-configured environment with all plugins
|
||||
|
||||
#### For System Administrators
|
||||
|
||||
- **Bulk Deployment**: Deploy to multiple systems easily
|
||||
- **Consistent Environment**: Identical setup across all machines
|
||||
- **Offline Installation**: Manual packages work without internet
|
||||
- **Integration Ready**: System-wide installation with proper paths
|
||||
|
||||
#### for Distributors/Packagers
|
||||
|
||||
- **Ready Binaries**: All binaries built and tested
|
||||
- **Cross-Platform**: Support for all major platforms
|
||||
- **Checksums Included**: Integrity verification built-in
|
||||
@ -302,33 +321,34 @@ This repository provides:
|
||||
| **nu_plugin_fluent** | ✅ Tracked | Upstream | Fluent localization framework |
|
||||
| **nu_plugin_tera** | ✅ Tracked | Private | Tera templating engine (private repo) |
|
||||
| **nu_plugin_kcl** | ✅ Tracked | Private | KCL configuration language (private repo) |
|
||||
| **nu_plugin_nickel** | 🏠 Local | Local | Nickel configuration language (eval, export, format, validate) |
|
||||
|
||||
### Provisioning Platform Plugins (NEW)
|
||||
### Provisioning Platform Plugins
|
||||
|
||||
High-performance native plugins for the provisioning platform with **10x performance improvement** over HTTP APIs:
|
||||
High-performance native plugins for the provisioning platform:
|
||||
|
||||
| Plugin | Type | Description | Performance Gain |
|
||||
|--------|------|-------------|------------------|
|
||||
| **nu_plugin_auth** | 🔐 Security | JWT authentication, MFA (TOTP/WebAuthn), session management | 20% faster |
|
||||
| **nu_plugin_kms** | 🔑 Security | Multi-backend KMS (RustyVault, Age, Cosmian, AWS, Vault) | **10x faster** |
|
||||
| **nu_plugin_orchestrator** | 🎯 Operations | Orchestrator status, workflow validation, task management | **10x faster** |
|
||||
|
||||
**Key Features**:
|
||||
- **Native Performance**: Direct Rust integration eliminates HTTP overhead
|
||||
- **Pipeline Integration**: Full Nushell pipeline support
|
||||
- **Multi-Backend KMS**: RustyVault, Age, Cosmian, AWS KMS, HashiCorp Vault
|
||||
- **Security First**: JWT, MFA (TOTP/WebAuthn), keyring storage
|
||||
- **Production Ready**: Comprehensive tests, error handling, documentation
|
||||
| Plugin | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| **nu_plugin_auth** | 🔐 Security | JWT authentication, MFA (TOTP/WebAuthn), session management |
|
||||
| **nu_plugin_kms** | 🔑 Security | Multi-backend KMS (RustyVault, Age, Cosmian, AWS, Vault) |
|
||||
| **nu_plugin_orchestrator** | 🎯 Operations | Orchestrator status, workflow validation, task management |
|
||||
| **nu_plugin_typedialog** | 💬 UX | Interactive forms/prompts via TypeDialog — replaces shlib TTY wrappers |
|
||||
| **nu_plugin_mcp** | 🤖 AI | MCP client — spawn and interact with `provisioning-mcp-server` |
|
||||
|
||||
**Quick Start**:
|
||||
|
||||
```bash
|
||||
# Build and register provisioning plugins
|
||||
just build-plugin nu_plugin_auth
|
||||
just build-plugin nu_plugin_kms
|
||||
just build-plugin nu_plugin_orchestrator
|
||||
just build-plugin nu_plugin_typedialog
|
||||
just build-plugin nu_plugin_mcp
|
||||
just install-plugin nu_plugin_auth
|
||||
just install-plugin nu_plugin_kms
|
||||
just install-plugin nu_plugin_orchestrator
|
||||
just install-plugin nu_plugin_typedialog
|
||||
just install-plugin nu_plugin_mcp
|
||||
|
||||
# Verify installation
|
||||
nu -c "plugin list | where name =~ provisioning"
|
||||
@ -337,6 +357,7 @@ nu -c "plugin list | where name =~ provisioning"
|
||||
**See Full Guide**: `docs/user/NUSHELL_PLUGINS_GUIDE.md`
|
||||
|
||||
### Legend
|
||||
|
||||
- ✅ **Tracked**: Has upstream repository with automated tracking
|
||||
- 🏠 **Local**: Developed locally without upstream
|
||||
- 🔒 **Private**: Private repository with tracking (requires authentication)
|
||||
@ -412,6 +433,7 @@ For detailed instructions, platform-specific setup, troubleshooting, and advance
|
||||
**➡️ [Complete Building and Cross-Compilation Guide](docs/BUILDING.md)**
|
||||
|
||||
The guide covers:
|
||||
|
||||
- Platform-specific setup and dependencies
|
||||
- Native vs Docker cross-compilation
|
||||
- Configuration and customization
|
||||
@ -608,7 +630,7 @@ The repository now uses a **unified script system** with automatic nushell detec
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
```plaintext
|
||||
scripts/
|
||||
├── run.sh # Universal script runner with version checking
|
||||
├── check_version.nu # Version consistency validator
|
||||
@ -682,7 +704,7 @@ Every script automatically validates that your system nushell version matches th
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
```plaintext
|
||||
nushell-plugins/
|
||||
├── README.md # This file
|
||||
├── justfile # Just task runner recipes
|
||||
@ -731,6 +753,7 @@ nu --version && nu -c "plugin list"
|
||||
```
|
||||
|
||||
**What you get:**
|
||||
|
||||
- Complete Nushell installation
|
||||
- All plugins from this repository
|
||||
- Optimized configuration
|
||||
@ -742,6 +765,7 @@ nu --version && nu -c "plugin list"
|
||||
The installation system uses a **single source of truth** with symlinks to eliminate code duplication:
|
||||
|
||||
**Key Files:**
|
||||
|
||||
- **Source of Truth**: `installers/bootstrap/install.sh` (1,176 lines)
|
||||
- Complete bootstrap installer for Nushell + plugins
|
||||
- Repository: `https://github.com/jesusperezlorenzo/nushell-plugins`
|
||||
@ -775,6 +799,7 @@ Install from local archives or directories without downloading:
|
||||
```
|
||||
|
||||
**Version-Agnostic Archive Detection**:
|
||||
|
||||
- Automatically detects any `nushell-*` version directory
|
||||
- Works with: 0.107, 0.108, 0.109, or any future version
|
||||
- Searches for binaries in: `bin/nu` (preferred) → root `nu` (fallback)
|
||||
@ -782,6 +807,7 @@ Install from local archives or directories without downloading:
|
||||
- Smart extraction and path detection
|
||||
|
||||
**Installation Options**:
|
||||
|
||||
```bash
|
||||
./install.sh # Interactive mode
|
||||
./install.sh --install-dir ~/.local # Custom path, non-interactive
|
||||
@ -792,6 +818,7 @@ Install from local archives or directories without downloading:
|
||||
```
|
||||
|
||||
**How DRY Works**:
|
||||
|
||||
1. **Single Source**: Only `installers/bootstrap/install.sh` is edited
|
||||
2. **Symlinks Propagate**: All changes automatically available at `./install.sh` and `./scripts/templates/install.sh`
|
||||
3. **Verified**: All symlinked paths contain identical content
|
||||
@ -939,6 +966,7 @@ just validate # Validate setup and dependencies
|
||||
**A:** This system requires your installed nushell version to match the submodule version for consistency. All operations automatically check version consistency and will fail if versions don't match.
|
||||
|
||||
**Solutions:**
|
||||
|
||||
- **Auto-fix**: `just fix-nushell` or `./scripts/run.sh --fix --check-only`
|
||||
- **Manual check**: `just validate-nushell`
|
||||
- **Skip (not recommended)**: `./scripts/run.sh --no-version-check script.nu`
|
||||
@ -946,6 +974,7 @@ just validate # Validate setup and dependencies
|
||||
### Q: What happened to the bash wrapper scripts?
|
||||
|
||||
**A:** The repository has been consolidated to eliminate script duplication. The old bash wrappers in `scripts/sh/` have been removed in favor of:
|
||||
|
||||
- **Universal wrapper**: `./scripts/run.sh` with automatic version checking
|
||||
- **Direct nu scripts**: All scripts moved from `scripts/nu/` to `scripts/`
|
||||
- **Just recipes**: Updated to use the new system
|
||||
@ -953,6 +982,7 @@ just validate # Validate setup and dependencies
|
||||
### Q: How does the new script system work?
|
||||
|
||||
**A:** The new system provides:
|
||||
|
||||
1. **Universal wrapper** (`scripts/run.sh`) with automatic nushell detection and version validation
|
||||
2. **Consolidated scripts** - all nu scripts in `scripts/` directory
|
||||
3. **Mandatory version checking** - every operation validates version consistency
|
||||
@ -965,6 +995,7 @@ just validate # Validate setup and dependencies
|
||||
### Q: What happens to my local changes during upstream merges?
|
||||
|
||||
**A:** Local changes are preserved. The system:
|
||||
|
||||
1. Creates backup branches before any merge
|
||||
2. Applies upstream changes in a temporary branch
|
||||
3. Restores your local nu_* dependency versions
|
||||
@ -978,6 +1009,7 @@ just validate # Validate setup and dependencies
|
||||
### Q: How do I add a new plugin to the repository?
|
||||
|
||||
**A:** Use the template generator:
|
||||
|
||||
```bash
|
||||
just make-plugin nu_plugin_myfeature
|
||||
# or
|
||||
@ -987,6 +1019,7 @@ nu scripts/nu/make_plugin.nu nu_plugin_myfeature
|
||||
### Q: What if upstream tracking fails?
|
||||
|
||||
**A:** Check the plugin status with `just status`. Failed plugins show error details. Common issues:
|
||||
|
||||
- Network connectivity to upstream repository
|
||||
- Authentication for private repositories
|
||||
- Merge conflicts requiring manual resolution
|
||||
@ -994,6 +1027,7 @@ nu scripts/nu/make_plugin.nu nu_plugin_myfeature
|
||||
### Q: How do I update nushell dependency versions?
|
||||
|
||||
**A:** Use the version updater:
|
||||
|
||||
```bash
|
||||
just update-nu-versions # Update all plugins
|
||||
just list-nu-versions # Show current versions
|
||||
@ -1006,6 +1040,7 @@ just list-nu-versions # Show current versions
|
||||
### Q: How do I distribute plugins to other systems?
|
||||
|
||||
**A:** Use the distribution pipeline:
|
||||
|
||||
```bash
|
||||
just build # Build all plugins
|
||||
just collect # Collect binaries
|
||||
@ -1017,6 +1052,7 @@ The resulting archive contains all binaries and installation scripts.
|
||||
### Q: What's the difference between shell scripts and nushell scripts?
|
||||
|
||||
**A:**
|
||||
|
||||
- **Nushell scripts** (`scripts/nu/`): Primary implementation with full features
|
||||
- **Shell scripts** (`scripts/sh/`): Wrappers for compatibility with non-nushell environments
|
||||
- Both provide the same functionality, use whichever fits your environment
|
||||
@ -1024,6 +1060,7 @@ The resulting archive contains all binaries and installation scripts.
|
||||
### Q: How do I contribute a new plugin?
|
||||
|
||||
**A:**
|
||||
|
||||
1. Create the plugin: `just make-plugin nu_plugin_yourname`
|
||||
2. Implement your functionality
|
||||
3. Add upstream URL to `etc/plugin_registry.toml` if it has one
|
||||
@ -1033,12 +1070,14 @@ The resulting archive contains all binaries and installation scripts.
|
||||
### Q: How do I exclude plugins from upstream tracking?
|
||||
|
||||
**A:** Edit `etc/upstream_exclude.toml` to exclude plugins from specific operations:
|
||||
|
||||
- Add to `[exclude]` section to exclude from all operations
|
||||
- Add to `[exclude.check]` to skip automatic checks
|
||||
- Add to `[exclude.merge]` to prevent automatic merging
|
||||
- Use patterns like `nu_plugin_test_*` to exclude multiple plugins
|
||||
|
||||
You can also use Just commands:
|
||||
|
||||
```bash
|
||||
just exclude nu_plugin_test add # Add to exclusion
|
||||
just exclude nu_plugin_test remove # Remove from exclusion
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
851
docs/building.md
851
docs/building.md
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -182,12 +182,6 @@ additional_dirs = [
|
||||
[packaging]
|
||||
# Output directory for packages
|
||||
output_dir = "bin_archives"
|
||||
# Package formats per platform
|
||||
formats = {
|
||||
linux = ["tar.gz"],
|
||||
macos = ["tar.gz"],
|
||||
windows = ["zip"]
|
||||
}
|
||||
# Compression level (0-9)
|
||||
compression_level = 6
|
||||
# Whether to generate checksums
|
||||
@ -195,6 +189,12 @@ generate_checksums = true
|
||||
# Checksum algorithms
|
||||
checksum_algorithms = ["sha256", "sha512"]
|
||||
|
||||
# Package formats per platform
|
||||
[packaging.formats]
|
||||
linux = ["tar.gz"]
|
||||
macos = ["tar.gz"]
|
||||
windows = ["zip"]
|
||||
|
||||
# Manifest settings
|
||||
[packaging.manifest]
|
||||
# Include detailed manifest in packages
|
||||
@ -210,11 +210,6 @@ include_plugin_info = true
|
||||
|
||||
# Installation settings
|
||||
[installation]
|
||||
# Default configuration templates
|
||||
config_templates = {
|
||||
env = "scripts/templates/default_env.nu",
|
||||
config = "scripts/templates/default_config.nu"
|
||||
}
|
||||
# Whether to create config directory
|
||||
create_config_dir = true
|
||||
# Whether to update PATH
|
||||
@ -227,6 +222,11 @@ shell_scripts = [
|
||||
"installers/bootstrap/install.ps1"
|
||||
]
|
||||
|
||||
# Default configuration templates
|
||||
[installation.config_templates]
|
||||
env = "scripts/templates/default_env.nu"
|
||||
config = "scripts/templates/default_config.nu"
|
||||
|
||||
# Verification settings
|
||||
[verification]
|
||||
# Enable installation verification
|
||||
@ -274,11 +274,10 @@ generate_release_notes = true
|
||||
# Pre-release validation
|
||||
validate_before_release = true
|
||||
# Release channels
|
||||
channels = {
|
||||
stable = "main",
|
||||
beta = "develop",
|
||||
nightly = "nightly"
|
||||
}
|
||||
[release.channels]
|
||||
stable = "main"
|
||||
beta = "develop"
|
||||
nightly = "nightly"
|
||||
|
||||
# Documentation settings
|
||||
[documentation]
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
# Nushell Plugin Registry for Provisioning Platform
|
||||
# This file tracks available Nushell plugins with metadata
|
||||
|
||||
[nu_plugin_auth]
|
||||
[plugins.nu_plugin_auth]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_auth"
|
||||
description = "Authentication plugin (JWT, MFA) for provisioning platform"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
@ -14,59 +13,71 @@ commands = [
|
||||
"auth verify",
|
||||
"auth sessions",
|
||||
"auth mfa enroll",
|
||||
"auth mfa verify"
|
||||
"auth mfa verify",
|
||||
]
|
||||
dependencies = [
|
||||
"jsonwebtoken",
|
||||
"reqwest",
|
||||
"keyring",
|
||||
"rpassword",
|
||||
"qrcode"
|
||||
"qrcode",
|
||||
]
|
||||
|
||||
[nu_plugin_kms]
|
||||
[plugins.nu_plugin_kms]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_kms"
|
||||
description = "KMS plugin (RustyVault, Age, Cosmian) for provisioning platform"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
backends = ["rustyvault", "age", "cosmian", "aws", "vault"]
|
||||
backends = [
|
||||
"rustyvault",
|
||||
"age",
|
||||
"cosmian",
|
||||
"aws",
|
||||
"vault",
|
||||
]
|
||||
commands = [
|
||||
"kms encrypt",
|
||||
"kms decrypt",
|
||||
"kms generate-key",
|
||||
"kms status"
|
||||
"kms status",
|
||||
]
|
||||
dependencies = [
|
||||
"reqwest",
|
||||
"age",
|
||||
"base64",
|
||||
"serde"
|
||||
"serde",
|
||||
]
|
||||
|
||||
[nu_plugin_orchestrator]
|
||||
[plugins.nu_plugin_orchestrator]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_orchestrator"
|
||||
description = "Orchestrator operations plugin (status, validate, tasks)"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"orch status",
|
||||
"orch validate",
|
||||
"orch tasks"
|
||||
"orch tasks",
|
||||
]
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"walkdir"
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[nu_plugin_inquire]
|
||||
[plugins.nu_plugin_inquire]
|
||||
upstream_url = "https://github.com/jesusperezlorenzo/nu_plugin_inquire"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_inquire"
|
||||
description = "Interactive forms and prompts plugin using inquire crate - solves TTY buffering issues"
|
||||
version = "0.1.0"
|
||||
category = "utility"
|
||||
@ -79,7 +90,7 @@ commands = [
|
||||
"inquire custom",
|
||||
"inquire editor",
|
||||
"inquire date",
|
||||
"inquire form"
|
||||
"inquire form",
|
||||
]
|
||||
dependencies = [
|
||||
"inquire",
|
||||
@ -87,13 +98,15 @@ dependencies = [
|
||||
"serde_json",
|
||||
"toml",
|
||||
"chrono",
|
||||
"dialoguer"
|
||||
"dialoguer",
|
||||
]
|
||||
|
||||
[forminquire]
|
||||
[plugins.forminquire]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "forminquire"
|
||||
description = "Standalone interactive forms and prompts library + CLI tool - no Nushell dependency required"
|
||||
version = "0.1.0"
|
||||
category = "utility"
|
||||
@ -108,16 +121,20 @@ commands = [
|
||||
"forminquire custom",
|
||||
"forminquire editor",
|
||||
"forminquire date",
|
||||
"forminquire form"
|
||||
"forminquire form",
|
||||
]
|
||||
library_support = true
|
||||
output_formats = ["text", "json", "yaml"]
|
||||
output_formats = [
|
||||
"text",
|
||||
"json",
|
||||
"yaml",
|
||||
]
|
||||
features = [
|
||||
"8 interactive prompt types",
|
||||
"TOML-based form definitions",
|
||||
"Automatic stdin fallback",
|
||||
"Multiple output formats",
|
||||
"Both library and CLI usage"
|
||||
"Both library and CLI usage",
|
||||
]
|
||||
dependencies = [
|
||||
"clap",
|
||||
@ -129,18 +146,343 @@ dependencies = [
|
||||
"chrono",
|
||||
"dialoguer",
|
||||
"anyhow",
|
||||
"thiserror"
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
# Distribution Configuration
|
||||
[distribution]
|
||||
excluded_plugins = [
|
||||
"nu_plugin_example"
|
||||
[plugins.nu_plugin_nickel]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_nickel"
|
||||
description = "Nushell plugin for Nickel configuration language with eval, export, format, and validation"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"nickel-eval",
|
||||
"nickel-export",
|
||||
"nickel-format",
|
||||
"nickel-validate",
|
||||
"nickel-cache-status",
|
||||
]
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"anyhow",
|
||||
"tempfile",
|
||||
"sha2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"dirs",
|
||||
"chrono",
|
||||
]
|
||||
features = [
|
||||
"Config file evaluation with caching",
|
||||
"Export Nickel to JSON/YAML",
|
||||
"Format Nickel files",
|
||||
"Validate Nickel projects",
|
||||
"Cache status management",
|
||||
]
|
||||
|
||||
[plugins.nu_plugin_nats]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_nats"
|
||||
description = "NATS JetStream plugin for provisioning platform event bus"
|
||||
version = "0.110.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"nats stream setup",
|
||||
"nats consumer setup",
|
||||
"nats notify",
|
||||
"nats pub",
|
||||
"nats status",
|
||||
]
|
||||
dependencies = [
|
||||
"async-nats",
|
||||
"tokio",
|
||||
"bytes",
|
||||
"futures",
|
||||
"serde_json",
|
||||
]
|
||||
features = [
|
||||
"Idempotent stream + consumer provisioning",
|
||||
"Pull drain of cli-notifications consumer",
|
||||
"JetStream publish with stream+sequence ack",
|
||||
"Live stream state for all 6 platform streams",
|
||||
"NATS_SERVER env var or nats://127.0.0.1:4222 default",
|
||||
]
|
||||
|
||||
[distribution]
|
||||
excluded_plugins = ["nu_plugin_example"]
|
||||
reason = "Reference/documentation plugin - excluded from distributions, installations, and collections. Still included in build and test for validation."
|
||||
|
||||
# Metadata
|
||||
[settings]
|
||||
nu_managed_dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"nu-plugin-core",
|
||||
"nu-plugin-protocol",
|
||||
"nu-engine",
|
||||
"nu-system",
|
||||
"nu-path",
|
||||
]
|
||||
|
||||
[registry]
|
||||
version = "1.0.0"
|
||||
updated = "2025-10-09"
|
||||
format = "toml"
|
||||
|
||||
["plugins.nu_plugin_auth"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_auth"
|
||||
description = "Authentication plugin (JWT, MFA) for provisioning platform"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"auth login",
|
||||
"auth logout",
|
||||
"auth verify",
|
||||
"auth sessions",
|
||||
"auth mfa enroll",
|
||||
"auth mfa verify",
|
||||
]
|
||||
dependencies = [
|
||||
"jsonwebtoken",
|
||||
"reqwest",
|
||||
"keyring",
|
||||
"rpassword",
|
||||
"qrcode",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_kms"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_kms"
|
||||
description = "KMS plugin (RustyVault, Age, Cosmian) for provisioning platform"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
backends = [
|
||||
"rustyvault",
|
||||
"age",
|
||||
"cosmian",
|
||||
"aws",
|
||||
"vault",
|
||||
]
|
||||
commands = [
|
||||
"kms encrypt",
|
||||
"kms decrypt",
|
||||
"kms generate-key",
|
||||
"kms status",
|
||||
]
|
||||
dependencies = [
|
||||
"reqwest",
|
||||
"age",
|
||||
"base64",
|
||||
"serde",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_orchestrator"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_orchestrator"
|
||||
description = "Orchestrator operations plugin (status, validate, tasks)"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"orch status",
|
||||
"orch validate",
|
||||
"orch tasks",
|
||||
]
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_inquire"]
|
||||
upstream_url = "https://github.com/jesusperezlorenzo/nu_plugin_inquire"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_inquire"
|
||||
description = "Interactive forms and prompts plugin using inquire crate - solves TTY buffering issues"
|
||||
version = "0.1.0"
|
||||
category = "utility"
|
||||
commands = [
|
||||
"inquire text",
|
||||
"inquire confirm",
|
||||
"inquire select",
|
||||
"inquire multi-select",
|
||||
"inquire password",
|
||||
"inquire custom",
|
||||
"inquire editor",
|
||||
"inquire date",
|
||||
"inquire form",
|
||||
]
|
||||
dependencies = [
|
||||
"inquire",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"chrono",
|
||||
"dialoguer",
|
||||
]
|
||||
|
||||
["plugins.forminquire"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "forminquire"
|
||||
description = "Standalone interactive forms and prompts library + CLI tool - no Nushell dependency required"
|
||||
version = "0.1.0"
|
||||
category = "utility"
|
||||
type = "binary"
|
||||
dual_mode = true
|
||||
commands = [
|
||||
"forminquire text",
|
||||
"forminquire confirm",
|
||||
"forminquire select",
|
||||
"forminquire multi-select",
|
||||
"forminquire password",
|
||||
"forminquire custom",
|
||||
"forminquire editor",
|
||||
"forminquire date",
|
||||
"forminquire form",
|
||||
]
|
||||
library_support = true
|
||||
output_formats = [
|
||||
"text",
|
||||
"json",
|
||||
"yaml",
|
||||
]
|
||||
features = [
|
||||
"8 interactive prompt types",
|
||||
"TOML-based form definitions",
|
||||
"Automatic stdin fallback",
|
||||
"Multiple output formats",
|
||||
"Both library and CLI usage",
|
||||
]
|
||||
dependencies = [
|
||||
"clap",
|
||||
"inquire",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"toml",
|
||||
"chrono",
|
||||
"dialoguer",
|
||||
"anyhow",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_nickel"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "error"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_nickel"
|
||||
description = "Nushell plugin for Nickel configuration language with eval, export, format, and validation"
|
||||
version = "0.1.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"nickel-eval",
|
||||
"nickel-export",
|
||||
"nickel-format",
|
||||
"nickel-validate",
|
||||
"nickel-cache-status",
|
||||
]
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"anyhow",
|
||||
"tempfile",
|
||||
"sha2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"dirs",
|
||||
"chrono",
|
||||
]
|
||||
features = [
|
||||
"Config file evaluation with caching",
|
||||
"Export Nickel to JSON/YAML",
|
||||
"Format Nickel files",
|
||||
"Validate Nickel projects",
|
||||
"Cache status management",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_typedialog"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_typedialog"
|
||||
description = "TypeDialog interactive forms and prompts plugin — replaces shlib TTY wrappers"
|
||||
version = "0.110.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"typedialog form",
|
||||
"typedialog nickel-roundtrip",
|
||||
"typedialog text",
|
||||
"typedialog confirm",
|
||||
"typedialog select",
|
||||
"typedialog multi-select",
|
||||
"typedialog password",
|
||||
]
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"typedialog-core",
|
||||
"tokio",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"interprocess",
|
||||
]
|
||||
features = [
|
||||
"CLI and web backends (--backend cli|web)",
|
||||
"Nickel roundtrip with typecheck validation",
|
||||
"Direct prompts: text, confirm, select, multi-select, password",
|
||||
"ESC/cancel returns null (Value::nothing), not error",
|
||||
"Initial values seeding via --initial <record>",
|
||||
]
|
||||
|
||||
["plugins.nu_plugin_mcp"]
|
||||
upstream_url = "local"
|
||||
upstream_branch = "main"
|
||||
status = "ok"
|
||||
auto_merge = false
|
||||
local_path = "nu_plugin_mcp"
|
||||
description = "MCP client plugin — spawn and interact with provisioning-mcp-server via JSON-RPC 2.0"
|
||||
version = "0.110.0"
|
||||
category = "provisioning"
|
||||
commands = [
|
||||
"mcp connect",
|
||||
"mcp tools list",
|
||||
"mcp tool call",
|
||||
"mcp disconnect",
|
||||
]
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"interprocess",
|
||||
]
|
||||
features = [
|
||||
"Spawn MCP server binary as child process",
|
||||
"MCP protocol handshake (initialize + initialized)",
|
||||
"Tool discovery via tools/list",
|
||||
"Tool dispatch with record payload",
|
||||
"Session state persisted in Arc<Mutex<Option<McpSession>>>",
|
||||
"isError responses mapped to {error: true, message: ...} records",
|
||||
]
|
||||
|
||||
289
guides/README.md
289
guides/README.md
File diff suppressed because one or more lines are too long
@ -3,9 +3,11 @@
|
||||
## Fundamental Rules for AI-Friendly Nushell Code
|
||||
|
||||
### Rule 1: One Command, One Purpose
|
||||
|
||||
Every command must do exactly one thing. AI agents struggle with multi-purpose functions.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Single purpose
|
||||
def extract-errors [log_file: path] -> table {
|
||||
open $log_file | lines | parse "{time} [{level}] {msg}" | where level == "ERROR"
|
||||
@ -18,9 +20,11 @@ def process-logs [log_file: path, --extract-errors, --count-warnings, --save-out
|
||||
```
|
||||
|
||||
### Rule 2: Explicit Type Signatures Always
|
||||
|
||||
AI agents need clear contracts. Never omit types.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Complete type information
|
||||
def calculate-average [numbers: list<float>] -> float {
|
||||
$numbers | math avg
|
||||
@ -33,9 +37,11 @@ def calculate-average [numbers] {
|
||||
```
|
||||
|
||||
### Rule 3: Return Early, Fail Fast
|
||||
|
||||
Check preconditions immediately. Don't nest error handling.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Early returns
|
||||
def process-file [path: path] -> table {
|
||||
if not ($path | path exists) {
|
||||
@ -66,9 +72,11 @@ def process-file [path: path] -> table {
|
||||
## Essential Patterns for AI Code Generation
|
||||
|
||||
### Pattern 1: Command Template Pattern
|
||||
|
||||
Use this structure for EVERY command:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# [PURPOSE]: Single-line description of what this does
|
||||
# [INPUT]: Expected input format
|
||||
# [OUTPUT]: Output format
|
||||
@ -90,9 +98,11 @@ def command-name [
|
||||
```
|
||||
|
||||
### Pattern 2: Pipeline Stage Pattern
|
||||
|
||||
Each pipeline stage must be self-contained and testable:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Clear pipeline stages
|
||||
def analyze-data [input: path] -> table {
|
||||
load-data $input
|
||||
@ -111,11 +121,13 @@ def format-output [data: table] -> table { $data | select relevant_columns }
|
||||
```
|
||||
|
||||
### Pattern 3: Error Context Pattern
|
||||
|
||||
Always provide context for errors that AI can use to fix issues:
|
||||
|
||||
in Nushell 0.108, try-catch with error parameter might not be supported when assigning to variables.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Detailed error context
|
||||
def parse-config [config_path: path] -> record {
|
||||
try {
|
||||
@ -134,9 +146,11 @@ def parse-config [config_path: path] -> record {
|
||||
```
|
||||
|
||||
### Pattern 4: Data Validation Pattern
|
||||
|
||||
Validate data structure at boundaries:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Explicit validation
|
||||
def process-user-data [data: table] -> table {
|
||||
# Define expected schema
|
||||
@ -163,9 +177,11 @@ def process-user-data [data: table] -> table {
|
||||
## Critical Rules for AI Tool Integration
|
||||
|
||||
### Rule 4: No Side Effects in Functions
|
||||
|
||||
Functions must be pure unless explicitly named as mutations:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Pure function
|
||||
def calculate-tax [amount: float, rate: float] -> float {
|
||||
$amount * $rate
|
||||
@ -186,9 +202,11 @@ def calculate-tax [amount: float, rate: float] -> float {
|
||||
```
|
||||
|
||||
### Rule 5: Atomic Operations
|
||||
|
||||
Every operation must be atomic - it either completely succeeds or completely fails:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Atomic operation
|
||||
def update-json-file [path: path, updates: record] -> nothing {
|
||||
# Read, modify, write as single operation
|
||||
@ -208,9 +226,11 @@ def update-json-file [path: path, updates: record] -> nothing {
|
||||
```
|
||||
|
||||
### Rule 6: Explicit Dependencies
|
||||
|
||||
Never rely on global state or environment without declaring it:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Explicit dependencies
|
||||
def api-request [
|
||||
endpoint: string
|
||||
@ -232,9 +252,11 @@ def api-request [endpoint: string] -> any {
|
||||
## Structured Data Patterns
|
||||
|
||||
### Pattern 5: Table Transformation Pattern
|
||||
|
||||
Always use Nushell's table operations instead of loops:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Table operations
|
||||
def transform-sales [sales: table] -> table {
|
||||
$sales
|
||||
@ -258,9 +280,11 @@ def transform-sales [sales: table] -> table {
|
||||
```
|
||||
|
||||
### Pattern 6: Schema Definition Pattern
|
||||
|
||||
Define data schemas explicitly for AI understanding:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Schema definitions at module level
|
||||
const USER_SCHEMA = {
|
||||
id: "int"
|
||||
@ -291,9 +315,11 @@ def validate-user [user: record] -> bool {
|
||||
## AI-Specific Patterns
|
||||
|
||||
### Pattern 7: Self-Documenting Code Pattern
|
||||
|
||||
Include inline documentation that AI can parse:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
def complex-calculation [
|
||||
data: table # @format: [{x: float, y: float, weight: float}]
|
||||
] -> record { # @returns: {mean: float, std: float, correlation: float}
|
||||
@ -318,9 +344,11 @@ def complex-calculation [
|
||||
```
|
||||
|
||||
### Pattern 8: Testable Unit Pattern
|
||||
|
||||
Every function must include test examples:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Function with embedded test cases
|
||||
def parse-version [version: string] -> record {
|
||||
# @test: "1.2.3" -> {major: 1, minor: 2, patch: 3}
|
||||
@ -342,9 +370,11 @@ def test-parse-version [] {
|
||||
```
|
||||
|
||||
### Pattern 9: Incremental Computation Pattern
|
||||
|
||||
Break complex computations into verifiable steps:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Each step is verifiable
|
||||
def analyze-dataset [data: path] -> record {
|
||||
# Load and get shape
|
||||
@ -373,9 +403,11 @@ def analyze-dataset [data: path] -> record {
|
||||
## Module Organization Rules
|
||||
|
||||
### Rule 7: Single Responsibility Modules
|
||||
|
||||
Each module handles one domain:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# file: data_validation.nu
|
||||
module data_validation {
|
||||
export def validate-email [email: string] -> bool { }
|
||||
@ -392,9 +424,11 @@ module data_transformation {
|
||||
```
|
||||
|
||||
### Rule 8: Explicit Exports
|
||||
|
||||
Only export what's needed:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
module api_client {
|
||||
# Public API
|
||||
export def get [endpoint: string] -> any {
|
||||
@ -415,9 +449,11 @@ module api_client {
|
||||
## Performance Rules for AI Tools
|
||||
|
||||
### Rule 9: Lazy Evaluation
|
||||
|
||||
Don't compute until necessary:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Lazy evaluation
|
||||
def process-conditionally [
|
||||
data: table
|
||||
@ -436,9 +472,11 @@ def process-conditionally [
|
||||
```
|
||||
|
||||
### Rule 10: Stream Large Data
|
||||
|
||||
Never load entire large files into memory:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Streaming
|
||||
def process-large-file [path: path] -> nothing {
|
||||
open --raw $path
|
||||
@ -460,9 +498,11 @@ def process-large-file [path: path] -> table {
|
||||
## Error Handling Rules
|
||||
|
||||
### Rule 11: Never Swallow Errors
|
||||
|
||||
Always propagate or handle errors explicitly:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Explicit error handling
|
||||
def safe-divide [a: float, b: float] -> float {
|
||||
if $b == 0 {
|
||||
@ -478,9 +518,11 @@ def safe-divide [a: float, b: float] -> float {
|
||||
```
|
||||
|
||||
### Rule 12: Structured Error Returns
|
||||
|
||||
Use consistent error structures:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Define error type
|
||||
const ERROR_SCHEMA = {
|
||||
success: "bool"
|
||||
@ -512,9 +554,11 @@ def api-call [url: string] -> record {
|
||||
## Code Generation Rules for AI
|
||||
|
||||
### Rule 13: Predictable Naming
|
||||
|
||||
Use consistent, predictable names:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Naming conventions AI can predict:
|
||||
# - get-* : Returns data without modification
|
||||
# - set-* : Updates data
|
||||
@ -536,9 +580,11 @@ def parse-json [text: string] -> any { }
|
||||
```
|
||||
|
||||
### Rule 14: Consistent Parameter Order
|
||||
|
||||
Always use this parameter order:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Order: required positional, optional positional, flags
|
||||
def command [
|
||||
required1: type # Required parameters first
|
||||
@ -550,9 +596,11 @@ def command [
|
||||
```
|
||||
|
||||
### Rule 15: Return Type Consistency
|
||||
|
||||
Use consistent return types for similar operations:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# All getters return record or null
|
||||
def get-config [] -> record? {
|
||||
try { open config.json } catch { null }
|
||||
@ -571,9 +619,11 @@ def transform-table [input: table] -> table {
|
||||
```
|
||||
|
||||
### Rule 16: Function Signature Syntax with Pipeline Types (Nushell 0.107.1+)
|
||||
|
||||
**CRITICAL**: When using return type annotations, use the pipeline signature: `[params]: input_type -> return_type`
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Complete pipeline signature
|
||||
def process-data [input: string]: nothing -> table {
|
||||
$input | from json
|
||||
@ -601,9 +651,11 @@ def process-data [input: string] {
|
||||
**Note**: The syntax is `[parameters]: input_type -> return_type`. Both the colon AND arrow are required when specifying return types. This has been the syntax since Nushell 0.107.1.
|
||||
|
||||
### Rule 17: String Interpolation - Always Use Parentheses
|
||||
|
||||
**CRITICAL**: In string interpolations, ALWAYS use parentheses `($var)` or `($expr)` for ALL interpolations.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# ✅ GOOD - Parentheses for variables
|
||||
print $"Processing file ($filename) at ($timestamp)"
|
||||
print $"Server ($hostname) running on port ($port)"
|
||||
@ -624,12 +676,14 @@ print $"Server $hostname on port $port"
|
||||
```
|
||||
|
||||
**Why**:
|
||||
|
||||
- Parentheses `($var)` or `($expr)` are the ONLY way to interpolate in Nushell strings
|
||||
- Square brackets `[...]` are treated as literal characters (no interpolation)
|
||||
- Both variables and expressions use the same syntax: `($something)`
|
||||
- Consistent syntax reduces errors and improves maintainability
|
||||
|
||||
**Rule of thumb**:
|
||||
|
||||
- Variable? Use `($var)`
|
||||
- Expression? Use `($expr)`
|
||||
- Function call? Use `($fn arg)`
|
||||
@ -640,24 +694,31 @@ print $"Server $hostname on port $port"
|
||||
**CRITICAL**: In `$"..."` strings, parentheses that are NOT variable interpolation MUST be escaped.
|
||||
|
||||
❌ **WRONG**:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
let msg = $"Update? (yes/no): " # ERROR: (yes/no) treated as command
|
||||
let text = $"Use format (JSON/YAML)" # ERROR: tries to execute command
|
||||
```
|
||||
|
||||
✅ **CORRECT**:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
let msg = $"Update? \(yes/no\): " # Escaped literal parentheses
|
||||
let text = $"Use format \(JSON/YAML\)" # Escaped literal parentheses
|
||||
let msg = $"Value: ($var)" # Unescaped for variable interpolation
|
||||
```
|
||||
|
||||
**Simple rule**:
|
||||
|
||||
- If `()` contains a variable name → keep as is: `($variable)`
|
||||
- If `()` is literal text → escape with backslash: `\(text\)`
|
||||
|
||||
**Common mistake patterns:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# BAD - will try to execute 'yes/no' command
|
||||
input $"Continue? (yes/no): "
|
||||
|
||||
@ -676,6 +737,7 @@ log_info $"Format \(example\): data"
|
||||
## Quick Reference Card for AI Agents
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# TEMPLATE: Copy-paste this for new commands (Nushell 0.107.1+)
|
||||
# [PURPOSE]:
|
||||
# [INPUT]:
|
||||
@ -716,6 +778,7 @@ def command-name [
|
||||
## Summary Checklist for AI-Compatible Nushell
|
||||
|
||||
✅ **Every function has:**
|
||||
|
||||
- Explicit type signatures with pipeline syntax `[param: type]: input_type -> return_type {`
|
||||
- Single responsibility
|
||||
- Early validation
|
||||
@ -723,6 +786,7 @@ def command-name [
|
||||
- Test examples
|
||||
|
||||
✅ **Never use:**
|
||||
|
||||
- Global state without declaration
|
||||
- Hidden side effects
|
||||
- Nested conditionals (prefer early returns)
|
||||
@ -733,6 +797,7 @@ def command-name [
|
||||
- Function signatures without both colon AND arrow when specifying return types
|
||||
|
||||
✅ **Always prefer:**
|
||||
|
||||
- Pipeline operations over loops
|
||||
- Pure functions over stateful
|
||||
- Explicit over implicit
|
||||
@ -741,6 +806,7 @@ def command-name [
|
||||
- Parentheses `($var)` for ALL string interpolations (variables and expressions)
|
||||
|
||||
✅ **For AI tools specifically:**
|
||||
|
||||
- Use predictable naming patterns
|
||||
- Include operation markers (! for mutations)
|
||||
- Document schemas inline
|
||||
@ -752,37 +818,36 @@ Following these rules and patterns ensures that AI agents like Claude Code can e
|
||||
|
||||
1. Try-Catch Block Pattern (10 files)
|
||||
|
||||
- Issue: Nushell 0.108 has stricter parsing for try-catch blocks
|
||||
- Solution: Replace try {...} catch {...} with complete-based error handling:
|
||||
- Issue: Nushell 0.108 has stricter parsing for try-catch blocks
|
||||
- Solution: Replace try {...} catch {...} with complete-based error handling:
|
||||
let result = (do { ... } | complete)
|
||||
if $result.exit_code == 0 { $result.stdout } else { error_value }
|
||||
- Files fixed:
|
||||
- Files fixed:
|
||||
- workspace/version.nu
|
||||
- workspace/migration.nu (4 blocks)
|
||||
- user/config.nu
|
||||
- config/loader.nu
|
||||
- oci/client.nu (8 blocks - OCI currently disabled)
|
||||
|
||||
2. Function Signature Syntax (2 instances)
|
||||
1. Function Signature Syntax (2 instances)
|
||||
|
||||
- Issue: Missing input type in signatures
|
||||
- Old: def foo [x: string] -> bool
|
||||
- New: def foo [x: string]: nothing -> bool
|
||||
- Files fixed: workspace/helpers.nu
|
||||
- Issue: Missing input type in signatures
|
||||
- Old: def foo [x: string] -> bool
|
||||
- New: def foo [x: string]: nothing -> bool
|
||||
- Files fixed: workspace/helpers.nu
|
||||
|
||||
3. Boolean Flag Syntax (1 instance)
|
||||
1. Boolean Flag Syntax (1 instance)
|
||||
|
||||
- Issue: Type annotations not allowed on boolean flags
|
||||
- Old: --flag: bool = true
|
||||
- New: --flag = true
|
||||
- Files fixed: main_provisioning/contexts.nu
|
||||
- Issue: Type annotations not allowed on boolean flags
|
||||
- Old: --flag: bool = true
|
||||
- New: --flag = true
|
||||
- Files fixed: main_provisioning/contexts.nu
|
||||
|
||||
4. Variable Type Initialization (1 instance)
|
||||
|
||||
- Issue: Can't assign record to null variable in 0.108
|
||||
- Old: mut var = null; $var = {record}
|
||||
- New: mut var = {success: false}; $var = {record}
|
||||
1. Variable Type Initialization (1 instance)
|
||||
|
||||
- Issue: Can't assign record to null variable in 0.108
|
||||
- Old: mut var = null; $var = {record}
|
||||
- New: mut var = {success: false}; $var = {record}
|
||||
|
||||
#" Before (fails in Nushell 0.107.1)
|
||||
try {
|
||||
@ -793,7 +858,8 @@ Following these rules and patterns ensures that AI agents like Claude Code can e
|
||||
default_value
|
||||
}
|
||||
|
||||
# After (works in Nushell 0.107.1)
|
||||
# After (works in Nushell 0.107.1)
|
||||
|
||||
let result = (do {
|
||||
# operations
|
||||
result
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,65 +1,64 @@
|
||||
# Tools Module - Development Tools and Utilities
|
||||
# Commands for development utilities, plugin management, and system tools
|
||||
|
||||
# 🔍 VERSION AND VALIDATION COMMANDS
|
||||
|
||||
# Check nushell version consistency
|
||||
[no-cd]
|
||||
validate-nushell:
|
||||
@echo "🔍 Validating nushell version consistency..."
|
||||
@{{justfile_directory()}}/scripts/run.sh --check-only
|
||||
@{{ justfile_directory() }}/scripts/run.sh --check-only
|
||||
|
||||
# Fix nushell version mismatches
|
||||
[no-cd]
|
||||
fix-nushell:
|
||||
@echo "🔧 Fixing nushell version mismatches..."
|
||||
@{{justfile_directory()}}/scripts/run.sh --fix --check-only
|
||||
@{{ justfile_directory() }}/scripts/run.sh --fix --check-only
|
||||
|
||||
# Update nu dependency versions
|
||||
[no-cd]
|
||||
update-nu-versions:
|
||||
@echo "🔄 Updating nu dependency versions..."
|
||||
@{{justfile_directory()}}/scripts/run.sh update_nu_versions.nu
|
||||
@{{ justfile_directory() }}/scripts/run.sh update_nu_versions.nu
|
||||
|
||||
# List current nu dependency versions
|
||||
[no-cd]
|
||||
list-nu-versions:
|
||||
@echo "📋 Current nu dependency versions:"
|
||||
@{{justfile_directory()}}/scripts/run.sh update_nu_versions.nu list
|
||||
@{{ justfile_directory() }}/scripts/run.sh update_nu_versions.nu list
|
||||
|
||||
# Update nushell submodule
|
||||
[no-cd]
|
||||
update-nushell:
|
||||
@echo "🔄 Updating nushell submodule..."
|
||||
@bash {{justfile_directory()}}/scripts/sh/update_nushell.sh update
|
||||
@bash {{ justfile_directory() }}/scripts/sh/update_nushell.sh update
|
||||
|
||||
# 🆕 PLUGIN MANAGEMENT COMMANDS
|
||||
|
||||
# Create a new plugin from template
|
||||
[no-cd]
|
||||
make-plugin PLUGIN_NAME:
|
||||
@echo "🆕 Creating new plugin: {{PLUGIN_NAME}}"
|
||||
@{{justfile_directory()}}/scripts/run.sh make_plugin.nu {{PLUGIN_NAME}}
|
||||
@echo "🆕 Creating new plugin: {{ PLUGIN_NAME }}"
|
||||
@{{ justfile_directory() }}/scripts/run.sh make_plugin.nu {{ PLUGIN_NAME }}
|
||||
|
||||
# Install specific plugin locally (build + register)
|
||||
[no-cd]
|
||||
install-plugin PLUGIN:
|
||||
@{{justfile_directory()}}/scripts/run.sh install_plugin.nu {{PLUGIN}} --verify
|
||||
@{{ justfile_directory() }}/scripts/run.sh install_plugin.nu {{ PLUGIN }} --verify
|
||||
|
||||
# Register specific plugin with nushell
|
||||
[no-cd]
|
||||
register-plugin PLUGIN:
|
||||
@{{justfile_directory()}}/scripts/run.sh register_plugins.nu register ./{{PLUGIN}}/target/release/{{PLUGIN}} --verify
|
||||
@{{ justfile_directory() }}/scripts/run.sh register_plugins.nu register ./{{ PLUGIN }}/target/release/{{ PLUGIN }} --verify
|
||||
|
||||
# Register all built plugins with nushell
|
||||
[no-cd]
|
||||
register-all-plugins:
|
||||
@{{justfile_directory()}}/scripts/run.sh register_plugins.nu register-all --verify
|
||||
@{{ justfile_directory() }}/scripts/run.sh register_plugins.nu register-all --verify
|
||||
|
||||
# Verify plugin registration status
|
||||
[no-cd]
|
||||
verify-plugins:
|
||||
@{{justfile_directory()}}/scripts/run.sh register_plugins.nu verify
|
||||
@{{ justfile_directory() }}/scripts/run.sh register_plugins.nu verify
|
||||
|
||||
# Install plugins locally from distribution
|
||||
[no-cd]
|
||||
@ -83,7 +82,7 @@ install-local:
|
||||
PLATFORM_DIR=$(find distribution -maxdepth 1 -type d -name "*-*" | head -n1)
|
||||
fi
|
||||
|
||||
if [ -z "$PLATFORM_DIR" ] || [ ! -f "$PLATFORM_DIR/install.nu" ]; then
|
||||
if [ -z "$PLATFORM_DIR" ] || [ ! -f "$PLATFORM_DIR/install.sh" ]; then
|
||||
echo "❌ Installation script not found in distribution"
|
||||
echo "💡 Run 'just collect' to regenerate distribution"
|
||||
exit 1
|
||||
@ -92,7 +91,7 @@ install-local:
|
||||
echo "📦 Installing plugins locally from distribution..."
|
||||
echo "💡 Using register-only mode (no sudo required)"
|
||||
echo "💡 Using distribution: $PLATFORM_DIR"
|
||||
cd "$PLATFORM_DIR" && nu install.nu --verify
|
||||
cd "$PLATFORM_DIR" && bash install.sh --local
|
||||
|
||||
echo ""
|
||||
echo "✅ Local installation completed!"
|
||||
@ -120,7 +119,7 @@ install-system:
|
||||
PLATFORM_DIR=$(find distribution -maxdepth 1 -type d -name "*-*" | head -n1)
|
||||
fi
|
||||
|
||||
if [ -z "$PLATFORM_DIR" ] || [ ! -f "$PLATFORM_DIR/install.nu" ]; then
|
||||
if [ -z "$PLATFORM_DIR" ] || [ ! -f "$PLATFORM_DIR/install.sh" ]; then
|
||||
echo "❌ Installation script not found in distribution"
|
||||
echo "💡 Run 'just collect' to regenerate distribution"
|
||||
exit 1
|
||||
@ -136,6 +135,7 @@ install-system:
|
||||
|
||||
# Copy nushell binary to user location (safer than system)
|
||||
echo " Installing nushell binary to ~/.local/bin..."
|
||||
rm -f ~/.local/bin/nu # Remove old version if it exists
|
||||
cp "$PLATFORM_DIR/nu" ~/.local/bin/nu
|
||||
chmod +x ~/.local/bin/nu
|
||||
|
||||
@ -169,7 +169,7 @@ install-system:
|
||||
|
||||
# Verify installation
|
||||
echo " Verifying installation..."
|
||||
~/.local/bin/nu -c "plugin list" | head -20
|
||||
~/.local/bin/nu -c "plugin list" # | head -20
|
||||
|
||||
# Update PATH suggestion
|
||||
echo ""
|
||||
@ -186,7 +186,7 @@ install-from-archive ARCHIVE="":
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
ARCHIVE="{{ARCHIVE}}"
|
||||
ARCHIVE="{{ ARCHIVE }}"
|
||||
|
||||
# If no archive specified, find the latest one
|
||||
if [ -z "$ARCHIVE" ]; then
|
||||
@ -206,7 +206,7 @@ install-from-archive ARCHIVE="":
|
||||
fi
|
||||
|
||||
echo "📦 Installing from archive: $ARCHIVE"
|
||||
./install.sh --source-path "$ARCHIVE" --install-dir ~/.local --verify
|
||||
./install.sh --source-path "$ARCHIVE" --install-dir ~/.local/bin --verify
|
||||
|
||||
# Install from bin_archives/ (fastest - everything already built)
|
||||
[no-cd]
|
||||
@ -230,7 +230,7 @@ install-fast:
|
||||
echo "📍 Installing to: ~/.local/bin"
|
||||
echo ""
|
||||
|
||||
./install.sh --source-path "$ARCHIVE" --install-dir ~/.local --verify
|
||||
./install.sh --source-path "$ARCHIVE" --install-dir ~/.local/bin --verify
|
||||
|
||||
echo ""
|
||||
echo "✅ Installation complete!"
|
||||
@ -240,18 +240,18 @@ install-fast:
|
||||
# Remove plugin from workspace
|
||||
[no-cd]
|
||||
remove-plugin PLUGIN:
|
||||
@echo "🗑️ Removing plugin {{PLUGIN}}..."
|
||||
@if [ -d "{{PLUGIN}}" ]; then \
|
||||
echo "Are you sure you want to remove {{PLUGIN}}? (y/N)"; \
|
||||
@echo "🗑️ Removing plugin {{ PLUGIN }}..."
|
||||
@if [ -d "{{ PLUGIN }}" ]; then \
|
||||
echo "Are you sure you want to remove {{ PLUGIN }}? (y/N)"; \
|
||||
read -r confirm; \
|
||||
if [ "$$confirm" = "y" ] || [ "$$confirm" = "Y" ]; then \
|
||||
rm -rf "{{PLUGIN}}"; \
|
||||
echo "✅ Removed {{PLUGIN}}"; \
|
||||
rm -rf "{{ PLUGIN }}"; \
|
||||
echo "✅ Removed {{ PLUGIN }}"; \
|
||||
else \
|
||||
echo "❌ Cancelled"; \
|
||||
fi; \
|
||||
else \
|
||||
echo "Plugin {{PLUGIN}} not found"; \
|
||||
echo "Plugin {{ PLUGIN }} not found"; \
|
||||
fi
|
||||
|
||||
# List all plugins
|
||||
@ -267,40 +267,40 @@ list-plugins:
|
||||
# Show plugin information
|
||||
[no-cd]
|
||||
plugin-info PLUGIN:
|
||||
@echo "ℹ️ Plugin Information: {{PLUGIN}}"
|
||||
@if [ -d "{{PLUGIN}}" ]; then \
|
||||
echo "Name: {{PLUGIN}}"; \
|
||||
echo "Path: $(pwd)/{{PLUGIN}}"; \
|
||||
if [ -f "{{PLUGIN}}/Cargo.toml" ]; then \
|
||||
echo "Version: $(grep '^version' {{PLUGIN}}/Cargo.toml | cut -d'"' -f2)"; \
|
||||
echo "Description: $(grep '^description' {{PLUGIN}}/Cargo.toml | cut -d'"' -f2 || echo 'Not available')"; \
|
||||
@echo "ℹ️ Plugin Information: {{ PLUGIN }}"
|
||||
@if [ -d "{{ PLUGIN }}" ]; then \
|
||||
echo "Name: {{ PLUGIN }}"; \
|
||||
echo "Path: $(pwd)/{{ PLUGIN }}"; \
|
||||
if [ -f "{{ PLUGIN }}/Cargo.toml" ]; then \
|
||||
echo "Version: $(grep '^version' {{ PLUGIN }}/Cargo.toml | cut -d'"' -f2)"; \
|
||||
echo "Description: $(grep '^description' {{ PLUGIN }}/Cargo.toml | cut -d'"' -f2 || echo 'Not available')"; \
|
||||
fi; \
|
||||
echo "Binary exists: $([ -f {{PLUGIN}}/target/release/{{PLUGIN}} ] && echo 'Yes' || echo 'No')"; \
|
||||
echo "Last modified: $(stat -c %y {{PLUGIN}} 2>/dev/null || stat -f %m {{PLUGIN}} 2>/dev/null || echo 'Unknown')"; \
|
||||
echo "Binary exists: $([ -f {{ PLUGIN }}/target/release/{{ PLUGIN }} ] && echo 'Yes' || echo 'No')"; \
|
||||
echo "Last modified: $(stat -c %y {{ PLUGIN }} 2>/dev/null || stat -f %m {{ PLUGIN }} 2>/dev/null || echo 'Unknown')"; \
|
||||
else \
|
||||
echo "Plugin {{PLUGIN}} not found"; \
|
||||
echo "Plugin {{ PLUGIN }} not found"; \
|
||||
fi
|
||||
|
||||
# 🛠️ DEVELOPMENT TOOLS
|
||||
|
||||
# Run command on specific plugin
|
||||
plugin PLUGIN CMD:
|
||||
@echo "🔧 Running '{{CMD}}' on {{PLUGIN}}"
|
||||
@cd {{PLUGIN}} && {{CMD}}
|
||||
@echo "🔧 Running '{{ CMD }}' on {{ PLUGIN }}"
|
||||
@cd {{ PLUGIN }} && {{ CMD }}
|
||||
|
||||
# Check specific plugin
|
||||
[no-cd]
|
||||
check-plugin PLUGIN:
|
||||
@echo "🔍 Checking {{PLUGIN}}..."
|
||||
@cd {{PLUGIN}} && cargo check
|
||||
@echo "🔍 Checking {{ PLUGIN }}..."
|
||||
@cd {{ PLUGIN }} && cargo check
|
||||
|
||||
# Watch for changes and rebuild (requires entr)
|
||||
[no-cd]
|
||||
watch PLUGIN:
|
||||
#!/usr/bin/env bash
|
||||
if command -v entr >/dev/null 2>&1; then
|
||||
echo "👀 Watching {{PLUGIN}} for changes..."
|
||||
find {{PLUGIN}}/src -name "*.rs" | entr just build-plugin {{PLUGIN}}
|
||||
echo "👀 Watching {{ PLUGIN }} for changes..."
|
||||
find {{ PLUGIN }}/src -name "*.rs" | entr just build-plugin {{ PLUGIN }}
|
||||
else
|
||||
echo "❌ entr not installed. Install with: brew install entr (macOS) or apt install entr (Ubuntu)"
|
||||
fi
|
||||
@ -420,12 +420,12 @@ clean:
|
||||
# Clean specific plugin
|
||||
[no-cd]
|
||||
clean-plugin PLUGIN:
|
||||
@echo "🧹 Cleaning {{PLUGIN}}..."
|
||||
@if [ -d "{{PLUGIN}}/target" ]; then \
|
||||
echo "Removing {{PLUGIN}}/target..."; \
|
||||
rm -rf "{{PLUGIN}}/target"; \
|
||||
@echo "🧹 Cleaning {{ PLUGIN }}..."
|
||||
@if [ -d "{{ PLUGIN }}/target" ]; then \
|
||||
echo "Removing {{ PLUGIN }}/target..."; \
|
||||
rm -rf "{{ PLUGIN }}/target"; \
|
||||
else \
|
||||
echo "No target directory found for {{PLUGIN}}"; \
|
||||
echo "No target directory found for {{ PLUGIN }}"; \
|
||||
fi
|
||||
|
||||
# Clean distribution files
|
||||
@ -498,8 +498,8 @@ config-list:
|
||||
# Edit configuration file
|
||||
[no-cd]
|
||||
config-edit FILE:
|
||||
@echo "✏️ Editing configuration: {{FILE}}"
|
||||
@${EDITOR:-nano} {{FILE}}
|
||||
@echo "✏️ Editing configuration: {{ FILE }}"
|
||||
@${EDITOR:-nano} {{ FILE }}
|
||||
|
||||
# Backup configuration
|
||||
[no-cd]
|
||||
|
||||
@ -262,6 +262,20 @@ list-versions:
|
||||
@echo "📋 Plugin Version List"
|
||||
@nu {{justfile_directory()}}/scripts/update_all_plugins.nu --list
|
||||
|
||||
# Replace [package] version from old to new (only exact matches)
|
||||
[no-cd]
|
||||
[group('version-update')]
|
||||
replace-package-version FROM TO:
|
||||
@echo "🔄 Replacing [package] version from {{FROM}} to {{TO}}"
|
||||
@nu {{justfile_directory()}}/scripts/update_all_plugins.nu replace-version {{FROM}} {{TO}}
|
||||
|
||||
# Preview [package] version replacement (dry-run)
|
||||
[no-cd]
|
||||
[group('version-update')]
|
||||
preview-package-version FROM TO:
|
||||
@echo "🔍 Preview: Replacing [package] version from {{FROM}} to {{TO}}"
|
||||
@nu {{justfile_directory()}}/scripts/update_all_plugins.nu replace-version {{FROM}} {{TO}} --dry-run
|
||||
|
||||
# 📦 DISTRIBUTION CREATION
|
||||
|
||||
# Create complete distribution packages (nushell + all plugins)
|
||||
@ -480,6 +494,10 @@ update-help:
|
||||
@echo " just dist-status - Show distribution status"
|
||||
@echo " just list-versions - List plugin versions"
|
||||
@echo ""
|
||||
@echo "Package Version Management:"
|
||||
@echo " just replace-package-version 0.109.1 0.110.0 - Replace [package] version"
|
||||
@echo " just preview-package-version 0.109.1 0.110.0 - Preview replacement (dry-run)"
|
||||
@echo ""
|
||||
@echo "Documentation:"
|
||||
@echo " just update-docs - Show documentation paths"
|
||||
@echo " cat guides/COMPLETE_VERSION_UPDATE_GUIDE.md"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nu_plugin_auth"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
authors = ["Jesus Perez <jesus@librecloud.online>"]
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for provisioning authentication (JWT, MFA)"
|
||||
@ -8,8 +8,8 @@ repository = "https://github.com/provisioning/nu_plugin_auth"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
jsonwebtoken = "=9.3"
|
||||
serde_json = "1.0"
|
||||
keyring = "3.6"
|
||||
@ -39,6 +39,5 @@ features = ["full"]
|
||||
version = "5.7"
|
||||
features = ["qr"]
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.1"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = "0.111.0"
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
[package]
|
||||
name = "nu_plugin_auth"
|
||||
version = "0.109.0"
|
||||
authors = ["Jesus Perez <jesus@librecloud.online>"]
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for provisioning authentication (JWT, MFA)"
|
||||
repository = "https://github.com/provisioning/nu_plugin_auth"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
jsonwebtoken = "=9.3"
|
||||
serde_json = "1.0"
|
||||
keyring = "3.6"
|
||||
rpassword = "7.4"
|
||||
base64 = "0.22"
|
||||
qrcode = "0.14"
|
||||
chrono = "0.4"
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
features = [
|
||||
"json",
|
||||
"rustls-tls",
|
||||
"blocking",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.48"
|
||||
features = ["full"]
|
||||
|
||||
[dependencies.totp-rs]
|
||||
version = "5.7"
|
||||
features = ["qr"]
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.0"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
@ -21,12 +21,16 @@ This plugin provides native Nushell commands for authenticating with the provisi
|
||||
Login to provisioning platform with JWT authentication.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth login <username> [password] [--url <control-center-url>] [--save]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Login with password prompt (secure)
|
||||
auth login admin
|
||||
|
||||
@ -45,12 +49,16 @@ auth login admin --save
|
||||
Logout from provisioning platform (revoke tokens).
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth logout [--all]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Logout from current session
|
||||
auth logout
|
||||
|
||||
@ -63,12 +71,16 @@ auth logout --all
|
||||
Verify current authentication token.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth verify [--token <jwt-token>]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Verify stored authentication token
|
||||
auth verify
|
||||
|
||||
@ -81,12 +93,16 @@ auth verify --token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
List active authentication sessions.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth sessions [--active]
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# List all sessions
|
||||
auth sessions
|
||||
|
||||
@ -98,7 +114,8 @@ auth sessions --active
|
||||
|
||||
### Build from source
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
cd provisioning/core/plugins/nushell-plugins/nu_plugin_auth
|
||||
cargo build --release
|
||||
```
|
||||
@ -106,13 +123,15 @@ cargo build --release
|
||||
### Register with Nushell
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
plugin add target/release/nu_plugin_auth
|
||||
plugin use auth
|
||||
```
|
||||
|
||||
### Using justfile (recommended)
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# From nushell-plugins directory
|
||||
just install-plugin nu_plugin_auth
|
||||
|
||||
@ -131,6 +150,7 @@ The plugin uses the following defaults:
|
||||
Override defaults using command flags:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Use custom control center URL
|
||||
auth login admin --url https://control.production.example.com
|
||||
```
|
||||
@ -167,6 +187,7 @@ See control center API documentation for details: `provisioning/platform/control
|
||||
**Version**: 0.1.0 (Initial structure)
|
||||
|
||||
**Implementation Progress**:
|
||||
|
||||
- ✅ Plugin structure created (Agente 1)
|
||||
- ⏳ Login command implementation (Agente 2)
|
||||
- ⏳ Logout command implementation (Agente 3)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -10,6 +10,7 @@
|
||||
## ✅ Completed Components
|
||||
|
||||
### 1. Login Command (`auth login`)
|
||||
|
||||
- [x] Username/password authentication
|
||||
- [x] Secure password prompt (no echo)
|
||||
- [x] HTTP POST to `/auth/login`
|
||||
@ -20,6 +21,7 @@
|
||||
- [x] Error handling (HTTP errors, keyring errors)
|
||||
|
||||
### 2. Logout Command (`auth logout`)
|
||||
|
||||
- [x] Token retrieval from keyring
|
||||
- [x] HTTP POST to `/auth/logout`
|
||||
- [x] Token revocation on server
|
||||
@ -29,6 +31,7 @@
|
||||
- [x] Error handling (no session, HTTP errors)
|
||||
|
||||
### 3. Helper Functions (`src/helpers.rs`)
|
||||
|
||||
- [x] `store_tokens_in_keyring()` - Save JWT tokens securely
|
||||
- [x] `get_access_token()` - Retrieve access token
|
||||
- [x] `get_tokens_from_keyring()` - Retrieve both tokens
|
||||
@ -40,6 +43,7 @@
|
||||
- [x] `list_sessions()` - HTTP sessions API (ready for future use)
|
||||
|
||||
### 4. MFA Support (BONUS)
|
||||
|
||||
- [x] `send_mfa_enroll_request()` - TOTP/WebAuthn enrollment
|
||||
- [x] `send_mfa_verify_request()` - TOTP code verification
|
||||
- [x] `generate_qr_code()` - QR code generation for TOTP
|
||||
@ -48,6 +52,7 @@
|
||||
- [x] `auth mfa verify` command
|
||||
|
||||
### 5. Security Features
|
||||
|
||||
- [x] OS keyring integration (macOS Keychain, Linux libsecret, Windows Credential Manager)
|
||||
- [x] Secure password input (rpassword crate)
|
||||
- [x] HTTPS with rustls-tls
|
||||
@ -56,6 +61,7 @@
|
||||
- [x] Server-side token revocation
|
||||
|
||||
### 6. Documentation
|
||||
|
||||
- [x] `LOGIN_LOGOUT_IMPLEMENTATION.md` - Complete implementation details
|
||||
- [x] `QUICK_REFERENCE.md` - Command reference card
|
||||
- [x] `IMPLEMENTATION_STATUS.md` - This status file
|
||||
@ -67,7 +73,9 @@
|
||||
## 🔧 Build Status
|
||||
|
||||
### Compilation
|
||||
```bash
|
||||
|
||||
```nushell
|
||||
bash
|
||||
$ cargo check
|
||||
Checking nu_plugin_auth v0.1.0
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.89s
|
||||
@ -81,6 +89,7 @@ $ cargo build --release
|
||||
**Warnings**: 6 unused code warnings (for future commands)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- ✅ `reqwest` with `blocking` feature
|
||||
- ✅ `keyring = "3.2"` for OS credential storage
|
||||
- ✅ `rpassword = "7.4"` for secure input
|
||||
@ -93,13 +102,17 @@ $ cargo build --release
|
||||
## 📝 Test Instructions
|
||||
|
||||
### 1. Register Plugin
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
plugin add target/release/nu_plugin_auth
|
||||
plugin use nu_plugin_auth
|
||||
```
|
||||
|
||||
### 2. Test Login
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Interactive password prompt
|
||||
auth login admin
|
||||
|
||||
@ -111,7 +124,9 @@ auth login admin --url http://control.example.com:8081
|
||||
```
|
||||
|
||||
### 3. Test Logout
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Logout current user
|
||||
auth logout
|
||||
|
||||
@ -125,7 +140,9 @@ auth logout --all
|
||||
### 4. Expected Output
|
||||
|
||||
**Login Success:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
user: {
|
||||
@ -140,7 +157,9 @@ auth logout --all
|
||||
```
|
||||
|
||||
**Logout Success:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
message: "Logged out successfully",
|
||||
@ -153,6 +172,7 @@ auth logout --all
|
||||
## 🚀 Integration Points
|
||||
|
||||
### Control Center API
|
||||
|
||||
- **Base URL**: `http://localhost:8081` (default)
|
||||
- **Endpoints**:
|
||||
- `POST /auth/login` - Authentication
|
||||
@ -163,6 +183,7 @@ auth logout --all
|
||||
- `POST /mfa/verify` - MFA verification
|
||||
|
||||
### Security System
|
||||
|
||||
- **JWT Auth**: RS256-signed tokens (15min access, 7d refresh)
|
||||
- **MFA**: TOTP (RFC 6238) + WebAuthn/FIDO2
|
||||
- **Audit**: All auth events logged
|
||||
@ -173,12 +194,14 @@ auth logout --all
|
||||
## ⏭️ Future Work (Not Implemented)
|
||||
|
||||
### Commands to Implement
|
||||
|
||||
- [ ] `auth verify` - Verify current token validity
|
||||
- [ ] `auth sessions` - List all active sessions
|
||||
- [ ] `auth whoami` - Show current user from token
|
||||
- [ ] `auth refresh` - Refresh expired access token
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [ ] Auto-refresh tokens before expiration
|
||||
- [ ] Background token refresh daemon
|
||||
- [ ] Session management (revoke specific session)
|
||||
@ -292,6 +315,7 @@ Beyond the basic requirements:
|
||||
**Status**: ✅ PRODUCTION READY
|
||||
|
||||
**Ready for**:
|
||||
|
||||
- Manual testing with Control Center
|
||||
- Integration testing
|
||||
- User acceptance testing
|
||||
|
||||
@ -20,27 +20,32 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
**Implemented Functions:**
|
||||
|
||||
#### Token Storage (Keyring Integration)
|
||||
|
||||
- `store_tokens_in_keyring()` - Store JWT tokens in OS keyring
|
||||
- `get_access_token()` - Retrieve access token from keyring
|
||||
- `get_tokens_from_keyring()` - Retrieve both tokens from keyring
|
||||
- `remove_tokens_from_keyring()` - Delete tokens from keyring
|
||||
|
||||
#### Password Input
|
||||
|
||||
- `prompt_password()` - Secure password input (no echo)
|
||||
|
||||
#### HTTP API Calls
|
||||
|
||||
- `send_login_request()` - POST `/auth/login` with credentials
|
||||
- `send_logout_request()` - POST `/auth/logout` to revoke token
|
||||
- `verify_token()` - GET `/auth/verify` to check token validity
|
||||
- `list_sessions()` - GET `/auth/sessions` to list active sessions
|
||||
|
||||
#### MFA Support (Bonus)
|
||||
|
||||
- `send_mfa_enroll_request()` - POST `/mfa/enroll/{type}` for TOTP/WebAuthn
|
||||
- `send_mfa_verify_request()` - POST `/mfa/verify` to verify TOTP code
|
||||
- `generate_qr_code()` - Generate QR code for TOTP secret
|
||||
- `display_qr_code()` - Display QR code in terminal with instructions
|
||||
|
||||
**Data Structures:**
|
||||
|
||||
- `LoginRequest` - Login payload
|
||||
- `TokenResponse` - Login response with JWT tokens and user info
|
||||
- `UserInfo` - User details (id, username, email, roles)
|
||||
@ -59,13 +64,16 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
**Implemented Commands:**
|
||||
|
||||
#### `auth login` Command (Lines 92-149)
|
||||
|
||||
**Signature:**
|
||||
|
||||
- Required: `username: String`
|
||||
- Optional: `password: String` (prompts if omitted)
|
||||
- Flag: `--url <string>` (default: `http://localhost:8081`)
|
||||
- Switch: `--save` (save tokens to keyring)
|
||||
|
||||
**Behavior:**
|
||||
|
||||
1. Get username from first argument
|
||||
2. Get password from second argument OR prompt securely
|
||||
3. Send login request to Control Center
|
||||
@ -73,7 +81,9 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
5. Return success response with user info and token metadata
|
||||
|
||||
**Example Output:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
user: {
|
||||
@ -88,12 +98,15 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
```
|
||||
|
||||
#### `auth logout` Command (Lines 193-234)
|
||||
|
||||
**Signature:**
|
||||
|
||||
- Flag: `--user <string>` (default: current system user)
|
||||
- Flag: `--url <string>` (default: `http://localhost:8081`)
|
||||
- Switch: `--all` (logout all sessions)
|
||||
|
||||
**Behavior:**
|
||||
|
||||
1. Get username from flag or environment variable `$USER`
|
||||
2. Retrieve access token from keyring
|
||||
3. Send logout request to Control Center
|
||||
@ -101,7 +114,9 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
5. Return success confirmation
|
||||
|
||||
**Example Output:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
message: "Logged out successfully",
|
||||
@ -114,6 +129,7 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
### 3. `Cargo.toml`
|
||||
|
||||
**Dependencies Added:**
|
||||
|
||||
- `reqwest` with `blocking` feature enabled for synchronous HTTP
|
||||
- `keyring = "3.2"` for OS-level credential storage
|
||||
- `rpassword = "7.4"` for secure password input
|
||||
@ -149,6 +165,7 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
**Base URL**: Configurable via `--url` flag (default: `http://localhost:8081`)
|
||||
|
||||
**Endpoints Used:**
|
||||
|
||||
- `POST /auth/login` - Authenticate and receive JWT tokens
|
||||
- `POST /auth/logout` - Revoke access token
|
||||
- `GET /auth/verify` - Verify token validity
|
||||
@ -157,7 +174,9 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
- `POST /mfa/verify` - Verify MFA code
|
||||
|
||||
**Request Format:**
|
||||
```json
|
||||
|
||||
```nushell
|
||||
json
|
||||
// Login
|
||||
{
|
||||
"username": "admin",
|
||||
@ -171,7 +190,9 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
```
|
||||
|
||||
**Response Format:**
|
||||
```json
|
||||
|
||||
```nushell
|
||||
json
|
||||
// Login success
|
||||
{
|
||||
"access_token": "eyJhbGc...",
|
||||
@ -189,13 +210,16 @@ Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nu
|
||||
### Error Handling
|
||||
|
||||
**Comprehensive error messages:**
|
||||
|
||||
- HTTP request failures with status codes
|
||||
- Keyring errors (access denied, not found)
|
||||
- Password input errors
|
||||
- API response parsing errors
|
||||
|
||||
**Example Error Flow:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# No active session
|
||||
auth logout
|
||||
# Error: No active session: No token found
|
||||
@ -215,7 +239,8 @@ auth login admin --url http://invalid:8081
|
||||
|
||||
✅ **Successful Compilation**
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
$ cargo check
|
||||
Checking nu_plugin_auth v0.1.0
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.89s
|
||||
@ -236,53 +261,70 @@ $ cargo build --release
|
||||
### Manual Testing
|
||||
|
||||
#### 1. Register Plugin
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
plugin add target/release/nu_plugin_auth
|
||||
plugin use nu_plugin_auth
|
||||
```
|
||||
|
||||
#### 2. Test Login (Password Prompt)
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth login admin
|
||||
# Password: ******
|
||||
# Returns user info and token metadata
|
||||
```
|
||||
|
||||
#### 3. Test Login (Password in Command)
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth login admin mypassword --save
|
||||
# Saves tokens to keyring
|
||||
```
|
||||
|
||||
#### 4. Test Login (Custom URL)
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth login admin --url http://control.example.com:8081
|
||||
```
|
||||
|
||||
#### 5. Test Logout
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth logout
|
||||
# Logs out current user
|
||||
```
|
||||
|
||||
#### 6. Test Logout (Specific User)
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth logout --user admin
|
||||
```
|
||||
|
||||
#### 7. Test Logout (All Sessions)
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
auth logout --all
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- Control Center running at `http://localhost:8081`
|
||||
- Valid user account (username + password)
|
||||
|
||||
**Test Workflow:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# 1. Login
|
||||
let login_result = auth login testuser testpass --save
|
||||
|
||||
@ -324,7 +366,9 @@ assert ($logout_result.message == "Logged out successfully")
|
||||
### MFA Support (Bonus Implementation)
|
||||
|
||||
**TOTP Enrollment:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Enroll in TOTP (Google Authenticator, Authy)
|
||||
auth mfa enroll totp --user admin
|
||||
|
||||
@ -333,13 +377,17 @@ auth mfa enroll totp --user admin
|
||||
```
|
||||
|
||||
**TOTP Verification:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Verify 6-digit TOTP code
|
||||
auth mfa verify --code 123456 --user admin
|
||||
```
|
||||
|
||||
**WebAuthn Enrollment:**
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Enroll WebAuthn (YubiKey, Touch ID, Windows Hello)
|
||||
auth mfa enroll webauthn --user admin
|
||||
```
|
||||
@ -349,18 +397,22 @@ auth mfa enroll webauthn --user admin
|
||||
## Future Enhancements (Not Implemented)
|
||||
|
||||
### Token Refresh
|
||||
|
||||
- Auto-refresh expired access tokens using refresh token
|
||||
- Background refresh before expiration
|
||||
|
||||
### Session Management
|
||||
|
||||
- `auth sessions` - List all active sessions
|
||||
- `auth sessions --revoke <id>` - Revoke specific session
|
||||
|
||||
### Token Verification
|
||||
|
||||
- `auth verify` - Check if current token is valid
|
||||
- `auth whoami` - Show current user info from token
|
||||
|
||||
### Certificate Pinning
|
||||
|
||||
- Pin Control Center TLS certificate
|
||||
- Prevent MITM attacks
|
||||
|
||||
@ -369,6 +421,7 @@ auth mfa enroll webauthn --user admin
|
||||
## Dependencies
|
||||
|
||||
### Runtime Dependencies
|
||||
|
||||
- `keyring = "3.2"` - OS credential storage
|
||||
- `rpassword = "7.4"` - Secure password input
|
||||
- `reqwest = "0.12"` - HTTP client (blocking mode)
|
||||
@ -377,10 +430,12 @@ auth mfa enroll webauthn --user admin
|
||||
- `qrcode = "0.14"` - QR code generation
|
||||
|
||||
### Build Dependencies
|
||||
|
||||
- Rust 1.70+ (stable)
|
||||
- Nushell 0.107.1 (via path dependency)
|
||||
|
||||
### Platform Requirements
|
||||
|
||||
- macOS: Keychain access
|
||||
- Linux: libsecret/gnome-keyring
|
||||
- Windows: Credential Manager
|
||||
@ -392,7 +447,9 @@ auth mfa enroll webauthn --user admin
|
||||
### Command Help
|
||||
|
||||
#### Login Command
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
help auth login
|
||||
|
||||
# Usage:
|
||||
@ -417,7 +474,9 @@ help auth login
|
||||
```
|
||||
|
||||
#### Logout Command
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
help auth logout
|
||||
|
||||
# Usage:
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -8,6 +8,7 @@
|
||||
## Installation
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Build plugin
|
||||
cargo build --release -p nu_plugin_auth
|
||||
|
||||
@ -21,7 +22,9 @@ plugin use nu_plugin_auth
|
||||
## Login Command
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Interactive login (password prompt)
|
||||
auth login admin
|
||||
|
||||
@ -36,13 +39,16 @@ auth login admin --url http://control.example.com:8081
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Short | Type | Description | Default |
|
||||
|------|-------|------|-------------|---------|
|
||||
| `--url` | - | String | Control Center URL | `http://localhost:8081` |
|
||||
| `--save` | - | Switch | Save tokens to keyring | `false` |
|
||||
|
||||
### Output
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
user: {
|
||||
@ -61,7 +67,9 @@ auth login admin --url http://control.example.com:8081
|
||||
## Logout Command
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Logout current user
|
||||
auth logout
|
||||
|
||||
@ -73,6 +81,7 @@ auth logout --all
|
||||
```
|
||||
|
||||
### Flags
|
||||
|
||||
| Flag | Short | Type | Description | Default |
|
||||
|------|-------|------|-------------|---------|
|
||||
| `--user` | `-u` | String | Username | Current system user |
|
||||
@ -80,7 +89,9 @@ auth logout --all
|
||||
| `--all` | `-a` | Switch | Logout all sessions | `false` |
|
||||
|
||||
### Output
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
{
|
||||
success: true,
|
||||
message: "Logged out successfully",
|
||||
@ -93,7 +104,9 @@ auth logout --all
|
||||
## MFA Commands (Bonus)
|
||||
|
||||
### TOTP Enrollment
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Enroll in TOTP
|
||||
auth mfa enroll totp
|
||||
|
||||
@ -104,7 +117,9 @@ auth mfa enroll totp --user alice
|
||||
**Output**: QR code in terminal + secret + backup codes
|
||||
|
||||
### TOTP Verification
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Verify TOTP code
|
||||
auth mfa verify --code 123456
|
||||
|
||||
@ -113,7 +128,9 @@ auth mfa verify --code 123456 --user alice
|
||||
```
|
||||
|
||||
### WebAuthn Enrollment
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Enroll WebAuthn (YubiKey, Touch ID)
|
||||
auth mfa enroll webauthn
|
||||
```
|
||||
@ -133,6 +150,7 @@ auth mfa enroll webauthn
|
||||
## Error Handling
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# No active session
|
||||
auth logout
|
||||
# Error: No active session: No token found
|
||||
@ -174,7 +192,9 @@ auth login admin --url http://invalid:8081
|
||||
## Workflow Examples
|
||||
|
||||
### Standard Login/Logout
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Login
|
||||
auth login admin --save
|
||||
|
||||
@ -185,7 +205,9 @@ auth logout
|
||||
```
|
||||
|
||||
### Multiple Users
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Login as different users
|
||||
auth login alice --save
|
||||
auth login bob --save
|
||||
@ -195,7 +217,9 @@ auth logout --user alice
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Non-interactive login
|
||||
let token = auth login $env.CI_USER $env.CI_PASS | get user.id
|
||||
|
||||
@ -210,18 +234,22 @@ auth logout --user $env.CI_USER
|
||||
## Troubleshooting
|
||||
|
||||
### "No token found" error
|
||||
|
||||
**Cause**: No active session or keyring not accessible
|
||||
**Fix**: Login again with `--save` flag
|
||||
|
||||
### "HTTP request failed"
|
||||
|
||||
**Cause**: Control Center not running or wrong URL
|
||||
**Fix**: Check Control Center status and `--url` flag
|
||||
|
||||
### "Login failed: HTTP 401"
|
||||
|
||||
**Cause**: Invalid credentials
|
||||
**Fix**: Verify username and password
|
||||
|
||||
### Keyring access denied
|
||||
|
||||
**Cause**: OS permission issue
|
||||
**Fix**: Grant keychain/keyring access to plugin binary
|
||||
|
||||
@ -230,7 +258,9 @@ auth logout --user $env.CI_USER
|
||||
## Development
|
||||
|
||||
### Build Commands
|
||||
```bash
|
||||
|
||||
```nushell
|
||||
bash
|
||||
# Check code
|
||||
cargo check -p nu_plugin_auth
|
||||
|
||||
@ -245,6 +275,7 @@ cargo test -p nu_plugin_auth
|
||||
```
|
||||
|
||||
### Plugin Location
|
||||
|
||||
- Source: `provisioning/core/plugins/nushell-plugins/nu_plugin_auth/`
|
||||
- Binary: `target/release/nu_plugin_auth`
|
||||
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Build plugin
|
||||
cargo build --release
|
||||
|
||||
@ -15,7 +16,8 @@ plugin use auth
|
||||
|
||||
### TOTP Enrollment
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Enroll with QR code
|
||||
auth mfa enroll totp
|
||||
|
||||
@ -30,7 +32,8 @@ auth mfa enroll totp --url http://control.example.com:8081
|
||||
|
||||
### TOTP Verification
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Verify code
|
||||
auth mfa verify --code 123456
|
||||
|
||||
@ -42,7 +45,8 @@ auth mfa verify --code 123456 --user alice
|
||||
|
||||
## Complete Workflow
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# 1. Login
|
||||
auth login admin --save
|
||||
|
||||
|
||||
@ -93,7 +93,9 @@ impl VerificationResult {
|
||||
pub fn decode_claims_unverified(token: &str) -> Result<Claims, AuthError> {
|
||||
let parts: Vec<&str> = token.split('.').collect();
|
||||
if parts.len() != 3 {
|
||||
return Err(AuthError::invalid_token("Token must have 3 parts separated by '.'"));
|
||||
return Err(AuthError::invalid_token(
|
||||
"Token must have 3 parts separated by '.'",
|
||||
));
|
||||
}
|
||||
|
||||
let payload = parts[1];
|
||||
@ -118,7 +120,10 @@ pub fn decode_claims_unverified(token: &str) -> Result<Claims, AuthError> {
|
||||
///
|
||||
/// Returns a VerificationResult indicating whether the token is valid
|
||||
/// and containing the claims if verification succeeded.
|
||||
pub fn verify_token_rs256(token: &str, public_key_pem: &str) -> Result<VerificationResult, AuthError> {
|
||||
pub fn verify_token_rs256(
|
||||
token: &str,
|
||||
public_key_pem: &str,
|
||||
) -> Result<VerificationResult, AuthError> {
|
||||
// Verify the token header uses RS256
|
||||
let header = decode_header(token)
|
||||
.map_err(|e| AuthError::invalid_token(format!("Failed to decode header: {}", e)))?;
|
||||
|
||||
@ -206,9 +206,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_error_kind_display() {
|
||||
assert_eq!(AuthErrorKind::InvalidCredentials.to_string(), "invalid credentials");
|
||||
assert_eq!(
|
||||
AuthErrorKind::InvalidCredentials.to_string(),
|
||||
"invalid credentials"
|
||||
);
|
||||
assert_eq!(AuthErrorKind::TokenExpired.to_string(), "token expired");
|
||||
assert_eq!(AuthErrorKind::KeyringError.to_string(), "keyring operation failed");
|
||||
assert_eq!(
|
||||
AuthErrorKind::KeyringError.to_string(),
|
||||
"keyring operation failed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -248,7 +248,7 @@ pub fn verify_token(url: &str, token: &str) -> Result<VerifyResponse, AuthError>
|
||||
pub fn list_sessions(
|
||||
url: &str,
|
||||
token: &str,
|
||||
active_only: bool
|
||||
active_only: bool,
|
||||
) -> Result<Vec<SessionInfo>, AuthError> {
|
||||
let client = create_client()?;
|
||||
|
||||
@ -365,8 +365,12 @@ pub fn prompt_password(prompt: &str) -> Result<String, AuthError> {
|
||||
.flush()
|
||||
.map_err(|e| AuthError::new(AuthErrorKind::InternalError, format!("Flush error: {}", e)))?;
|
||||
|
||||
rpassword::read_password()
|
||||
.map_err(|e| AuthError::new(AuthErrorKind::InternalError, format!("Password read error: {}", e)))
|
||||
rpassword::read_password().map_err(|e| {
|
||||
AuthError::new(
|
||||
AuthErrorKind::InternalError,
|
||||
format!("Password read error: {}", e),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -386,8 +390,12 @@ pub fn generate_qr_code(uri: &str) -> Result<String, AuthError> {
|
||||
use qrcode::render::unicode;
|
||||
use qrcode::QrCode;
|
||||
|
||||
let code = QrCode::new(uri)
|
||||
.map_err(|e| AuthError::new(AuthErrorKind::InternalError, format!("QR code generation failed: {}", e)))?;
|
||||
let code = QrCode::new(uri).map_err(|e| {
|
||||
AuthError::new(
|
||||
AuthErrorKind::InternalError,
|
||||
format!("QR code generation failed: {}", e),
|
||||
)
|
||||
})?;
|
||||
|
||||
let qr_string = code
|
||||
.render::<unicode::Dense1x2>()
|
||||
@ -425,10 +433,12 @@ fn extract_secret(uri: &str) -> Result<String, AuthError> {
|
||||
.nth(1)
|
||||
.and_then(|s| s.split('&').next())
|
||||
.map(|s| s.to_string())
|
||||
.ok_or_else(|| AuthError::new(
|
||||
.ok_or_else(|| {
|
||||
AuthError::new(
|
||||
AuthErrorKind::InternalError,
|
||||
"Failed to extract secret from URI",
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -437,6 +447,21 @@ fn extract_secret(uri: &str) -> Result<String, AuthError> {
|
||||
|
||||
use nu_protocol::{record, Span, Value};
|
||||
|
||||
/// Converts a UserInfo to a Nushell Value record.
|
||||
pub fn user_info_to_value(user: &UserInfo, span: Span) -> Value {
|
||||
Value::record(
|
||||
record! {
|
||||
"id" => Value::string(&user.id, span),
|
||||
"username" => Value::string(&user.username, span),
|
||||
"email" => Value::string(&user.email, span),
|
||||
"roles" => Value::list(
|
||||
user.roles.iter().map(|r| Value::string(r, span)).collect(),
|
||||
span,
|
||||
),
|
||||
},
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
/// Converts a SessionInfo to a Nushell Value record.
|
||||
pub fn session_info_to_value(session: &SessionInfo, span: Span) -> Value {
|
||||
|
||||
@ -78,12 +78,12 @@ pub fn get_access_token(username: &str) -> Result<String, AuthError> {
|
||||
let entry = Entry::new(SERVICE_NAME_ACCESS, username)
|
||||
.map_err(|e| AuthError::keyring_error(format!("Failed to access keyring: {}", e)))?;
|
||||
|
||||
entry
|
||||
.get_password()
|
||||
.map_err(|e| AuthError::new(
|
||||
entry.get_password().map_err(|e| {
|
||||
AuthError::new(
|
||||
AuthErrorKind::SessionNotFound,
|
||||
format!("No access token found for user '{}': {}", username, e),
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieves the refresh token from the system keyring.
|
||||
@ -100,12 +100,12 @@ pub fn get_refresh_token(username: &str) -> Result<String, AuthError> {
|
||||
let entry = Entry::new(SERVICE_NAME_REFRESH, username)
|
||||
.map_err(|e| AuthError::keyring_error(format!("Failed to access keyring: {}", e)))?;
|
||||
|
||||
entry
|
||||
.get_password()
|
||||
.map_err(|e| AuthError::new(
|
||||
entry.get_password().map_err(|e| {
|
||||
AuthError::new(
|
||||
AuthErrorKind::SessionNotFound,
|
||||
format!("No refresh token found for user '{}': {}", username, e),
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieves both access and refresh tokens from the system keyring.
|
||||
@ -175,9 +175,9 @@ pub fn get_public_key(key_id: &str) -> Result<String, AuthError> {
|
||||
let entry = Entry::new(SERVICE_NAME_PUBLIC_KEY, key_id)
|
||||
.map_err(|e| AuthError::keyring_error(format!("Failed to access keyring: {}", e)))?;
|
||||
|
||||
entry
|
||||
.get_password()
|
||||
.map_err(|e| AuthError::configuration_error(format!("Public key '{}' not found: {}", key_id, e)))
|
||||
entry.get_password().map_err(|e| {
|
||||
AuthError::configuration_error(format!("Public key '{}' not found: {}", key_id, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if tokens exist for a user.
|
||||
|
||||
@ -128,8 +128,7 @@ impl SimplePluginCommand for Login {
|
||||
let password = if let Some(pwd) = password_arg {
|
||||
pwd
|
||||
} else {
|
||||
helpers::prompt_password("Password: ")
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?
|
||||
helpers::prompt_password("Password: ").map_err(|e| LabeledError::new(e.to_string()))?
|
||||
};
|
||||
|
||||
// Send login request
|
||||
@ -234,16 +233,15 @@ impl SimplePluginCommand for Logout {
|
||||
let username = username_arg.unwrap_or_else(keyring::get_current_username);
|
||||
|
||||
// Get access token
|
||||
let access_token = keyring::get_access_token(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
let access_token =
|
||||
keyring::get_access_token(&username).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
// Send logout request
|
||||
helpers::send_logout_request(&url, &access_token)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
// Remove tokens from keyring
|
||||
keyring::remove_tokens(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
keyring::remove_tokens(&username).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
@ -292,7 +290,11 @@ impl SimplePluginCommand for Verify {
|
||||
"Control Center URL for remote verification",
|
||||
None,
|
||||
)
|
||||
.switch("local", "Verify locally without contacting server", Some('l'))
|
||||
.switch(
|
||||
"local",
|
||||
"Verify locally without contacting server",
|
||||
Some('l'),
|
||||
)
|
||||
.category(Category::Custom("provisioning".into()))
|
||||
}
|
||||
|
||||
@ -337,14 +339,13 @@ impl SimplePluginCommand for Verify {
|
||||
t
|
||||
} else {
|
||||
let username = username_arg.unwrap_or_else(keyring::get_current_username);
|
||||
keyring::get_access_token(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?
|
||||
keyring::get_access_token(&username).map_err(|e| LabeledError::new(e.to_string()))?
|
||||
};
|
||||
|
||||
if local_only {
|
||||
// Local verification (no network)
|
||||
let result = auth::verify_token_local(&token)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
let result =
|
||||
auth::verify_token_local(&token).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
Ok(Value::record(
|
||||
record! {
|
||||
@ -448,8 +449,8 @@ impl SimplePluginCommand for Sessions {
|
||||
|
||||
// Get username and access token
|
||||
let username = username_arg.unwrap_or_else(keyring::get_current_username);
|
||||
let access_token = keyring::get_access_token(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
let access_token =
|
||||
keyring::get_access_token(&username).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
// List sessions from server
|
||||
let sessions = helpers::list_sessions(&url, &access_token, active_only)
|
||||
@ -536,8 +537,8 @@ impl SimplePluginCommand for MfaEnroll {
|
||||
}
|
||||
|
||||
// Get access token
|
||||
let access_token = keyring::get_access_token(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
let access_token =
|
||||
keyring::get_access_token(&username).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
// Send enrollment request
|
||||
let response = helpers::send_mfa_enroll_request(&url, &access_token, &mfa_type)
|
||||
@ -622,9 +623,7 @@ impl SimplePluginCommand for MfaVerify {
|
||||
|
||||
// Validate code format
|
||||
if code.len() != 6 || !code.chars().all(|c| c.is_ascii_digit()) {
|
||||
return Err(LabeledError::new(
|
||||
"Code must be a 6-digit number",
|
||||
));
|
||||
return Err(LabeledError::new("Code must be a 6-digit number"));
|
||||
}
|
||||
|
||||
let username = call
|
||||
@ -635,8 +634,8 @@ impl SimplePluginCommand for MfaVerify {
|
||||
.unwrap_or_else(|| DEFAULT_CONTROL_CENTER_URL.to_string());
|
||||
|
||||
// Get access token
|
||||
let access_token = keyring::get_access_token(&username)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
let access_token =
|
||||
keyring::get_access_token(&username).map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
// Verify code
|
||||
let valid = helpers::send_mfa_verify_request(&url, &access_token, &code)
|
||||
|
||||
@ -117,10 +117,19 @@ fn test_auth_error_kind_display() {
|
||||
"invalid credentials"
|
||||
);
|
||||
assert_eq!(AuthErrorKind::TokenExpired.to_string(), "token expired");
|
||||
assert_eq!(AuthErrorKind::InvalidToken.to_string(), "invalid token format");
|
||||
assert_eq!(AuthErrorKind::KeyringError.to_string(), "keyring operation failed");
|
||||
assert_eq!(
|
||||
AuthErrorKind::InvalidToken.to_string(),
|
||||
"invalid token format"
|
||||
);
|
||||
assert_eq!(
|
||||
AuthErrorKind::KeyringError.to_string(),
|
||||
"keyring operation failed"
|
||||
);
|
||||
assert_eq!(AuthErrorKind::NetworkError.to_string(), "network error");
|
||||
assert_eq!(AuthErrorKind::MfaFailed.to_string(), "MFA verification failed");
|
||||
assert_eq!(
|
||||
AuthErrorKind::MfaFailed.to_string(),
|
||||
"MFA verification failed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
File diff suppressed because one or more lines are too long
564
nu_plugin_clipboard/Cargo.lock
generated
564
nu_plugin_clipboard/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -10,14 +10,14 @@ keywords = [
|
||||
homepage = "https://github.com/FMotalleb/nu_plugin_clipboard"
|
||||
repository = "https://github.com/FMotalleb/nu_plugin_clipboard"
|
||||
description = "A nushell plugin to copy text into clipboard or get text from it."
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
edition = "2024"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-json = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
nu-json = "0.111.0"
|
||||
|
||||
[dependencies.arboard]
|
||||
version = "3.6.1"
|
||||
|
||||
@ -25,13 +25,15 @@ Try disabling the daemon mode, as mentioned in [#20](https://github.com/FMotalle
|
||||
|
||||
### Copying a string (supports only strings for now)
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
echo "test value" | clipboard copy
|
||||
```
|
||||
|
||||
### Using clipboard content
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
clipboard paste | echo $in
|
||||
```
|
||||
|
||||
@ -41,7 +43,8 @@ clipboard paste | echo $in
|
||||
- When pasting, `clipboard paste` tries to parse JSON into a table or object.
|
||||
- If parsing fails, the content is returned as a string.
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
$env | clipboard copy
|
||||
clipboard paste
|
||||
|
||||
@ -55,7 +58,8 @@ clipboard paste
|
||||
|
||||
This method automatically handles dependencies and features:
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_clipboard.git
|
||||
nupm install --path nu_plugin_clipboard -f
|
||||
```
|
||||
@ -71,7 +75,8 @@ nupm install --path nu_plugin_clipboard -f
|
||||
|
||||
### 🛠️ Manual Compilation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_clipboard.git
|
||||
cd nu_plugin_clipboard
|
||||
cargo build -r
|
||||
@ -80,7 +85,8 @@ plugin add target/release/nu_plugin_clipboard
|
||||
|
||||
### 📦 Install via Cargo (using git)
|
||||
|
||||
```bash
|
||||
```rust
|
||||
bash
|
||||
cargo install --git https://github.com/FMotalleb/nu_plugin_clipboard.git
|
||||
plugin add ~/.cargo/bin/nu_plugin_clipboard
|
||||
```
|
||||
@ -89,7 +95,8 @@ plugin add ~/.cargo/bin/nu_plugin_clipboard
|
||||
|
||||
- Since I live in Iran and crates.io won't let me update my packages like a normal person, most of the time crates.io is outdated.
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
cargo install nu_plugin_clipboard
|
||||
plugin add ~/.cargo/bin/nu_plugin_clipboard
|
||||
```
|
||||
@ -1,3 +1,3 @@
|
||||
pub(crate) fn map_arboard_err_to_label(err: arboard::Error) -> nu_protocol::LabeledError {
|
||||
nu_protocol::LabeledError::new(format!("Clipboard Error: {}", err.to_string()))
|
||||
nu_protocol::LabeledError::new(format!("Clipboard Error: {}", err))
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
env,
|
||||
io::{stderr, stdout, Read, Write},
|
||||
io::{Read, Write, stderr, stdout},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::clipboard::clipboard::Clipboard;
|
||||
use crate::ClipboardPlugins;
|
||||
use crate::clipboard::clipboard::Clipboard;
|
||||
use crate::{clipboard::clipboard::create_clipboard, utils::json};
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||
use nu_protocol::{Category, IntoPipelineData, LabeledError, PipelineData, Signature, Type, Value};
|
||||
@ -12,7 +12,7 @@ impl ClipboardCopy {
|
||||
}
|
||||
fn format_json(input: &Value) -> Result<String, LabeledError> {
|
||||
let json_value =
|
||||
json::value_to_json_value(&input).map(|v| nu_json::to_string_with_indent(&v, 4));
|
||||
json::value_to_json_value(input).map(|v| nu_json::to_string_with_indent(&v, 4));
|
||||
|
||||
match json_value {
|
||||
Ok(Ok(text)) => Ok(text.to_owned()), // Return the owned String
|
||||
@ -62,9 +62,7 @@ impl PluginCommand for ClipboardCopy {
|
||||
let value = input.into_value(call.head);
|
||||
match value {
|
||||
Ok(value) => {
|
||||
if let Err(err) = Self::copy(engine, &value) {
|
||||
return Err(err);
|
||||
}
|
||||
Self::copy(engine, &value)?;
|
||||
Ok(value.into_pipeline_data())
|
||||
}
|
||||
Err(err) => Err(LabeledError::new(err.to_string())),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
clipboard::clipboard::{create_clipboard, Clipboard},
|
||||
utils::json::json_to_value,
|
||||
ClipboardPlugins,
|
||||
clipboard::clipboard::{Clipboard, create_clipboard},
|
||||
utils::json::json_to_value,
|
||||
};
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||
use nu_protocol::{Category, IntoPipelineData, LabeledError, PipelineData, Type, Value};
|
||||
|
||||
@ -4,13 +4,13 @@ pub mod utils;
|
||||
use std::io;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{
|
||||
io::{stderr, stdout, Write},
|
||||
io::{Write, stderr, stdout},
|
||||
process::exit,
|
||||
};
|
||||
|
||||
use crate::command::copy::ClipboardCopy;
|
||||
use crate::command::paste::ClipboardPaste;
|
||||
use clipboard::clipboard::{create_clipboard, CheckResult, Clipboard};
|
||||
use clipboard::clipboard::{CheckResult, Clipboard, create_clipboard};
|
||||
use nu_plugin::PluginCommand;
|
||||
|
||||
pub struct ClipboardPlugins;
|
||||
@ -30,10 +30,13 @@ impl nu_plugin::Plugin for ClipboardPlugins {
|
||||
|
||||
fn main() -> Result<(), io::Error> {
|
||||
match create_clipboard(None).pre_execute_check() {
|
||||
CheckResult::Continue => Ok(nu_plugin::serve_plugin(
|
||||
&mut ClipboardPlugins {},
|
||||
CheckResult::Continue => {
|
||||
nu_plugin::serve_plugin(
|
||||
&ClipboardPlugins {},
|
||||
nu_plugin::MsgPackSerializer {},
|
||||
)),
|
||||
);
|
||||
Ok(())
|
||||
},
|
||||
#[cfg(target_os = "linux")]
|
||||
CheckResult::Exit(message, code) => {
|
||||
if code != 0 {
|
||||
|
||||
514
nu_plugin_desktop_notifications/Cargo.lock
generated
514
nu_plugin_desktop_notifications/Cargo.lock
generated
@ -38,12 +38,6 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@ -53,6 +47,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@ -227,7 +271,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"shlex",
|
||||
"syn",
|
||||
]
|
||||
@ -370,16 +414,15 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.39"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"pure-rust-locales",
|
||||
"serde",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -402,6 +445,40 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
@ -540,6 +617,17 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doctest-file"
|
||||
version = "1.0.0"
|
||||
@ -637,9 +725,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.16.2"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
|
||||
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex-automata",
|
||||
@ -663,10 +751,55 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.4"
|
||||
name = "fluent"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||
checksum = "8137a6d5a2c50d6b0ebfcb9aaa91a28154e0a70605f112d30cb0cd4a78670477"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-bundle"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4"
|
||||
dependencies = [
|
||||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rustc-hash 2.1.1",
|
||||
"self_cell",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-langneg"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-syntax"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
@ -724,9 +857,9 @@ checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
@ -776,9 +909,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.4"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@ -786,9 +919,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "interprocess"
|
||||
version = "2.2.2"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb"
|
||||
checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
|
||||
dependencies = [
|
||||
"doctest-file",
|
||||
"libc",
|
||||
@ -797,6 +930,25 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl-memoizer"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
|
||||
dependencies = [
|
||||
"type-map",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl_pluralrules"
|
||||
version = "7.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.3.19"
|
||||
@ -812,6 +964,12 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@ -860,9 +1018,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -931,9 +1089,9 @@ checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
@ -963,12 +1121,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
@ -981,9 +1136,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@ -1008,7 +1163,7 @@ dependencies = [
|
||||
"supports-unicode",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1118,9 +1273,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-derive-value"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465d2d3ada6004cb6689f269a08c70ba81056231e2b5392d1e0ccf5825f81cb"
|
||||
checksum = "d71958b54c367bda033f7dcc4a73b61972fb52323f71a1e3533e290fa67148d1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error2",
|
||||
@ -1131,9 +1286,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b777faf7c5180fe5d7f67d83c44fd14138d91f2938a36494ed6ac66b7160f3"
|
||||
checksum = "d41b3e3e2d25c30741a0761856258e22624c0d60064e4f0e12f86202a451d492"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"log",
|
||||
@ -1146,25 +1301,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-experimental"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73dd212a1afdad646a38c00579a0988264880aeb97fee820b349a28cdcc04df2"
|
||||
checksum = "f328fa0531bdf49c2dc0312b40cb780e3d74e0d3dbb15d508469a5ae4cfd8d8f"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15aa2c17078926f14e393b4b708e69f228cb6fd4c81136839bde82772bdde1b5"
|
||||
checksum = "01ee787f61353c9c90581ddf4c0602a07b991cdd06c97dac8b6d323a1a52c43a"
|
||||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde9d8ba26f62c07176c0237a36f38ce964ab3a0dcfb6aab1feea7515d1c6594"
|
||||
checksum = "c01d110cb931acf56237ce572e5b156e8e1134227c90deeffb92eedda9482c23"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"omnipath",
|
||||
@ -1174,9 +1329,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea1fbfd41b2f5c967675fc948831e03be67d91c6b8e18a60f3445113fe6548c"
|
||||
checksum = "c322531b1a7d6338c5ead1f454294f46babf8c99cd4716311cab1e88ba52b154"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix 0.30.1",
|
||||
@ -1185,14 +1340,14 @@ dependencies = [
|
||||
"nu-plugin-protocol",
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd2410648c2c38cf9359595ffcf281d9d60a81c0580ff07f7c7d42bed414f3a1"
|
||||
checksum = "38ee792aeb0d37e0ed55ca4304e434eece497914e27ae42616a8bb973f5d2720"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
@ -1206,9 +1361,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27de26da922261dff8103a811879228c55749a1b7b0e573b639c609a0651a01e"
|
||||
checksum = "7725f341428db16dbef4392970de32705abc77ee80a902572c8da811dade3564"
|
||||
dependencies = [
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
@ -1220,9 +1375,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038943300ca9de0924fef1c795a7dd16ffc67105629477cf163e8ee6bad95ea6"
|
||||
checksum = "f1c0e58cbeb46cbfd40156e6f4b9f90e4a77e774ca863fa158867a4726aab1d1"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"bytes",
|
||||
@ -1251,7 +1406,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"typetag",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
@ -1260,9 +1415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46be734cc9b19e09a9665769e14360e13e6978490056ba5c8bfad7dd0537ea83"
|
||||
checksum = "62fe7847b65edbe362a0fcb67dedfab9fd7370e89c0313f7cb7d0a7ab8f9834b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.14.0",
|
||||
@ -1274,15 +1429,16 @@ dependencies = [
|
||||
"ntapi",
|
||||
"procfs",
|
||||
"sysinfo",
|
||||
"uucore",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f8eb43c29cc5bce85f87defdadc2cca964fa434d808af37036a7cb78f3c68e9"
|
||||
checksum = "df85a8a4bb28c84d5f7c096c02c859ac454dfac59fd0296ab5eb6ed86619219e"
|
||||
dependencies = [
|
||||
"byteyarn",
|
||||
"crossterm",
|
||||
@ -1303,7 +1459,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_desktop_notifications"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
dependencies = [
|
||||
"notify-rust",
|
||||
"nu-plugin",
|
||||
@ -1357,18 +1513,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
@ -1395,6 +1551,12 @@ version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@ -1411,6 +1573,15 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_display"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad5fd71b79026fb918650dde6d125000a233764f1c2f1659a1c71118e33ea08f"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.1"
|
||||
@ -1542,23 +1713,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "procfs"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
|
||||
checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"hex",
|
||||
"procfs-core",
|
||||
"rustix 0.38.44",
|
||||
"rustix 1.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procfs-core"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
|
||||
checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
@ -1567,9 +1737,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
|
||||
checksum = "869675ad2d7541aea90c6d88c81f46a7f4ea9af8cd0395d38f11a95126998a0d"
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
@ -1633,23 +1803,23 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.23"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931"
|
||||
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.23"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
|
||||
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1698,11 +1868,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db"
|
||||
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
@ -1713,6 +1882,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
@ -1757,6 +1932,12 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.25"
|
||||
@ -1765,18 +1946,28 @@ checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1785,14 +1976,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.138"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1873,10 +2065,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
@ -1933,16 +2131,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.37.2"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows 0.61.1",
|
||||
"windows 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1952,7 +2150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
|
||||
dependencies = [
|
||||
"quick-xml",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"windows 0.61.1",
|
||||
"windows-version",
|
||||
]
|
||||
@ -1988,7 +2186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
|
||||
dependencies = [
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2002,11 +2200,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2022,9 +2220,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2050,6 +2248,17 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"serde_core",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
@ -2098,6 +2307,15 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.2"
|
||||
@ -2140,10 +2358,28 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
name = "unic-langid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
|
||||
dependencies = [
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-impl"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
|
||||
dependencies = [
|
||||
"tinystr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -2169,6 +2405,47 @@ version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uucore"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b157ba598d7f7ed06f6dbc62999edb9d730b4d3fb58e503d8ad6d5fbe1e04391"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"libc",
|
||||
"nix 0.30.1",
|
||||
"os_display",
|
||||
"thiserror 2.0.18",
|
||||
"unic-langid",
|
||||
"uucore_procs",
|
||||
"wild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uucore_procs"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa291a52608ac5a2f8539e119666e021baa6b8c01f22f02ed201bbae54cbbc0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.14.1"
|
||||
@ -2267,6 +2544,15 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1"
|
||||
dependencies = [
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -2763,6 +3049,28 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.4.0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
|
||||
[dependencies.notify-rust]
|
||||
version = "4.11.7"
|
||||
@ -20,4 +20,4 @@ license = "MIT"
|
||||
name = "nu_plugin_desktop_notifications"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/FMotalleb/nu_plugin_desktop_notifications"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
|
||||
@ -17,7 +17,8 @@ A [Nushell](https://www.nushell.sh/) plugin for sending desktop notifications us
|
||||
|
||||
### **Sending a Notification**
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
notify -t "Test notification body" --summary "Test title"
|
||||
```
|
||||
|
||||
@ -40,7 +41,8 @@ Send a notification after a task completes, displaying the elapsed time:
|
||||
|
||||

|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
def "notify on done" [
|
||||
task: closure
|
||||
] {
|
||||
@ -62,14 +64,16 @@ notify on done { port scan 8.8.8.8 53 }
|
||||
|
||||
### 🚀 Recommended: Using [nupm](https://github.com/nushell/nupm)
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_desktop_notifications.git
|
||||
nupm install --path nu_plugin_desktop_notifications -f
|
||||
```
|
||||
|
||||
### 🛠️ Manual Compilation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_desktop_notifications.git
|
||||
cd nu_plugin_desktop_notifications
|
||||
cargo build -r
|
||||
@ -78,7 +82,8 @@ register target/release/nu_plugin_desktop_notifications
|
||||
|
||||
### 📦 Install via Cargo (using git)
|
||||
|
||||
```bash
|
||||
```rust
|
||||
bash
|
||||
cargo install --git https://github.com/FMotalleb/nu_plugin_desktop_notifications.git
|
||||
register ~/.cargo/bin/nu_plugin_desktop_notifications
|
||||
```
|
||||
@ -87,7 +92,8 @@ register ~/.cargo/bin/nu_plugin_desktop_notifications
|
||||
>
|
||||
> _Since I live in Iran and crates.io often restricts package updates, the version there might be outdated._
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
cargo install nu_plugin_desktop_notifications
|
||||
register ~/.cargo/bin/nu_plugin_desktop_notifications
|
||||
```
|
||||
@ -1,4 +1,4 @@
|
||||
use nu_plugin::{serve_plugin, Plugin};
|
||||
use nu_plugin::{Plugin, serve_plugin};
|
||||
|
||||
use crate::notify::NotifyCommand;
|
||||
mod notify;
|
||||
@ -15,5 +15,5 @@ impl Plugin for NotifyPlugin {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut NotifyPlugin {}, nu_plugin::MsgPackSerializer {})
|
||||
serve_plugin(&NotifyPlugin {}, nu_plugin::MsgPackSerializer {})
|
||||
}
|
||||
|
||||
@ -107,15 +107,12 @@ impl SimplePluginCommand for NotifyCommand {
|
||||
}
|
||||
|
||||
if let Some(duration_value) = call.get_flag_value("timeout") {
|
||||
match duration_value.as_duration() {
|
||||
Ok(timeout) => {
|
||||
if let Ok(timeout) = duration_value.as_duration() {
|
||||
if let Ok(nanos) = timeout.try_into() {
|
||||
let duration = Timeout::from(Duration::from_nanos(nanos));
|
||||
notification.timeout(duration);
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
match notification.show() {
|
||||
|
||||
491
nu_plugin_fluent/Cargo.lock
generated
491
nu_plugin_fluent/Cargo.lock
generated
@ -47,6 +47,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
@ -197,9 +247,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
@ -228,6 +278,40 @@ dependencies = [
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.7.1"
|
||||
@ -264,7 +348,7 @@ dependencies = [
|
||||
"document-features",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix 1.1.2",
|
||||
"rustix",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
@ -382,9 +466,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.16.2"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
|
||||
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex-automata",
|
||||
@ -455,14 +539,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
@ -495,21 +579,15 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -534,7 +612,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.62.2",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -548,19 +626,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.12.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.0",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interprocess"
|
||||
version = "2.2.3"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d"
|
||||
checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
|
||||
dependencies = [
|
||||
"doctest-file",
|
||||
"libc",
|
||||
@ -603,6 +681,12 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
@ -651,9 +735,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
@ -686,12 +770,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.11.0"
|
||||
@ -722,11 +800,11 @@ checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -741,18 +819,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "miette"
|
||||
@ -851,9 +926,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-derive-value"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465d2d3ada6004cb6689f269a08c70ba81056231e2b5392d1e0ccf5825f81cb"
|
||||
checksum = "d71958b54c367bda033f7dcc4a73b61972fb52323f71a1e3533e290fa67148d1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error2",
|
||||
@ -864,9 +939,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b777faf7c5180fe5d7f67d83c44fd14138d91f2938a36494ed6ac66b7160f3"
|
||||
checksum = "d41b3e3e2d25c30741a0761856258e22624c0d60064e4f0e12f86202a451d492"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"log",
|
||||
@ -879,25 +954,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-experimental"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73dd212a1afdad646a38c00579a0988264880aeb97fee820b349a28cdcc04df2"
|
||||
checksum = "f328fa0531bdf49c2dc0312b40cb780e3d74e0d3dbb15d508469a5ae4cfd8d8f"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15aa2c17078926f14e393b4b708e69f228cb6fd4c81136839bde82772bdde1b5"
|
||||
checksum = "01ee787f61353c9c90581ddf4c0602a07b991cdd06c97dac8b6d323a1a52c43a"
|
||||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde9d8ba26f62c07176c0237a36f38ce964ab3a0dcfb6aab1feea7515d1c6594"
|
||||
checksum = "c01d110cb931acf56237ce572e5b156e8e1134227c90deeffb92eedda9482c23"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"omnipath",
|
||||
@ -907,9 +982,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea1fbfd41b2f5c967675fc948831e03be67d91c6b8e18a60f3445113fe6548c"
|
||||
checksum = "c322531b1a7d6338c5ead1f454294f46babf8c99cd4716311cab1e88ba52b154"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
@ -918,14 +993,14 @@ dependencies = [
|
||||
"nu-plugin-protocol",
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd2410648c2c38cf9359595ffcf281d9d60a81c0580ff07f7c7d42bed414f3a1"
|
||||
checksum = "38ee792aeb0d37e0ed55ca4304e434eece497914e27ae42616a8bb973f5d2720"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
@ -934,14 +1009,14 @@ dependencies = [
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27de26da922261dff8103a811879228c55749a1b7b0e573b639c609a0651a01e"
|
||||
checksum = "7725f341428db16dbef4392970de32705abc77ee80a902572c8da811dade3564"
|
||||
dependencies = [
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
@ -953,9 +1028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038943300ca9de0924fef1c795a7dd16ffc67105629477cf163e8ee6bad95ea6"
|
||||
checksum = "f1c0e58cbeb46cbfd40156e6f4b9f90e4a77e774ca863fa158867a4726aab1d1"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"bytes",
|
||||
@ -984,18 +1059,18 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
"typetag",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46be734cc9b19e09a9665769e14360e13e6978490056ba5c8bfad7dd0537ea83"
|
||||
checksum = "62fe7847b65edbe362a0fcb67dedfab9fd7370e89c0313f7cb7d0a7ab8f9834b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.14.0",
|
||||
@ -1007,15 +1082,16 @@ dependencies = [
|
||||
"ntapi",
|
||||
"procfs",
|
||||
"sysinfo",
|
||||
"uucore",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f8eb43c29cc5bce85f87defdadc2cca964fa434d808af37036a7cb78f3c68e9"
|
||||
checksum = "df85a8a4bb28c84d5f7c096c02c859ac454dfac59fd0296ab5eb6ed86619219e"
|
||||
dependencies = [
|
||||
"byteyarn",
|
||||
"crossterm",
|
||||
@ -1036,7 +1112,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_fluent"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
dependencies = [
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
@ -1047,7 +1123,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
@ -1072,18 +1148,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
@ -1101,12 +1177,27 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_display"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad5fd71b79026fb918650dde6d125000a233764f1c2f1659a1c71118e33ea08f"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.2"
|
||||
@ -1185,23 +1276,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "procfs"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
|
||||
checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"hex",
|
||||
"procfs-core",
|
||||
"rustix 0.38.44",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procfs-core"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
|
||||
checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
@ -1210,9 +1300,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
|
||||
checksum = "869675ad2d7541aea90c6d88c81f46a7f4ea9af8cd0395d38f11a95126998a0d"
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
@ -1262,23 +1352,23 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
|
||||
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
|
||||
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1327,11 +1417,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db"
|
||||
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
@ -1348,19 +1437,6 @@ version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.1.2"
|
||||
@ -1370,7 +1446,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
@ -1406,9 +1482,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@ -1416,18 +1492,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.225"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1436,15 +1512,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.145"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1499,10 +1575,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
@ -1559,16 +1641,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.37.2"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1580,7 +1662,7 @@ dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.2",
|
||||
"rustix",
|
||||
"windows-sys 0.61.0",
|
||||
]
|
||||
|
||||
@ -1590,7 +1672,7 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
|
||||
dependencies = [
|
||||
"rustix 1.1.2",
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
@ -1615,11 +1697,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.16",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1635,9 +1717,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.16"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1713,9 +1795,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -1747,6 +1829,41 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uucore"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b157ba598d7f7ed06f6dbc62999edb9d730b4d3fb58e503d8ad6d5fbe1e04391"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"libc",
|
||||
"nix",
|
||||
"os_display",
|
||||
"thiserror 2.0.18",
|
||||
"unic-langid",
|
||||
"uucore_procs",
|
||||
"wild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uucore_procs"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa291a52608ac5a2f8539e119666e021baa6b8c01f22f02ed201bbae54cbbc0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.14.1"
|
||||
@ -1855,6 +1972,15 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1"
|
||||
dependencies = [
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -1877,38 +2003,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.61.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||
dependencies = [
|
||||
"windows-collections 0.2.0",
|
||||
"windows-core 0.61.2",
|
||||
"windows-future 0.2.1",
|
||||
"windows-link 0.1.3",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
||||
dependencies = [
|
||||
"windows-collections 0.3.2",
|
||||
"windows-core 0.62.2",
|
||||
"windows-future 0.3.2",
|
||||
"windows-numerics 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-collections",
|
||||
"windows-core",
|
||||
"windows-future",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1917,20 +2021,7 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.1.3",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings 0.4.2",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1942,19 +2033,8 @@ dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.2.1",
|
||||
"windows-result 0.4.1",
|
||||
"windows-strings 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
"windows-threading 0.1.0",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1963,9 +2043,9 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-core",
|
||||
"windows-link 0.2.1",
|
||||
"windows-threading 0.2.1",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2002,35 +2082,16 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-core",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
@ -2040,15 +2101,6 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
@ -2127,15 +2179,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.2.1"
|
||||
@ -2282,3 +2325,9 @@ checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
|
||||
dependencies = [
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nu_plugin_fluent"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for Fluent i18n integration"
|
||||
authors = ["Jesús Pérex <jpl@jesusperez.com>"]
|
||||
@ -19,8 +19,8 @@ categories = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
serde_json = "1.0"
|
||||
fluent = "0.17"
|
||||
fluent-bundle = "0.16"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,10 +1,8 @@
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, LabeledError, Signature, Span, SyntaxShape, Type, Value, record,
|
||||
};
|
||||
use fluent::{FluentBundle, FluentResource};
|
||||
use unic_langid::LanguageIdentifier;
|
||||
use crate::FluentPlugin;
|
||||
use fluent::{FluentBundle, FluentResource};
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{record, Category, LabeledError, Signature, Span, SyntaxShape, Type, Value};
|
||||
use unic_langid::LanguageIdentifier;
|
||||
|
||||
pub struct CreateBundle;
|
||||
|
||||
@ -37,7 +35,11 @@ impl SimplePluginCommand for CreateBundle {
|
||||
"Fallback locales in order",
|
||||
Some('f'),
|
||||
)
|
||||
.switch("override", "Allow page files to override global messages", Some('o'))
|
||||
.switch(
|
||||
"override",
|
||||
"Allow page files to override global messages",
|
||||
Some('o'),
|
||||
)
|
||||
.category(Category::Strings)
|
||||
}
|
||||
|
||||
@ -70,16 +72,24 @@ impl SimplePluginCommand for CreateBundle {
|
||||
let locale_code: String = call.req(0)?;
|
||||
|
||||
// Parse locale
|
||||
let locale: LanguageIdentifier = locale_code.parse()
|
||||
.map_err(|e| LabeledError::new("Invalid locale").with_label(format!("Invalid locale '{}': {}", locale_code, e), call.head))?;
|
||||
let locale: LanguageIdentifier = locale_code.parse().map_err(|e| {
|
||||
LabeledError::new("Invalid locale").with_label(
|
||||
format!("Invalid locale '{}': {}", locale_code, e),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Create fallback locales
|
||||
let mut locales = vec![locale.clone()];
|
||||
if let Some(fallback_value) = call.get_flag("fallback")? {
|
||||
let fallback_codes = extract_string_list(fallback_value)?;
|
||||
for code in fallback_codes {
|
||||
let fallback_locale: LanguageIdentifier = code.parse()
|
||||
.map_err(|e| LabeledError::new("Invalid fallback locale").with_label(format!("Invalid fallback locale '{}': {}", code, e), call.head))?;
|
||||
let fallback_locale: LanguageIdentifier = code.parse().map_err(|e| {
|
||||
LabeledError::new("Invalid fallback locale").with_label(
|
||||
format!("Invalid fallback locale '{}': {}", code, e),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
locales.push(fallback_locale);
|
||||
}
|
||||
}
|
||||
@ -115,12 +125,12 @@ impl SimplePluginCommand for CreateBundle {
|
||||
|
||||
fn extract_string_list(value: Value) -> Result<Vec<String>, LabeledError> {
|
||||
match value {
|
||||
Value::List { vals, .. } => {
|
||||
vals.iter()
|
||||
Value::List { vals, .. } => vals
|
||||
.iter()
|
||||
.map(|v| value_to_string(v))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
_ => Err(LabeledError::new("Invalid list").with_label("Must be a list of strings", nu_protocol::Span::unknown())),
|
||||
.collect::<Result<Vec<_>, _>>(),
|
||||
_ => Err(LabeledError::new("Invalid list")
|
||||
.with_label("Must be a list of strings", nu_protocol::Span::unknown())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,23 +144,31 @@ fn load_files_to_bundle(
|
||||
source: &str,
|
||||
) -> Result<(), LabeledError> {
|
||||
for file_path in files {
|
||||
let content = std::fs::read_to_string(file_path)
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read '{}': {}", file_path, e), nu_protocol::Span::unknown()))?;
|
||||
let content = std::fs::read_to_string(file_path).map_err(|e| {
|
||||
LabeledError::new("Read error").with_label(
|
||||
format!("Failed to read '{}': {}", file_path, e),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let resource = FluentResource::try_new(content)
|
||||
.map_err(|e| LabeledError::new("Invalid FTL").with_label(format!("Invalid FTL in '{}': {:?}", file_path, e), nu_protocol::Span::unknown()))?;
|
||||
let resource = FluentResource::try_new(content).map_err(|e| {
|
||||
LabeledError::new("Invalid FTL").with_label(
|
||||
format!("Invalid FTL in '{}': {:?}", file_path, e),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
|
||||
bundle.add_resource(resource)
|
||||
.map_err(|errors| {
|
||||
let error_msgs: Vec<String> = errors.iter()
|
||||
.map(|e| format!("{:?}", e))
|
||||
.collect();
|
||||
LabeledError::new("Load error").with_label(format!(
|
||||
bundle.add_resource(resource).map_err(|errors| {
|
||||
let error_msgs: Vec<String> = errors.iter().map(|e| format!("{:?}", e)).collect();
|
||||
LabeledError::new("Load error").with_label(
|
||||
format!(
|
||||
"Failed to load {} file '{}': {}",
|
||||
source,
|
||||
file_path,
|
||||
error_msgs.join(", ")
|
||||
), nu_protocol::Span::unknown())
|
||||
),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
@ -197,7 +215,7 @@ fn value_to_string(value: &Value) -> Result<String, LabeledError> {
|
||||
Value::Bool { val, .. } => Ok(val.to_string()),
|
||||
_ => Err(LabeledError::new("Type conversion error").with_label(
|
||||
format!("Cannot convert {:?} to string", value.get_type()),
|
||||
nu_protocol::Span::unknown()
|
||||
nu_protocol::Span::unknown(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::FluentPlugin;
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value};
|
||||
use crate::FluentPlugin;
|
||||
|
||||
pub struct ExtractMessages;
|
||||
|
||||
@ -14,7 +14,11 @@ impl SimplePluginCommand for ExtractMessages {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(PluginCommand::name(self))
|
||||
.input_output_type(Type::Any, Type::List(Box::new(Type::String)))
|
||||
.required("file", SyntaxShape::Filepath, "FTL file to extract messages from")
|
||||
.required(
|
||||
"file",
|
||||
SyntaxShape::Filepath,
|
||||
"FTL file to extract messages from",
|
||||
)
|
||||
.category(Category::Strings)
|
||||
}
|
||||
|
||||
@ -23,13 +27,11 @@ impl SimplePluginCommand for ExtractMessages {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example<'_>> {
|
||||
vec![
|
||||
nu_protocol::Example {
|
||||
vec![nu_protocol::Example {
|
||||
description: "Extract message IDs from an FTL file",
|
||||
example: "fluent-extract locales/en-US/main.ftl",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::FluentPlugin;
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value};
|
||||
use std::fs;
|
||||
use crate::FluentPlugin;
|
||||
|
||||
pub struct ListLocales;
|
||||
|
||||
@ -15,7 +15,11 @@ impl SimplePluginCommand for ListLocales {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(PluginCommand::name(self))
|
||||
.input_output_type(Type::Any, Type::List(Box::new(Type::String)))
|
||||
.required("directory", SyntaxShape::Directory, "Directory containing locale folders")
|
||||
.required(
|
||||
"directory",
|
||||
SyntaxShape::Directory,
|
||||
"Directory containing locale folders",
|
||||
)
|
||||
.category(Category::Strings)
|
||||
}
|
||||
|
||||
@ -24,13 +28,11 @@ impl SimplePluginCommand for ListLocales {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example<'_>> {
|
||||
vec![
|
||||
nu_protocol::Example {
|
||||
vec![nu_protocol::Example {
|
||||
description: "List available locales",
|
||||
example: "fluent-list-locales ./locales",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -42,17 +44,27 @@ impl SimplePluginCommand for ListLocales {
|
||||
) -> Result<Value, LabeledError> {
|
||||
let directory: String = call.req(0)?;
|
||||
|
||||
let entries = fs::read_dir(&directory)
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read directory '{}': {}", directory, e), call.head))?;
|
||||
let entries = fs::read_dir(&directory).map_err(|e| {
|
||||
LabeledError::new("Read error").with_label(
|
||||
format!("Failed to read directory '{}': {}", directory, e),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut locales = Vec::new();
|
||||
|
||||
for entry in entries {
|
||||
let entry = entry
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read directory entry: {}", e), call.head))?;
|
||||
let entry = entry.map_err(|e| {
|
||||
LabeledError::new("Read error")
|
||||
.with_label(format!("Failed to read directory entry: {}", e), call.head)
|
||||
})?;
|
||||
|
||||
if entry.file_type()
|
||||
.map_err(|e| LabeledError::new("File type error").with_label(format!("Failed to get file type: {}", e), call.head))?
|
||||
if entry
|
||||
.file_type()
|
||||
.map_err(|e| {
|
||||
LabeledError::new("File type error")
|
||||
.with_label(format!("Failed to get file type: {}", e), call.head)
|
||||
})?
|
||||
.is_dir()
|
||||
{
|
||||
if let Some(name) = entry.file_name().to_str() {
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, LabeledError, Signature, SyntaxShape, Type, Value
|
||||
};
|
||||
use fluent::{FluentBundle, FluentResource, FluentArgs, FluentValue};
|
||||
use unic_langid::LanguageIdentifier;
|
||||
use crate::FluentPlugin;
|
||||
use fluent::{FluentArgs, FluentBundle, FluentResource, FluentValue};
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value};
|
||||
use unic_langid::LanguageIdentifier;
|
||||
|
||||
pub struct Localize;
|
||||
|
||||
@ -38,7 +36,11 @@ impl SimplePluginCommand for Localize {
|
||||
"FTL files to load",
|
||||
Some('f'),
|
||||
)
|
||||
.switch("fallback", "Return message ID if translation not found", Some('F'))
|
||||
.switch(
|
||||
"fallback",
|
||||
"Return message ID if translation not found",
|
||||
Some('F'),
|
||||
)
|
||||
.category(Category::Strings)
|
||||
}
|
||||
|
||||
@ -77,8 +79,12 @@ impl SimplePluginCommand for Localize {
|
||||
let locale_code: String = call.req(1)?;
|
||||
|
||||
// Parse locale
|
||||
let locale: LanguageIdentifier = locale_code.parse()
|
||||
.map_err(|e| LabeledError::new("Invalid locale").with_label(format!("Invalid locale '{}': {}", locale_code, e), call.head))?;
|
||||
let locale: LanguageIdentifier = locale_code.parse().map_err(|e| {
|
||||
LabeledError::new("Invalid locale").with_label(
|
||||
format!("Invalid locale '{}': {}", locale_code, e),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Create FluentBundle
|
||||
let mut bundle = FluentBundle::new(vec![locale.clone()]);
|
||||
@ -92,7 +98,8 @@ impl SimplePluginCommand for Localize {
|
||||
let files = extract_file_list(files_value)?;
|
||||
load_from_files(&mut bundle, &files)?;
|
||||
} else {
|
||||
return Err(LabeledError::new("Missing argument").with_label("Must provide either --bundle or --files", call.head));
|
||||
return Err(LabeledError::new("Missing argument")
|
||||
.with_label("Must provide either --bundle or --files", call.head));
|
||||
}
|
||||
|
||||
// Prepare arguments for interpolation
|
||||
@ -110,32 +117,37 @@ impl SimplePluginCommand for Localize {
|
||||
// Return message ID as fallback
|
||||
return Ok(Value::string(format!("[[{}]]", message_id), call.head));
|
||||
} else {
|
||||
return Err(LabeledError::new("Message not found").with_label(format!("Message '{}' not found in locale '{}'", message_id, locale_code), call.head));
|
||||
return Err(LabeledError::new("Message not found").with_label(
|
||||
format!(
|
||||
"Message '{}' not found in locale '{}'",
|
||||
message_id, locale_code
|
||||
),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Format the message
|
||||
let pattern = msg.value()
|
||||
.ok_or_else(|| LabeledError::new("Message has no value").with_label(format!("Message '{}' has no value", message_id), call.head))?;
|
||||
let pattern = msg.value().ok_or_else(|| {
|
||||
LabeledError::new("Message has no value")
|
||||
.with_label(format!("Message '{}' has no value", message_id), call.head)
|
||||
})?;
|
||||
|
||||
let mut errors = vec![];
|
||||
let formatted = bundle.format_pattern(
|
||||
pattern,
|
||||
fluent_args.as_ref(),
|
||||
&mut errors
|
||||
);
|
||||
let formatted = bundle.format_pattern(pattern, fluent_args.as_ref(), &mut errors);
|
||||
|
||||
// Handle formatting errors
|
||||
if !errors.is_empty() {
|
||||
let error_msgs: Vec<String> = errors.iter()
|
||||
.map(|e| format!("{:?}", e))
|
||||
.collect();
|
||||
return Err(LabeledError::new("Formatting error").with_label(format!(
|
||||
let error_msgs: Vec<String> = errors.iter().map(|e| format!("{:?}", e)).collect();
|
||||
return Err(LabeledError::new("Formatting error").with_label(
|
||||
format!(
|
||||
"Formatting errors for message '{}': {}",
|
||||
message_id,
|
||||
error_msgs.join(", ")
|
||||
), call.head));
|
||||
),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Value::string(formatted.to_string(), call.head))
|
||||
@ -153,7 +165,10 @@ fn load_from_bundle_value(
|
||||
load_messages_from_value(bundle, messages_value)?;
|
||||
}
|
||||
}
|
||||
_ => return Err(LabeledError::new("Invalid bundle").with_label("Bundle must be a record", nu_protocol::Span::unknown())),
|
||||
_ => {
|
||||
return Err(LabeledError::new("Invalid bundle")
|
||||
.with_label("Bundle must be a record", nu_protocol::Span::unknown()))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -172,16 +187,27 @@ fn load_messages_from_value(
|
||||
|
||||
// Create a minimal FTL resource from the message
|
||||
let ftl_content = format!("{} = {}", id, text);
|
||||
let resource = FluentResource::try_new(ftl_content)
|
||||
.map_err(|_| LabeledError::new("Invalid FTL").with_label(format!("Invalid FTL for message '{}'", id), nu_protocol::Span::unknown()))?;
|
||||
let resource = FluentResource::try_new(ftl_content).map_err(|_| {
|
||||
LabeledError::new("Invalid FTL").with_label(
|
||||
format!("Invalid FTL for message '{}'", id),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
|
||||
bundle.add_resource(resource)
|
||||
.map_err(|_| LabeledError::new("Failed to add message").with_label(format!("Failed to add message '{}'", id), nu_protocol::Span::unknown()))?;
|
||||
bundle.add_resource(resource).map_err(|_| {
|
||||
LabeledError::new("Failed to add message").with_label(
|
||||
format!("Failed to add message '{}'", id),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err(LabeledError::new("Invalid messages").with_label("Messages must be a list", nu_protocol::Span::unknown())),
|
||||
_ => {
|
||||
return Err(LabeledError::new("Invalid messages")
|
||||
.with_label("Messages must be a list", nu_protocol::Span::unknown()))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -191,26 +217,40 @@ fn load_from_files(
|
||||
files: &[String],
|
||||
) -> Result<(), LabeledError> {
|
||||
for file_path in files {
|
||||
let content = std::fs::read_to_string(file_path)
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read '{}': {}", file_path, e), nu_protocol::Span::unknown()))?;
|
||||
let content = std::fs::read_to_string(file_path).map_err(|e| {
|
||||
LabeledError::new("Read error").with_label(
|
||||
format!("Failed to read '{}': {}", file_path, e),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let resource = FluentResource::try_new(content)
|
||||
.map_err(|e| LabeledError::new("Invalid FTL").with_label(format!("Invalid FTL in '{}': {:?}", file_path, e), nu_protocol::Span::unknown()))?;
|
||||
let resource = FluentResource::try_new(content).map_err(|e| {
|
||||
LabeledError::new("Invalid FTL").with_label(
|
||||
format!("Invalid FTL in '{}': {:?}", file_path, e),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
|
||||
bundle.add_resource(resource)
|
||||
.map_err(|e| LabeledError::new("Load error").with_label(format!("Failed to load '{}': {:?}", file_path, e), nu_protocol::Span::unknown()))?;
|
||||
bundle.add_resource(resource).map_err(|e| {
|
||||
LabeledError::new("Load error").with_label(
|
||||
format!("Failed to load '{}': {:?}", file_path, e),
|
||||
nu_protocol::Span::unknown(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_file_list(files_value: Value) -> Result<Vec<String>, LabeledError> {
|
||||
match files_value {
|
||||
Value::List { vals, .. } => {
|
||||
vals.iter()
|
||||
Value::List { vals, .. } => vals
|
||||
.iter()
|
||||
.map(|v| value_to_string(v))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
_ => Err(LabeledError::new("Invalid files").with_label("Files must be a list of strings", nu_protocol::Span::unknown())),
|
||||
.collect::<Result<Vec<_>, _>>(),
|
||||
_ => Err(LabeledError::new("Invalid files").with_label(
|
||||
"Files must be a list of strings",
|
||||
nu_protocol::Span::unknown(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,16 +264,24 @@ fn convert_to_fluent_args(args_value: Value) -> Result<FluentArgs<'static>, Labe
|
||||
Value::String { val, .. } => FluentValue::from(val.clone()),
|
||||
Value::Int { val, .. } => FluentValue::from(*val as f64),
|
||||
Value::Float { val, .. } => FluentValue::from(*val),
|
||||
_ => return Err(LabeledError::new("Unsupported argument type").with_label(format!(
|
||||
_ => {
|
||||
return Err(LabeledError::new("Unsupported argument type").with_label(
|
||||
format!(
|
||||
"Unsupported argument type for '{}': {:?}",
|
||||
key,
|
||||
value.get_type()
|
||||
), nu_protocol::Span::unknown())),
|
||||
),
|
||||
nu_protocol::Span::unknown(),
|
||||
))
|
||||
}
|
||||
};
|
||||
fluent_args.set(key.clone(), fluent_value);
|
||||
}
|
||||
}
|
||||
_ => return Err(LabeledError::new("Invalid arguments").with_label("Arguments must be a record", nu_protocol::Span::unknown())),
|
||||
_ => {
|
||||
return Err(LabeledError::new("Invalid arguments")
|
||||
.with_label("Arguments must be a record", nu_protocol::Span::unknown()))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(fluent_args)
|
||||
@ -247,7 +295,7 @@ fn value_to_string(value: &Value) -> Result<String, LabeledError> {
|
||||
Value::Bool { val, .. } => Ok(val.to_string()),
|
||||
_ => Err(LabeledError::new("Type conversion error").with_label(
|
||||
format!("Cannot convert {:?} to string", value.get_type()),
|
||||
nu_protocol::Span::unknown()
|
||||
nu_protocol::Span::unknown(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,13 @@
|
||||
mod parse_ftl;
|
||||
mod localize;
|
||||
mod validate_ftl;
|
||||
mod create_bundle;
|
||||
mod extract_messages;
|
||||
mod list_locales;
|
||||
mod create_bundle;
|
||||
mod localize;
|
||||
mod parse_ftl;
|
||||
mod validate_ftl;
|
||||
|
||||
pub use parse_ftl::ParseFtl;
|
||||
pub use localize::Localize;
|
||||
pub use validate_ftl::ValidateFtl;
|
||||
pub use create_bundle::CreateBundle;
|
||||
pub use extract_messages::ExtractMessages;
|
||||
pub use list_locales::ListLocales;
|
||||
pub use create_bundle::CreateBundle;
|
||||
|
||||
pub use localize::Localize;
|
||||
pub use parse_ftl::ParseFtl;
|
||||
pub use validate_ftl::ValidateFtl;
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, LabeledError, Signature, Span, SyntaxShape, Type, Value, record
|
||||
};
|
||||
use fluent_syntax::parser::parse;
|
||||
use fluent_syntax::ast::{Entry, Message, Pattern, PatternElement};
|
||||
use std::fs;
|
||||
use crate::FluentPlugin;
|
||||
use fluent_syntax::ast::{Entry, Message, Pattern, PatternElement};
|
||||
use fluent_syntax::parser::parse;
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{record, Category, LabeledError, Signature, Span, SyntaxShape, Type, Value};
|
||||
use std::fs;
|
||||
|
||||
pub struct ParseFtl;
|
||||
|
||||
@ -28,13 +26,11 @@ impl SimplePluginCommand for ParseFtl {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example<'_>> {
|
||||
vec![
|
||||
nu_protocol::Example {
|
||||
vec![nu_protocol::Example {
|
||||
description: "Parse an FTL file",
|
||||
example: "fluent-parse locales/en-US/main.ftl",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -47,14 +43,21 @@ impl SimplePluginCommand for ParseFtl {
|
||||
let file_path: String = call.req(0)?;
|
||||
|
||||
// Read FTL file
|
||||
let ftl_content = fs::read_to_string(&file_path)
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read file '{}': {}", file_path, e), call.head))?;
|
||||
let ftl_content = fs::read_to_string(&file_path).map_err(|e| {
|
||||
LabeledError::new("Read error").with_label(
|
||||
format!("Failed to read file '{}': {}", file_path, e),
|
||||
call.head,
|
||||
)
|
||||
})?;
|
||||
|
||||
// Parse FTL content
|
||||
let resource = match parse(ftl_content) {
|
||||
Ok(res) => res,
|
||||
Err((_, errors)) => {
|
||||
return Err(LabeledError::new("Parse error").with_label(format!("Failed to parse FTL content: {:?}", errors), call.head));
|
||||
return Err(LabeledError::new("Parse error").with_label(
|
||||
format!("Failed to parse FTL content: {:?}", errors),
|
||||
call.head,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -76,7 +79,10 @@ impl SimplePluginCommand for ParseFtl {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_messages_from_resource(resource: &fluent_syntax::ast::Resource<String>, span: Span) -> Result<Vec<Value>, String> {
|
||||
fn extract_messages_from_resource(
|
||||
resource: &fluent_syntax::ast::Resource<String>,
|
||||
span: Span,
|
||||
) -> Result<Vec<Value>, String> {
|
||||
let mut messages = Vec::new();
|
||||
|
||||
for entry in &resource.body {
|
||||
@ -113,8 +119,16 @@ fn extract_message_info(message: &Message<String>, span: Span) -> Result<Value,
|
||||
}
|
||||
|
||||
// Extract comment if present
|
||||
let comment = message.comment.as_ref()
|
||||
.map(|c| c.content.iter().map(|line| line.trim()).collect::<Vec<_>>().join("\n"))
|
||||
let comment = message
|
||||
.comment
|
||||
.as_ref()
|
||||
.map(|c| {
|
||||
c.content
|
||||
.iter()
|
||||
.map(|line| line.trim())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
Ok(Value::record(
|
||||
@ -129,7 +143,8 @@ fn extract_message_info(message: &Message<String>, span: Span) -> Result<Value,
|
||||
}
|
||||
|
||||
fn extract_pattern_text(pattern: &Pattern<String>) -> String {
|
||||
pattern.elements
|
||||
pattern
|
||||
.elements
|
||||
.iter()
|
||||
.map(|element| match element {
|
||||
PatternElement::TextElement { value } => value.to_string(),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value, record};
|
||||
use fluent_syntax::parser::parse;
|
||||
use crate::FluentPlugin;
|
||||
use fluent_syntax::parser::parse;
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
|
||||
use nu_protocol::{record, Category, LabeledError, Signature, SyntaxShape, Type, Value};
|
||||
|
||||
pub struct ValidateFtl;
|
||||
|
||||
@ -24,13 +24,11 @@ impl SimplePluginCommand for ValidateFtl {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example<'_>> {
|
||||
vec![
|
||||
nu_protocol::Example {
|
||||
vec![nu_protocol::Example {
|
||||
description: "Validate an FTL file",
|
||||
example: "fluent-validate locales/en-US/main.ftl",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -42,8 +40,10 @@ impl SimplePluginCommand for ValidateFtl {
|
||||
) -> Result<Value, LabeledError> {
|
||||
let file_path: String = call.req(0)?;
|
||||
|
||||
let content = std::fs::read_to_string(&file_path)
|
||||
.map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read '{}': {}", file_path, e), call.head))?;
|
||||
let content = std::fs::read_to_string(&file_path).map_err(|e| {
|
||||
LabeledError::new("Read error")
|
||||
.with_label(format!("Failed to read '{}': {}", file_path, e), call.head)
|
||||
})?;
|
||||
|
||||
let parse_result = parse(content);
|
||||
let result = match parse_result {
|
||||
@ -56,7 +56,8 @@ impl SimplePluginCommand for ValidateFtl {
|
||||
call.head,
|
||||
),
|
||||
Err((_resource, errors)) => {
|
||||
let error_list: Vec<Value> = errors.iter()
|
||||
let error_list: Vec<Value> = errors
|
||||
.iter()
|
||||
.map(|err| Value::string(format!("{:?}", err), call.head))
|
||||
.collect();
|
||||
|
||||
|
||||
@ -22,4 +22,3 @@ impl Plugin for FluentPlugin {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
933
nu_plugin_hashes/Cargo.lock
generated
933
nu_plugin_hashes/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ keywords = [
|
||||
categories = ["algorithms"]
|
||||
repository = "https://github.com/ArmoredPony/nu_plugin_hashes"
|
||||
license = "MIT"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
@ -37,9 +37,9 @@ default = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = "0.109.1"
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-cmd-base = "0.111.0"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
digest = "0.10.7"
|
||||
|
||||
[dependencies.ascon-hash]
|
||||
@ -215,9 +215,8 @@ optional = true
|
||||
version = "0.10.4"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.1"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = "0.111.0"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
[package]
|
||||
name = "nu_plugin_hashes"
|
||||
description = "A Nushell plugin that adds 63 cryptographic hash functions from Hashes project"
|
||||
keywords = [
|
||||
"nu",
|
||||
"plugin",
|
||||
"hash",
|
||||
]
|
||||
categories = ["algorithms"]
|
||||
repository = "https://github.com/ArmoredPony/nu_plugin_hashes"
|
||||
license = "MIT"
|
||||
version = "0.109.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"ascon-hash",
|
||||
"belt-hash",
|
||||
"blake2",
|
||||
"blake3",
|
||||
"fsb",
|
||||
"gost94",
|
||||
"groestl",
|
||||
"jh",
|
||||
"md2",
|
||||
"md4",
|
||||
"ripemd",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"sha3",
|
||||
"shabal",
|
||||
"skein",
|
||||
"sm3",
|
||||
"streebog",
|
||||
"tiger",
|
||||
"whirlpool",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = "0.109.1"
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
digest = "0.10.7"
|
||||
|
||||
[dependencies.ascon-hash]
|
||||
version = "0.3.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.belt-hash]
|
||||
version = "0.1.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.blake2]
|
||||
version = "0.10.6"
|
||||
optional = true
|
||||
|
||||
[dependencies.blake3]
|
||||
version = "1.8.2"
|
||||
optional = true
|
||||
default-features = false
|
||||
features = [
|
||||
"std",
|
||||
"traits-preview",
|
||||
]
|
||||
|
||||
[dependencies.fsb]
|
||||
version = "0.1.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.gost94]
|
||||
version = "0.10.4"
|
||||
optional = true
|
||||
|
||||
[dependencies.groestl]
|
||||
version = "0.10.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.jh]
|
||||
version = "0.1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.md2]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.md4]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.ripemd]
|
||||
version = "0.1.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.sha1]
|
||||
version = "0.10.6"
|
||||
optional = true
|
||||
|
||||
[dependencies.sha2]
|
||||
version = "0.10.9"
|
||||
optional = true
|
||||
|
||||
[dependencies.sha3]
|
||||
version = "0.10.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.shabal]
|
||||
version = "0.4.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.skein]
|
||||
version = "0.1.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.sm3]
|
||||
version = "0.4.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.streebog]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.tiger]
|
||||
version = "0.2.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.whirlpool]
|
||||
version = "0.10.4"
|
||||
optional = true
|
||||
|
||||
[build-dependencies]
|
||||
digest = "0.10.7"
|
||||
|
||||
[build-dependencies.ascon-hash]
|
||||
version = "0.3.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.belt-hash]
|
||||
version = "0.1.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.blake2]
|
||||
version = "0.10.6"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.blake3]
|
||||
version = "1.8.2"
|
||||
optional = true
|
||||
default-features = false
|
||||
features = [
|
||||
"std",
|
||||
"traits-preview",
|
||||
]
|
||||
|
||||
[build-dependencies.fsb]
|
||||
version = "0.1.3"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.gost94]
|
||||
version = "0.10.4"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.groestl]
|
||||
version = "0.10.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.jh]
|
||||
version = "0.1.0"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.md2]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.md4]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.ripemd]
|
||||
version = "0.1.3"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.sha1]
|
||||
version = "0.10.6"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.sha2]
|
||||
version = "0.10.9"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.sha3]
|
||||
version = "0.10.8"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.shabal]
|
||||
version = "0.4.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.skein]
|
||||
version = "0.1.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.sm3]
|
||||
version = "0.4.2"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.streebog]
|
||||
version = "0.10.2"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.tiger]
|
||||
version = "0.2.1"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.whirlpool]
|
||||
version = "0.10.4"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.0"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
@ -13,20 +13,25 @@ crate.
|
||||
## Installation
|
||||
|
||||
To install this plugin with all algorithms available run
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
cargo install nu_plugin_hashes
|
||||
plugin add ($env.CARGO_HOME ++ /bin/nu_plugin_hashes)
|
||||
```
|
||||
|
||||
or on Windows
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
cargo install nu_plugin_hashes
|
||||
plugin add ($env.CARGO_HOME ++ /bin/nu_plugin_hashes.exe)
|
||||
```
|
||||
|
||||
After loading the plugin, execute `help hash` to list newly added commands
|
||||
|
||||
```nu
|
||||
```nushell
|
||||
nu
|
||||
~> help hash
|
||||
Apply hash function.
|
||||
|
||||
@ -47,12 +52,16 @@ Subcommands:
|
||||
|
||||
If you only need some algorithms, disable default features and select only
|
||||
those you need
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
cargo install nu_plugin_hashes --no-default-features --features sha2,streebog
|
||||
```
|
||||
|
||||
Then check what's installed
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
~> help hash
|
||||
Apply hash function.
|
||||
|
||||
|
||||
@ -467,12 +467,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let hashers_generated_path = Path::new(&out_dir).join("hashers_generated.rs");
|
||||
let commands_generated_path =
|
||||
Path::new(&out_dir).join("commands_generated.rs");
|
||||
let mut hashers_generated_file =
|
||||
std::fs::File::create(hashers_generated_path).unwrap();
|
||||
let mut commands_generated_file =
|
||||
std::fs::File::create(commands_generated_path).unwrap();
|
||||
let commands_generated_path = Path::new(&out_dir).join("commands_generated.rs");
|
||||
let mut hashers_generated_file = std::fs::File::create(hashers_generated_path).unwrap();
|
||||
let mut commands_generated_file = std::fs::File::create(commands_generated_path).unwrap();
|
||||
|
||||
write!(
|
||||
hashers_generated_file,
|
||||
@ -494,13 +491,10 @@ pub fn commands() -> Vec<Box<dyn PluginCommand<Plugin = HashesPlugin>>> {{
|
||||
)?;
|
||||
|
||||
for mut hasher_impl_meta in hasher_impls {
|
||||
let feature_name =
|
||||
hasher_impl_meta.crate_name.replace("-", "_").to_uppercase();
|
||||
let feature_name = hasher_impl_meta.crate_name.replace("-", "_").to_uppercase();
|
||||
if std::env::var(format!("CARGO_FEATURE_{feature_name}")).is_ok() {
|
||||
hashers_generated_file
|
||||
.write_all(build_impl_str(&mut hasher_impl_meta).as_bytes())?;
|
||||
hashers_generated_file
|
||||
.write_all(build_test_str(&hasher_impl_meta).as_bytes())?;
|
||||
hashers_generated_file.write_all(build_impl_str(&mut hasher_impl_meta).as_bytes())?;
|
||||
hashers_generated_file.write_all(build_test_str(&hasher_impl_meta).as_bytes())?;
|
||||
|
||||
let crate_name = hasher_impl_meta.crate_name;
|
||||
let hasher_type_name = hasher_impl_meta.hasher_type_name;
|
||||
@ -586,13 +580,11 @@ impl Hasher for {crate_name}::{hasher_type_name} {{
|
||||
}}
|
||||
}}
|
||||
",
|
||||
hash
|
||||
.iter()
|
||||
hash.iter()
|
||||
.map(|b| format!("{b:02x?}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(""),
|
||||
hash
|
||||
.iter()
|
||||
hash.iter()
|
||||
.map(|b| format!("0x{b:02x?}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",")
|
||||
|
||||
@ -7,21 +7,11 @@
|
||||
use std::{io::Write, marker::PhantomData, ops::Not};
|
||||
|
||||
use digest::{Digest, Output};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_cmd_base::input_handler::{CmdArgument, operate};
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||
use nu_protocol::{
|
||||
ast::CellPath,
|
||||
Category,
|
||||
Example,
|
||||
IntoPipelineData,
|
||||
LabeledError,
|
||||
PipelineData,
|
||||
ShellError,
|
||||
Signature,
|
||||
Span,
|
||||
SyntaxShape,
|
||||
Type,
|
||||
Value,
|
||||
Category, Example, IntoPipelineData, LabeledError, PipelineData, ShellError, Signature, Span,
|
||||
SyntaxShape, Type, Value, ast::CellPath,
|
||||
};
|
||||
|
||||
use crate::HashesPlugin;
|
||||
@ -42,10 +32,7 @@ impl<H: Hasher> Default for GenericHasher<H> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: format!("hash {}", H::name()),
|
||||
description: format!(
|
||||
"Hash a value using the {} hash algorithm.",
|
||||
H::name()
|
||||
),
|
||||
description: format!("Hash a value using the {} hash algorithm.", H::name()),
|
||||
_hasher: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use nu_plugin::{serve_plugin, MsgPackSerializer};
|
||||
use nu_plugin::{MsgPackSerializer, serve_plugin};
|
||||
use nu_plugin_hashes::HashesPlugin;
|
||||
|
||||
fn main() {
|
||||
|
||||
569
nu_plugin_highlight/Cargo.lock
generated
569
nu_plugin_highlight/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nu_plugin_highlight"
|
||||
version = "1.4.7+0.105.2"
|
||||
version = "0.111.0"
|
||||
authors = ["Tim 'Piepmatz' Hesse"]
|
||||
edition = "2024"
|
||||
repository = "https://github.com/cptpiepmatz/nu-plugin-highlight"
|
||||
@ -26,9 +26,9 @@ version = "0.26"
|
||||
default-features = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-path = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
nu-path = "0.111.0"
|
||||
nu-ansi-term = "0.50"
|
||||
ansi_colours = "1"
|
||||
mime_guess = "2"
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## About
|
||||
|
||||
`nu-plugin-highlight` is a plugin for [Nushell](https://www.nushell.sh) that
|
||||
provides syntax highlighting for source code.
|
||||
It uses the [`syntect`](https://crates.io/crates/syntect) library for syntax
|
||||
@ -26,9 +26,12 @@ access to its ready-to-use assets.
|
||||
Custom themes can be loaded too.
|
||||
|
||||
## Usage
|
||||
|
||||
The `highlight` command can be used for syntax highlighting source code.
|
||||
Here are a few examples:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
# Highlight a Markdown file by guessing the type from the pipeline metadata
|
||||
open README.md | highlight
|
||||
|
||||
@ -49,11 +52,13 @@ highlight --list-themes
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `language <string>`:
|
||||
This is an optional parameter that can be used to specify the language or file
|
||||
extension to aid language detection.
|
||||
|
||||
### Flags
|
||||
|
||||
- `-h, --help`:
|
||||
Display the help message for the highlight command.
|
||||
|
||||
@ -64,18 +69,23 @@ highlight --list-themes
|
||||
List all possible themes.
|
||||
|
||||
## Configuration
|
||||
|
||||
The plugin can be configured using the
|
||||
[`$env.config.plugins.highlight`](https://github.com/nushell/nushell/pull/10955)
|
||||
variable.
|
||||
|
||||
### `true_colors`
|
||||
|
||||
Enable or disable true colors (24-bit).
|
||||
By default, this is enabled.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
$env.config.plugins.highlight.true_colors = true
|
||||
```
|
||||
|
||||
### `theme`
|
||||
|
||||
Set a theme to use.
|
||||
The default theme depends on the operating system.
|
||||
Use `highlight --list-themes | where default == true` to see your default theme.
|
||||
@ -83,24 +93,31 @@ Setting this environment variable should allow
|
||||
`highlight --list-themes | where id == $env.config.plugins.highlight.theme` to
|
||||
result in a single row with your selected theme.
|
||||
If you get no results, you have set an invalid theme.
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
$env.config.plugins.highlight.theme = ansi
|
||||
```
|
||||
|
||||
### `custom_themes`
|
||||
|
||||
Set a directory to load custom themes from.
|
||||
Using `synctect`s theme loader, you can load custom themes in the `.tmtheme`
|
||||
format from a directory that is passed as this configuration value.
|
||||
```nushell
|
||||
|
||||
```toml
|
||||
nushell
|
||||
$env.config.plugins.highlight.custom_themes = ~/.nu/highlight/themes
|
||||
```
|
||||
|
||||
## Plugin Installation
|
||||
|
||||
Installing and registering the `nu-plugin-highlight` is a straightforward
|
||||
process.
|
||||
Follow these steps:
|
||||
|
||||
1. Install the plugin from crates.io using cargo:
|
||||
|
||||
```nushell
|
||||
cargo install nu_plugin_highlight
|
||||
```
|
||||
@ -108,6 +125,7 @@ Follow these steps:
|
||||
2. Restart your terminal session to ensure the newly installed plugin is recognized.
|
||||
|
||||
3. Find path of your installation:
|
||||
|
||||
```nushell
|
||||
which nu_plugin_highlight
|
||||
```
|
||||
@ -115,6 +133,7 @@ Follow these steps:
|
||||
4. Register the plugin with Nushell:
|
||||
|
||||
If you are using a version **lower** than **0.93.0**, use `register` instead of `plugin add`.
|
||||
|
||||
```nushell
|
||||
plugin add path/to/the/plugin/binary
|
||||
```
|
||||
@ -124,6 +143,7 @@ Follow these steps:
|
||||
Tip: You can simply restart the shell or terminal. When nushell starts, it loads all plugins.
|
||||
|
||||
If you are using a version **lower** than **0.93.0**, you do **not need** to do this.
|
||||
|
||||
```nushell
|
||||
plugin use highlight
|
||||
```
|
||||
@ -131,10 +151,12 @@ Follow these steps:
|
||||
After registering, the plugin is available as part of your set of commands:
|
||||
|
||||
```nushell
|
||||
nushell
|
||||
help commands | where command_type == "plugin"
|
||||
```
|
||||
|
||||
## Version Numbering
|
||||
|
||||
Starting with version `v1.1.0`, the version number of `nu-plugin-highlight`
|
||||
incorporates the version number of its dependency, `nu-plugin`.
|
||||
This is denoted in the format `v1.1.0+0.90.1`, where `v1.1.0` refers to the
|
||||
@ -142,5 +164,6 @@ version of `nu-plugin-highlight` and `0.90.1` refers to the version of the
|
||||
`nu-plugin` dependency.
|
||||
|
||||
## License
|
||||
|
||||
`nu_plugin_highlight` is licensed under the MIT License.
|
||||
See [LICENSE](LICENSE) for more information.
|
||||
@ -2,11 +2,11 @@ use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
|
||||
use bat::assets::HighlightingAssets;
|
||||
use bat::theme::{default_theme, ColorScheme};
|
||||
use bat::theme::{ColorScheme, default_theme};
|
||||
use syntect::LoadingError;
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::ThemeSet;
|
||||
use syntect::parsing::{SyntaxReference, SyntaxSet};
|
||||
use syntect::LoadingError;
|
||||
|
||||
use crate::terminal;
|
||||
use crate::theme::{ListThemes, ThemeDescription};
|
||||
@ -17,7 +17,7 @@ const SYNTAX_SET: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/syntax_set.b
|
||||
pub struct Highlighter {
|
||||
syntax_set: SyntaxSet,
|
||||
highlighting_assets: HighlightingAssets,
|
||||
custom_themes: Option<ThemeSet>
|
||||
custom_themes: Option<ThemeSet>,
|
||||
}
|
||||
|
||||
impl Highlighter {
|
||||
@ -27,13 +27,13 @@ impl Highlighter {
|
||||
syntax_set: syntect::dumps::from_uncompressed_data(SYNTAX_SET)
|
||||
.expect("Failed to load syntax set"),
|
||||
highlighting_assets: HighlightingAssets::from_binary(),
|
||||
custom_themes: None
|
||||
custom_themes: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn custom_themes_from_folder(
|
||||
&mut self,
|
||||
path: impl AsRef<Path>
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<(), LoadingError> {
|
||||
let path = nu_path::expand_to_real_path(path);
|
||||
self.custom_themes = Some(ThemeSet::load_from_folder(path)?);
|
||||
@ -53,7 +53,7 @@ impl Highlighter {
|
||||
id: t_id.to_owned(),
|
||||
name: theme.name.clone(),
|
||||
author: theme.author.clone(),
|
||||
default: default_theme_id == t_id
|
||||
default: default_theme_id == t_id,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -64,7 +64,7 @@ impl Highlighter {
|
||||
id: id.to_owned(),
|
||||
name: theme.name.clone(),
|
||||
author: theme.author.clone(),
|
||||
default: default_theme_id == id
|
||||
default: default_theme_id == id,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ impl Highlighter {
|
||||
input: &str,
|
||||
language: Option<&str>,
|
||||
theme: Option<&str>,
|
||||
true_colors: bool
|
||||
true_colors: bool,
|
||||
) -> String {
|
||||
let syntax_set = &self.syntax_set;
|
||||
let syntax_ref: Option<&SyntaxReference> = match language {
|
||||
@ -118,7 +118,7 @@ impl Highlighter {
|
||||
.or_else(|| syntax_set.find_syntax_by_extension(&language_lowercase))
|
||||
.or_else(|| syntax_set.find_syntax_by_extension(&language_capitalized))
|
||||
}
|
||||
_ => None
|
||||
_ => None,
|
||||
};
|
||||
let syntax_ref = syntax_ref
|
||||
.or(syntax_set.find_syntax_by_first_line(input))
|
||||
@ -126,7 +126,7 @@ impl Highlighter {
|
||||
|
||||
let theme_id = match theme {
|
||||
None => default_theme(ColorScheme::Dark),
|
||||
Some(theme) => theme
|
||||
Some(theme) => theme,
|
||||
};
|
||||
let theme = self
|
||||
.custom_themes
|
||||
@ -143,10 +143,11 @@ impl Highlighter {
|
||||
// insert a newline in between lines, this is necessary for bats syntax set
|
||||
let l = match i == line_count - 1 {
|
||||
false => format!("{}\n", l.trim_end()),
|
||||
true => l.trim_end().to_owned()
|
||||
true => l.trim_end().to_owned(),
|
||||
};
|
||||
|
||||
let styled_lines = highlighter.highlight_line(&l, syntax_set)
|
||||
let styled_lines = highlighter
|
||||
.highlight_line(&l, syntax_set)
|
||||
.expect("Failed to highlight line");
|
||||
styled_lines
|
||||
.iter()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use nu_plugin::{serve_plugin, MsgPackSerializer};
|
||||
use nu_plugin::{MsgPackSerializer, serve_plugin};
|
||||
use plugin::HighlightPlugin;
|
||||
|
||||
mod highlight;
|
||||
|
||||
@ -6,7 +6,7 @@ use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand};
|
||||
use nu_protocol::shell_error::io::IoError;
|
||||
use nu_protocol::{
|
||||
Category, DataSource, ErrorLabel, Example, FromValue, IntoValue, LabeledError, PipelineData,
|
||||
PipelineMetadata, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value
|
||||
PipelineMetadata, ShellError, Signature, Span, Spanned, SyntaxShape, Type, Value,
|
||||
};
|
||||
use syntect::LoadingError;
|
||||
|
||||
@ -29,7 +29,7 @@ impl Plugin for HighlightPlugin {
|
||||
struct Config {
|
||||
pub theme: Option<Spanned<String>>,
|
||||
pub true_colors: Option<bool>,
|
||||
pub custom_themes: Option<Spanned<PathBuf>>
|
||||
pub custom_themes: Option<Spanned<PathBuf>>,
|
||||
}
|
||||
|
||||
struct Highlight;
|
||||
@ -46,13 +46,13 @@ impl PluginCommand for Highlight {
|
||||
.optional(
|
||||
"language",
|
||||
SyntaxShape::String,
|
||||
"language or file extension to help language detection"
|
||||
"language or file extension to help language detection",
|
||||
)
|
||||
.named(
|
||||
"theme",
|
||||
SyntaxShape::String,
|
||||
"them used for highlighting",
|
||||
Some('t')
|
||||
Some('t'),
|
||||
)
|
||||
.switch("list-themes", "list all possible themes", None)
|
||||
.category(Category::Strings)
|
||||
@ -66,8 +66,8 @@ impl PluginCommand for Highlight {
|
||||
(String::from("author"), Type::String),
|
||||
(String::from("default"), Type::Bool),
|
||||
]
|
||||
.into()
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ impl PluginCommand for Highlight {
|
||||
_plugin: &Self::Plugin,
|
||||
engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
input: PipelineData
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, LabeledError> {
|
||||
let mut highlighter = Highlighter::new();
|
||||
|
||||
@ -96,17 +96,17 @@ impl PluginCommand for Highlight {
|
||||
err,
|
||||
custom_themes_path.span,
|
||||
custom_themes_path.item,
|
||||
"Error while loading custom themes"
|
||||
)
|
||||
)))
|
||||
"Error while loading custom themes",
|
||||
),
|
||||
)));
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(labeled_error(
|
||||
err,
|
||||
"Error while loading custom themes",
|
||||
custom_themes_path.span,
|
||||
None
|
||||
))
|
||||
None,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,12 +117,13 @@ impl PluginCommand for Highlight {
|
||||
.transpose()?
|
||||
.or(config.theme);
|
||||
if let Some(theme) = &theme
|
||||
&& !highlighter.is_valid_theme(&theme.item) {
|
||||
&& !highlighter.is_valid_theme(&theme.item)
|
||||
{
|
||||
return Err(labeled_error(
|
||||
"use `highlight --list-themes` to list all themes",
|
||||
format!("Unknown passed theme {:?}", &theme.item),
|
||||
theme.span,
|
||||
None
|
||||
None,
|
||||
));
|
||||
}
|
||||
let theme = theme.map(|spanned| spanned.item);
|
||||
@ -152,35 +153,35 @@ impl PluginCommand for Highlight {
|
||||
fn examples(&self) -> Vec<Example<'_>> {
|
||||
const fn example<'e>(description: &'e str, example: &'e str) -> Example<'e>
|
||||
where
|
||||
'e: 'static
|
||||
'e: 'static,
|
||||
{
|
||||
Example {
|
||||
example,
|
||||
description,
|
||||
result: None
|
||||
result: None,
|
||||
}
|
||||
}
|
||||
|
||||
vec![
|
||||
example(
|
||||
"Highlight a Markdown file by guessing the type from the pipeline metadata",
|
||||
"open README.md | highlight"
|
||||
"open README.md | highlight",
|
||||
),
|
||||
example(
|
||||
"Highlight a toml file by its file extension",
|
||||
"open Cargo.toml -r | echo $in | highlight toml"
|
||||
"open Cargo.toml -r | echo $in | highlight toml",
|
||||
),
|
||||
example(
|
||||
"Highlight a rust file by programming language",
|
||||
"open src/main.rs | echo $in | highlight Rust"
|
||||
"open src/main.rs | echo $in | highlight Rust",
|
||||
),
|
||||
example(
|
||||
"Highlight a bash script by inferring the language (needs shebang)",
|
||||
"open example.sh | echo $in | highlight"
|
||||
"open example.sh | echo $in | highlight",
|
||||
),
|
||||
example(
|
||||
"Highlight a toml file with another theme",
|
||||
"open Cargo.toml -r | highlight -t ansi"
|
||||
"open Cargo.toml -r | highlight -t ansi",
|
||||
),
|
||||
example("List all available themes", "highlight --list-themes"),
|
||||
]
|
||||
@ -189,7 +190,7 @@ impl PluginCommand for Highlight {
|
||||
|
||||
fn language_hint(
|
||||
call: &EvaluatedCall,
|
||||
metadata: Option<&PipelineMetadata>
|
||||
metadata: Option<&PipelineMetadata>,
|
||||
) -> Result<Option<String>, ShellError> {
|
||||
// first use passed argument
|
||||
let arg = call.opt(0)?.map(String::from_value).transpose()?;
|
||||
@ -206,15 +207,14 @@ fn language_hint(
|
||||
"x-toml" => Some("toml".to_string()),
|
||||
"x-nuscript" | "x-nushell" | "x-nuon" => Some("nushell".to_string()),
|
||||
s if s.starts_with("x-") => None, // we cannot be sure about this type,
|
||||
_ => Some(sub_type)
|
||||
_ => Some(sub_type),
|
||||
}
|
||||
};
|
||||
|
||||
// as last resort, try to use the extension of data source
|
||||
let data_source = || -> Option<String> {
|
||||
let data_source = &metadata?.data_source;
|
||||
let DataSource::FilePath(path) = data_source
|
||||
else {
|
||||
let DataSource::FilePath(path) = data_source else {
|
||||
return None;
|
||||
};
|
||||
let extension = path.extension()?.to_string_lossy();
|
||||
@ -229,20 +229,20 @@ fn labeled_error(
|
||||
msg: impl ToString,
|
||||
label: impl ToString,
|
||||
span: Span,
|
||||
inner: impl Into<Option<ShellError>>
|
||||
inner: impl Into<Option<ShellError>>,
|
||||
) -> LabeledError {
|
||||
LabeledError {
|
||||
msg: msg.to_string(),
|
||||
labels: Box::new(vec![ErrorLabel {
|
||||
text: label.to_string(),
|
||||
span
|
||||
span,
|
||||
}]),
|
||||
code: None,
|
||||
url: None,
|
||||
help: None,
|
||||
inner: match inner.into() {
|
||||
Some(inner) => Box::new(vec![inner.into()]),
|
||||
None => Box::new(vec![])
|
||||
}
|
||||
None => Box::new(vec![]),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ pub struct ThemeDescription {
|
||||
pub id: String,
|
||||
pub name: Option<String>,
|
||||
pub author: Option<String>,
|
||||
pub default: bool
|
||||
pub default: bool,
|
||||
}
|
||||
|
||||
/// List of theme descriptions.
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
# Nushell syntax highlight for sublime text
|
||||
|
||||
- Just copied matlab syntax file and modified it for nushell
|
||||
- Use nushell lsp language server (need lsp sublime package)
|
||||
|
||||
## Installation
|
||||
|
||||
1. In sublime text install the LSP package.
|
||||
2. After cloning and cd-ing into the directory, in nushell run (tested in Ubuntu 20.04):
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
ls
|
||||
| find -v README & export & color
|
||||
| get name
|
||||
@ -14,11 +18,14 @@ ls
|
||||
cp -f $file (~/.config/sublime-text/Packages/User | path expand)
|
||||
}
|
||||
```
|
||||
3. In sublime, open `Preferences > Customize Color Scheme` and add the contents of `sublime-color-scheme`. Modify to your liking.
|
||||
1. In sublime, open `Preferences > Customize Color Scheme` and add the contents of `sublime-color-scheme`. Modify to your liking.
|
||||
|
||||
## Update commands
|
||||
|
||||
If you need to update nushell functions or add your custom commands and aliases, run:
|
||||
```nu
|
||||
|
||||
```nushell
|
||||
nu
|
||||
chmod +x export.nu
|
||||
./export.nu
|
||||
```
|
||||
468
nu_plugin_image/Cargo.lock
generated
468
nu_plugin_image/Cargo.lock
generated
@ -90,12 +90,6 @@ version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
@ -232,7 +226,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"pastey",
|
||||
"rayon",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"v_frame",
|
||||
"y4m",
|
||||
]
|
||||
@ -273,7 +267,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"shlex",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
@ -432,18 +426,17 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.41"
|
||||
version = "0.4.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"pure-rust-locales",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link 0.1.3",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -486,6 +479,7 @@ dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -597,7 +591,7 @@ dependencies = [
|
||||
"document-features",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix 1.0.7",
|
||||
"rustix",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
@ -675,6 +669,17 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doctest-file"
|
||||
version = "1.0.0"
|
||||
@ -768,9 +773,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.16.2"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
|
||||
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"regex-automata",
|
||||
@ -817,10 +822,55 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
name = "fluent"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
checksum = "8137a6d5a2c50d6b0ebfcb9aaa91a28154e0a70605f112d30cb0cd4a78670477"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-bundle"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4"
|
||||
dependencies = [
|
||||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rustc-hash 2.1.1",
|
||||
"self_cell",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-langneg"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eebbe59450baee8282d71676f3bfed5689aeab00b27545e83e5f14b1195e8b0"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fluent-syntax"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
@ -885,9 +935,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.4"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
@ -1033,12 +1083,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.4"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.4",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1054,9 +1104,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "interprocess"
|
||||
version = "2.2.3"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d941b405bd2322993887859a8ee6ac9134945a24ec5ec763a8a962fc64dfec2d"
|
||||
checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69"
|
||||
dependencies = [
|
||||
"doctest-file",
|
||||
"libc",
|
||||
@ -1065,6 +1115,25 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl-memoizer"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
|
||||
dependencies = [
|
||||
"type-map",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intl_pluralrules"
|
||||
version = "7.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
|
||||
dependencies = [
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inventory"
|
||||
version = "0.3.20"
|
||||
@ -1176,9 +1245,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.174"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
@ -1251,12 +1320,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
@ -1296,11 +1359,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.4",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1315,12 +1378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
|
||||
|
||||
[[package]]
|
||||
name = "matrixmultiply"
|
||||
@ -1344,9 +1404,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "miette"
|
||||
@ -1483,9 +1543,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-derive-value"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465d2d3ada6004cb6689f269a08c70ba81056231e2b5392d1e0ccf5825f81cb"
|
||||
checksum = "d71958b54c367bda033f7dcc4a73b61972fb52323f71a1e3533e290fa67148d1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error2",
|
||||
@ -1496,9 +1556,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b777faf7c5180fe5d7f67d83c44fd14138d91f2938a36494ed6ac66b7160f3"
|
||||
checksum = "d41b3e3e2d25c30741a0761856258e22624c0d60064e4f0e12f86202a451d492"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"log",
|
||||
@ -1511,25 +1571,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-experimental"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73dd212a1afdad646a38c00579a0988264880aeb97fee820b349a28cdcc04df2"
|
||||
checksum = "f328fa0531bdf49c2dc0312b40cb780e3d74e0d3dbb15d508469a5ae4cfd8d8f"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15aa2c17078926f14e393b4b708e69f228cb6fd4c81136839bde82772bdde1b5"
|
||||
checksum = "01ee787f61353c9c90581ddf4c0602a07b991cdd06c97dac8b6d323a1a52c43a"
|
||||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde9d8ba26f62c07176c0237a36f38ce964ab3a0dcfb6aab1feea7515d1c6594"
|
||||
checksum = "c01d110cb931acf56237ce572e5b156e8e1134227c90deeffb92eedda9482c23"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"omnipath",
|
||||
@ -1539,9 +1599,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea1fbfd41b2f5c967675fc948831e03be67d91c6b8e18a60f3445113fe6548c"
|
||||
checksum = "c322531b1a7d6338c5ead1f454294f46babf8c99cd4716311cab1e88ba52b154"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
@ -1550,14 +1610,14 @@ dependencies = [
|
||||
"nu-plugin-protocol",
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd2410648c2c38cf9359595ffcf281d9d60a81c0580ff07f7c7d42bed414f3a1"
|
||||
checksum = "38ee792aeb0d37e0ed55ca4304e434eece497914e27ae42616a8bb973f5d2720"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
@ -1566,14 +1626,14 @@ dependencies = [
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27de26da922261dff8103a811879228c55749a1b7b0e573b639c609a0651a01e"
|
||||
checksum = "7725f341428db16dbef4392970de32705abc77ee80a902572c8da811dade3564"
|
||||
dependencies = [
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
@ -1585,9 +1645,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038943300ca9de0924fef1c795a7dd16ffc67105629477cf163e8ee6bad95ea6"
|
||||
checksum = "f1c0e58cbeb46cbfd40156e6f4b9f90e4a77e774ca863fa158867a4726aab1d1"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"bytes",
|
||||
@ -1616,18 +1676,18 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"typetag",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46be734cc9b19e09a9665769e14360e13e6978490056ba5c8bfad7dd0537ea83"
|
||||
checksum = "62fe7847b65edbe362a0fcb67dedfab9fd7370e89c0313f7cb7d0a7ab8f9834b"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.14.0",
|
||||
@ -1639,15 +1699,16 @@ dependencies = [
|
||||
"ntapi",
|
||||
"procfs",
|
||||
"sysinfo",
|
||||
"uucore",
|
||||
"web-time",
|
||||
"windows 0.62.2",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f8eb43c29cc5bce85f87defdadc2cca964fa434d808af37036a7cb78f3c68e9"
|
||||
checksum = "df85a8a4bb28c84d5f7c096c02c859ac454dfac59fd0296ab5eb6ed86619219e"
|
||||
dependencies = [
|
||||
"byteyarn",
|
||||
"crossterm",
|
||||
@ -1668,7 +1729,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_image"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"ansi_colours",
|
||||
@ -1790,18 +1851,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
@ -1831,6 +1892,15 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_display"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad5fd71b79026fb918650dde6d125000a233764f1c2f1659a1c71118e33ea08f"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.2"
|
||||
@ -1982,23 +2052,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "procfs"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f"
|
||||
checksum = "25485360a54d6861439d60facef26de713b1e126bf015ec8f98239467a2b82f7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"hex",
|
||||
"procfs-core",
|
||||
"rustix 0.38.44",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "procfs-core"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
|
||||
checksum = "e6401bf7b6af22f78b563665d15a22e9aef27775b79b149a66ca022468a4e405"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
@ -2026,9 +2095,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
|
||||
checksum = "869675ad2d7541aea90c6d88c81f46a7f4ea9af8cd0395d38f11a95126998a0d"
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
@ -2178,7 +2247,7 @@ dependencies = [
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"simd_helpers",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@ -2247,23 +2316,23 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
|
||||
checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
|
||||
dependencies = [
|
||||
"ref-cast-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ref-cast-impl"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
|
||||
checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2327,11 +2396,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rmp-serde"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db"
|
||||
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"rmp",
|
||||
"serde",
|
||||
]
|
||||
@ -2343,17 +2411,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
@ -2364,7 +2425,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.9.4",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -2395,6 +2456,12 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.26"
|
||||
@ -2433,14 +2500,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
"serde_core",
|
||||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2574,9 +2642,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
@ -2643,16 +2711,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.37.2"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows 0.61.3",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2685,7 +2753,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed"
|
||||
dependencies = [
|
||||
"rustix 1.0.7",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -2710,11 +2778,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2730,9 +2798,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2793,12 +2861,32 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"serde_core",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
version = "1.0.3"
|
||||
@ -2836,10 +2924,28 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.8.1"
|
||||
name = "unic-langid"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
||||
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
|
||||
dependencies = [
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unic-langid-impl"
|
||||
version = "0.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
|
||||
dependencies = [
|
||||
"tinystr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
@ -2877,6 +2983,35 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "uucore"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b157ba598d7f7ed06f6dbc62999edb9d730b4d3fb58e503d8ad6d5fbe1e04391"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"libc",
|
||||
"nix",
|
||||
"os_display",
|
||||
"thiserror 2.0.18",
|
||||
"unic-langid",
|
||||
"uucore_procs",
|
||||
"wild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uucore_procs"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daa291a52608ac5a2f8539e119666e021baa6b8c01f22f02ed201bbae54cbbc0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
@ -3018,6 +3153,15 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1"
|
||||
dependencies = [
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -3049,38 +3193,16 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.61.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||
dependencies = [
|
||||
"windows-collections 0.2.0",
|
||||
"windows-core 0.61.2",
|
||||
"windows-future 0.2.1",
|
||||
"windows-link 0.1.3",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
||||
dependencies = [
|
||||
"windows-collections 0.3.2",
|
||||
"windows-collections",
|
||||
"windows-core 0.62.2",
|
||||
"windows-future 0.3.2",
|
||||
"windows-numerics 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-future",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3118,17 +3240,6 @@ dependencies = [
|
||||
"windows-strings 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
"windows-threading 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.3.2"
|
||||
@ -3137,7 +3248,7 @@ checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-link 0.2.1",
|
||||
"windows-threading 0.2.1",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3174,16 +3285,6 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.3.1"
|
||||
@ -3298,15 +3399,6 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
||||
dependencies = [
|
||||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.2.1"
|
||||
@ -3468,6 +3560,28 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.11.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
|
||||
@ -11,8 +11,8 @@ vte = "0.15.0"
|
||||
lazy_static = "1.5.0"
|
||||
slog-term = "2.9.2"
|
||||
slog-async = "2.8.0"
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
|
||||
[dependencies.clap]
|
||||
features = ["derive"]
|
||||
@ -52,4 +52,4 @@ license = "MIT"
|
||||
name = "nu_plugin_image"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/FMotalleb/nu_plugin_image"
|
||||
version = "0.109.1"
|
||||
version = "0.111.0"
|
||||
|
||||
@ -19,7 +19,8 @@ The `to png` command converts an ANSI string into a PNG image. Customizable font
|
||||
|
||||
#### 📌 Usage
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
> to png {flags} (output-path)
|
||||
```
|
||||
|
||||
@ -55,7 +56,8 @@ The `to png` command converts an ANSI string into a PNG image. Customizable font
|
||||
|
||||
#### 📊 Example: Convert ANSI String to PNG with Custom Theme
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
> to png --theme "xterm" --custom-theme-fg "#FF00FF" --custom-theme-bg "#00000000" output.png
|
||||
```
|
||||
|
||||
@ -67,7 +69,8 @@ The `from png` command converts an image into its corresponding ANSI text repres
|
||||
|
||||
#### 📌 Usage
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
> from png {flags}
|
||||
```
|
||||
|
||||
@ -80,7 +83,8 @@ The `from png` command converts an image into its corresponding ANSI text repres
|
||||
|
||||
#### 📊 Example: Convert PNG Image to ANSI Text
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
> from png --width 80 --height 20 image.png
|
||||
```
|
||||
|
||||
@ -92,14 +96,16 @@ The `from png` command converts an image into its corresponding ANSI text repres
|
||||
|
||||
This method automatically handles dependencies and features.
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_image.git
|
||||
nupm install --path nu_plugin_image -f
|
||||
```
|
||||
|
||||
### 🛠️ Manual Compilation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
git clone https://github.com/FMotalleb/nu_plugin_image.git
|
||||
cd nu_plugin_image
|
||||
cargo build -r
|
||||
@ -108,8 +114,8 @@ plugin add target/release/nu_plugin_image
|
||||
|
||||
### 📦 Install via Cargo (using git)
|
||||
|
||||
```bash
|
||||
```rust
|
||||
bash
|
||||
cargo install --git https://github.com/FMotalleb/nu_plugin_image.git
|
||||
plugin add ~/.cargo/bin/nu_plugin_image
|
||||
```
|
||||
|
||||
|
||||
@ -73,7 +73,9 @@ fn load_u32(call: &EvaluatedCall, flag_name: &str) -> Result<u32, LabeledError>
|
||||
.map_err(|e| make_params_err(e.to_string(), call.head))?;
|
||||
int_val
|
||||
.try_into()
|
||||
.map_err(|err: std::num::TryFromIntError| make_params_err(err.to_string(), call.head))
|
||||
.map_err(|err: std::num::TryFromIntError| {
|
||||
make_params_err(err.to_string(), call.head)
|
||||
})
|
||||
}
|
||||
_ => Err(make_params_err(
|
||||
format!("value of `{flag_name}` is not an integer"),
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 11216da7174f88a7d5b3ce04fea3cd14bcde8d8c
|
||||
Subproject commit 97e7365a5a917cca6559ea8e66063a4242dc2605
|
||||
697
nu_plugin_kms/Cargo.lock
generated
697
nu_plugin_kms/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nu_plugin_kms"
|
||||
version = "0.1.0"
|
||||
version = "0.111.0"
|
||||
authors = ["Jesus Perez <jesus@librecloud.online>"]
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for KMS operations (RustyVault, Age, Cosmian)"
|
||||
@ -8,8 +8,8 @@ repository = "https://github.com/provisioning/nu_plugin_kms"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
rusty_vault = "0.2.1"
|
||||
age = "0.11"
|
||||
base64 = "0.22"
|
||||
@ -32,6 +32,5 @@ default-features = false
|
||||
version = "1.48"
|
||||
features = ["full"]
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.1"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = "0.111.0"
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
[package]
|
||||
name = "nu_plugin_kms"
|
||||
version = "0.1.0"
|
||||
authors = ["Jesus Perez <jesus@librecloud.online>"]
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for KMS operations (RustyVault, Age, Cosmian)"
|
||||
repository = "https://github.com/provisioning/nu_plugin_kms"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = "0.109.1"
|
||||
nu-protocol = "0.109.1"
|
||||
rusty_vault = "0.2.1"
|
||||
age = "0.11"
|
||||
base64 = "0.22"
|
||||
serde_json = "1.0"
|
||||
tempfile = "3.23"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.reqwest]
|
||||
version = "0.12"
|
||||
features = [
|
||||
"json",
|
||||
"rustls-tls",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1.48"
|
||||
features = ["full"]
|
||||
|
||||
[dev-dependencies.nu-plugin-test-support]
|
||||
version = "0.109.0"
|
||||
path = "../nushell/crates/nu-plugin-test-support"
|
||||
@ -18,7 +18,8 @@ Nushell plugin for KMS operations with multiple backends.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
cargo build --release
|
||||
plugin add target/release/nu_plugin_kms
|
||||
```
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -182,7 +182,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_kms_error_with_source() {
|
||||
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "key file not found");
|
||||
let error = KmsError::with_source(KmsErrorKind::KeyNotFound, "failed to load key", io_error);
|
||||
let error =
|
||||
KmsError::with_source(KmsErrorKind::KeyNotFound, "failed to load key", io_error);
|
||||
assert!(error.to_string().contains("caused by"));
|
||||
}
|
||||
|
||||
|
||||
@ -209,7 +209,8 @@ pub fn encrypt_age(data: &[u8], recipient_str: &str) -> Result<String, String> {
|
||||
.parse::<age::x25519::Recipient>()
|
||||
.map_err(|e| format!("Invalid Age recipient: {}", e))?;
|
||||
|
||||
let encryptor = age::Encryptor::with_recipients(std::iter::once(&recipient as &dyn age::Recipient))
|
||||
let encryptor =
|
||||
age::Encryptor::with_recipients(std::iter::once(&recipient as &dyn age::Recipient))
|
||||
.map_err(|_| "Failed to create Age encryptor".to_string())?;
|
||||
|
||||
let mut encrypted = vec![];
|
||||
@ -513,9 +514,7 @@ pub async fn decrypt_aws_kms(_key_id: &str, ciphertext: &str) -> Result<Vec<u8>,
|
||||
.await
|
||||
.map_err(|e| format!("JSON parse error: {}", e))?;
|
||||
|
||||
let plaintext_b64 = result["Plaintext"]
|
||||
.as_str()
|
||||
.ok_or("Missing Plaintext")?;
|
||||
let plaintext_b64 = result["Plaintext"].as_str().ok_or("Missing Plaintext")?;
|
||||
|
||||
general_purpose::STANDARD
|
||||
.decode(plaintext_b64)
|
||||
@ -523,7 +522,10 @@ pub async fn decrypt_aws_kms(_key_id: &str, ciphertext: &str) -> Result<Vec<u8>,
|
||||
}
|
||||
|
||||
/// Generate data key using AWS KMS
|
||||
pub async fn generate_data_key_aws(key_id: &str, key_spec: &str) -> Result<(String, String), String> {
|
||||
pub async fn generate_data_key_aws(
|
||||
key_id: &str,
|
||||
key_spec: &str,
|
||||
) -> Result<(String, String), String> {
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let kms_url = std::env::var("AWS_KMS_ENDPOINT")
|
||||
@ -649,7 +651,10 @@ pub async fn generate_data_key_vault(
|
||||
};
|
||||
|
||||
let response = client
|
||||
.post(format!("{}/v1/transit/datakey/plaintext/{}", addr, key_name))
|
||||
.post(format!(
|
||||
"{}/v1/transit/datakey/plaintext/{}",
|
||||
addr, key_name
|
||||
))
|
||||
.header("X-Vault-Token", token)
|
||||
.json(&serde_json::json!({
|
||||
"bits": bits,
|
||||
@ -685,16 +690,12 @@ pub fn check_backend_available(backend_name: &str) -> bool {
|
||||
"rustyvault" => {
|
||||
std::env::var("RUSTYVAULT_ADDR").is_ok() && std::env::var("RUSTYVAULT_TOKEN").is_ok()
|
||||
}
|
||||
"age" => {
|
||||
std::env::var("AGE_RECIPIENT").is_ok() || std::env::var("AGE_IDENTITY").is_ok()
|
||||
}
|
||||
"age" => std::env::var("AGE_RECIPIENT").is_ok() || std::env::var("AGE_IDENTITY").is_ok(),
|
||||
"aws" => {
|
||||
std::env::var("AWS_ACCESS_KEY_ID").is_ok()
|
||||
&& std::env::var("AWS_SECRET_ACCESS_KEY").is_ok()
|
||||
}
|
||||
"vault" => {
|
||||
std::env::var("VAULT_ADDR").is_ok() && std::env::var("VAULT_TOKEN").is_ok()
|
||||
}
|
||||
"vault" => std::env::var("VAULT_ADDR").is_ok() && std::env::var("VAULT_TOKEN").is_ok(),
|
||||
"cosmian" => std::env::var("KMS_HTTP_URL").is_ok(),
|
||||
_ => false,
|
||||
}
|
||||
|
||||
@ -169,14 +169,15 @@ impl SimplePluginCommand for KmsEncrypt {
|
||||
helpers::encrypt_age(data.as_bytes(), recipient)
|
||||
.map_err(|e| LabeledError::new(e))?
|
||||
}
|
||||
helpers::Backend::AwsKms { ref key_id } => {
|
||||
runtime.block_on(async {
|
||||
helpers::Backend::AwsKms { ref key_id } => runtime.block_on(async {
|
||||
helpers::encrypt_aws_kms(key_id, data.as_bytes())
|
||||
.await
|
||||
.map_err(|e| LabeledError::new(e))
|
||||
})?
|
||||
}
|
||||
helpers::Backend::Vault { ref addr, ref token } => {
|
||||
})?,
|
||||
helpers::Backend::Vault {
|
||||
ref addr,
|
||||
ref token,
|
||||
} => {
|
||||
let key_name = key.unwrap_or_else(|| "provisioning-main".to_string());
|
||||
runtime.block_on(async {
|
||||
helpers::encrypt_vault(addr, token, &key_name, data.as_bytes())
|
||||
@ -321,14 +322,15 @@ impl SimplePluginCommand for KmsDecrypt {
|
||||
})?;
|
||||
helpers::decrypt_age(&encrypted, identity_path).map_err(|e| LabeledError::new(e))?
|
||||
}
|
||||
helpers::Backend::AwsKms { ref key_id } => {
|
||||
runtime.block_on(async {
|
||||
helpers::Backend::AwsKms { ref key_id } => runtime.block_on(async {
|
||||
helpers::decrypt_aws_kms(key_id, &encrypted)
|
||||
.await
|
||||
.map_err(|e| LabeledError::new(e))
|
||||
})?
|
||||
}
|
||||
helpers::Backend::Vault { ref addr, ref token } => {
|
||||
})?,
|
||||
helpers::Backend::Vault {
|
||||
ref addr,
|
||||
ref token,
|
||||
} => {
|
||||
let key_name = key.unwrap_or_else(|| "provisioning-main".to_string());
|
||||
runtime.block_on(async {
|
||||
helpers::decrypt_vault(addr, token, &key_name, &encrypted)
|
||||
@ -463,20 +465,19 @@ impl SimplePluginCommand for KmsGenerateKey {
|
||||
.map(|(secret, public)| (secret, public))
|
||||
.map_err(|e| LabeledError::new(e))?
|
||||
}
|
||||
helpers::Backend::AwsKms { ref key_id } => {
|
||||
runtime.block_on(async {
|
||||
helpers::Backend::AwsKms { ref key_id } => runtime.block_on(async {
|
||||
helpers::generate_data_key_aws(key_id, &key_spec)
|
||||
.await
|
||||
.map_err(|e| LabeledError::new(e))
|
||||
})?
|
||||
}
|
||||
helpers::Backend::Vault { ref addr, ref token } => {
|
||||
runtime.block_on(async {
|
||||
})?,
|
||||
helpers::Backend::Vault {
|
||||
ref addr,
|
||||
ref token,
|
||||
} => runtime.block_on(async {
|
||||
helpers::generate_data_key_vault(addr, token, "provisioning-main", &key_spec)
|
||||
.await
|
||||
.map_err(|e| LabeledError::new(e))
|
||||
})?
|
||||
}
|
||||
})?,
|
||||
helpers::Backend::HttpFallback {
|
||||
ref backend_name,
|
||||
ref url,
|
||||
@ -560,12 +561,8 @@ impl SimplePluginCommand for KmsStatus {
|
||||
format!("recipient: {}, identity: {}", recipient, identity_status),
|
||||
)
|
||||
}
|
||||
helpers::Backend::AwsKms { ref key_id } => {
|
||||
("aws", true, format!("key_id: {}", key_id))
|
||||
}
|
||||
helpers::Backend::Vault { ref addr, .. } => {
|
||||
("vault", true, format!("addr: {}", addr))
|
||||
}
|
||||
helpers::Backend::AwsKms { ref key_id } => ("aws", true, format!("key_id: {}", key_id)),
|
||||
helpers::Backend::Vault { ref addr, .. } => ("vault", true, format!("addr: {}", addr)),
|
||||
helpers::Backend::HttpFallback {
|
||||
ref backend_name,
|
||||
ref url,
|
||||
@ -624,11 +621,31 @@ impl SimplePluginCommand for KmsListBackends {
|
||||
_input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
let backends = vec![
|
||||
("rustyvault", "RustyVault Transit backend", "RUSTYVAULT_ADDR, RUSTYVAULT_TOKEN"),
|
||||
("age", "Age file-based encryption", "AGE_RECIPIENT, AGE_IDENTITY"),
|
||||
("aws", "AWS Key Management Service", "AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION"),
|
||||
("vault", "HashiCorp Vault Transit", "VAULT_ADDR, VAULT_TOKEN"),
|
||||
("cosmian", "Cosmian privacy-preserving encryption", "KMS_HTTP_URL"),
|
||||
(
|
||||
"rustyvault",
|
||||
"RustyVault Transit backend",
|
||||
"RUSTYVAULT_ADDR, RUSTYVAULT_TOKEN",
|
||||
),
|
||||
(
|
||||
"age",
|
||||
"Age file-based encryption",
|
||||
"AGE_RECIPIENT, AGE_IDENTITY",
|
||||
),
|
||||
(
|
||||
"aws",
|
||||
"AWS Key Management Service",
|
||||
"AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION",
|
||||
),
|
||||
(
|
||||
"vault",
|
||||
"HashiCorp Vault Transit",
|
||||
"VAULT_ADDR, VAULT_TOKEN",
|
||||
),
|
||||
(
|
||||
"cosmian",
|
||||
"Cosmian privacy-preserving encryption",
|
||||
"KMS_HTTP_URL",
|
||||
),
|
||||
];
|
||||
|
||||
let backend_values: Vec<Value> = backends
|
||||
|
||||
@ -24,11 +24,26 @@ fn test_kms_error_with_source() {
|
||||
|
||||
#[test]
|
||||
fn test_kms_error_kind_display() {
|
||||
assert_eq!(KmsErrorKind::BackendNotAvailable.to_string(), "backend not available");
|
||||
assert_eq!(KmsErrorKind::EncryptionFailed.to_string(), "encryption failed");
|
||||
assert_eq!(KmsErrorKind::DecryptionFailed.to_string(), "decryption failed");
|
||||
assert_eq!(KmsErrorKind::KeyGenerationFailed.to_string(), "key generation failed");
|
||||
assert_eq!(KmsErrorKind::InvalidKeySpec.to_string(), "invalid key specification");
|
||||
assert_eq!(
|
||||
KmsErrorKind::BackendNotAvailable.to_string(),
|
||||
"backend not available"
|
||||
);
|
||||
assert_eq!(
|
||||
KmsErrorKind::EncryptionFailed.to_string(),
|
||||
"encryption failed"
|
||||
);
|
||||
assert_eq!(
|
||||
KmsErrorKind::DecryptionFailed.to_string(),
|
||||
"decryption failed"
|
||||
);
|
||||
assert_eq!(
|
||||
KmsErrorKind::KeyGenerationFailed.to_string(),
|
||||
"key generation failed"
|
||||
);
|
||||
assert_eq!(
|
||||
KmsErrorKind::InvalidKeySpec.to_string(),
|
||||
"invalid key specification"
|
||||
);
|
||||
assert_eq!(KmsErrorKind::NetworkError.to_string(), "network error");
|
||||
}
|
||||
|
||||
@ -71,10 +86,7 @@ fn test_backend_new_age_invalid() {
|
||||
fn test_backend_http_fallback() {
|
||||
let backend = helpers::Backend::new_http_fallback("cosmian", "http://localhost:8081");
|
||||
match backend {
|
||||
helpers::Backend::HttpFallback {
|
||||
backend_name,
|
||||
url,
|
||||
} => {
|
||||
helpers::Backend::HttpFallback { backend_name, url } => {
|
||||
assert_eq!(backend_name, "cosmian");
|
||||
assert_eq!(url, "http://localhost:8081");
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
|
||||
### 1. Verify Binary Exists
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
cd /Users/Akasha/project-provisioning/provisioning/core/plugins/nushell-plugins/nu_plugin_kms
|
||||
|
||||
# Check binary exists
|
||||
@ -19,7 +20,8 @@ ls -lh target/release/nu_plugin_kms
|
||||
|
||||
### 2. Register Plugin with Nushell
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Register plugin
|
||||
nu -c "plugin add target/release/nu_plugin_kms"
|
||||
|
||||
@ -35,7 +37,8 @@ nu -c "plugin list | where name =~ kms"
|
||||
|
||||
### 3. Test Plugin Help
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Check command help
|
||||
nu -c "kms encrypt --help"
|
||||
nu -c "kms decrypt --help"
|
||||
@ -49,7 +52,8 @@ nu -c "kms status --help"
|
||||
|
||||
#### Setup
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Install Age (if not already installed)
|
||||
brew install age # macOS
|
||||
# or
|
||||
@ -68,7 +72,8 @@ echo "Age Identity: $AGE_IDENTITY"
|
||||
|
||||
#### Test Encryption
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 1: Encrypt with Age
|
||||
nu -c "kms encrypt 'Hello, Age!' --backend age --key $AGE_RECIPIENT" > /tmp/encrypted.txt
|
||||
|
||||
@ -80,7 +85,8 @@ cat /tmp/encrypted.txt
|
||||
|
||||
#### Test Decryption
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 2: Decrypt with Age
|
||||
nu -c "kms decrypt '$(cat /tmp/encrypted.txt)' --backend age --key $AGE_IDENTITY"
|
||||
|
||||
@ -89,7 +95,8 @@ nu -c "kms decrypt '$(cat /tmp/encrypted.txt)' --backend age --key $AGE_IDENTITY
|
||||
|
||||
#### Test Key Generation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 3: Generate new Age key pair
|
||||
nu -c "kms generate-key --backend age"
|
||||
|
||||
@ -102,7 +109,8 @@ nu -c "kms generate-key --backend age"
|
||||
|
||||
#### Test Auto-Detection
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 4: Auto-detect Age backend
|
||||
nu -c "kms status"
|
||||
|
||||
@ -118,7 +126,8 @@ nu -c "kms status"
|
||||
|
||||
#### Setup
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Start RustyVault in Docker
|
||||
docker run -d --name rustyvault \
|
||||
-p 8200:8200 \
|
||||
@ -143,7 +152,8 @@ docker exec rustyvault \
|
||||
|
||||
#### Test Encryption
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 1: Encrypt with RustyVault
|
||||
nu -c "kms encrypt 'Secret data!' --backend rustyvault --key provisioning-main"
|
||||
|
||||
@ -152,7 +162,8 @@ nu -c "kms encrypt 'Secret data!' --backend rustyvault --key provisioning-main"
|
||||
|
||||
#### Test Decryption
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 2: Encrypt and then decrypt
|
||||
ENCRYPTED=$(nu -c "kms encrypt 'RustyVault test' --backend rustyvault --key provisioning-main")
|
||||
|
||||
@ -163,7 +174,8 @@ nu -c "kms decrypt '$ENCRYPTED' --backend rustyvault --key provisioning-main"
|
||||
|
||||
#### Test Key Generation
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 3: Generate AES256 data key
|
||||
nu -c "kms generate-key --backend rustyvault --spec AES256"
|
||||
|
||||
@ -176,7 +188,8 @@ nu -c "kms generate-key --backend rustyvault --spec AES256"
|
||||
|
||||
#### Test Status
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 4: Check RustyVault status
|
||||
nu -c "kms status"
|
||||
|
||||
@ -190,7 +203,8 @@ nu -c "kms status"
|
||||
|
||||
#### Cleanup
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Stop and remove RustyVault container
|
||||
docker stop rustyvault
|
||||
docker rm rustyvault
|
||||
@ -200,7 +214,8 @@ docker rm rustyvault
|
||||
|
||||
#### Setup (Mock Server)
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Create simple mock KMS server with Python
|
||||
cat > /tmp/mock_kms_server.py << 'EOF'
|
||||
#!/usr/bin/env python3
|
||||
@ -262,7 +277,8 @@ export KMS_HTTP_BACKEND="mock"
|
||||
|
||||
#### Test HTTP Backend
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 1: Encrypt
|
||||
nu -c "kms encrypt 'HTTP test data' --backend mock"
|
||||
|
||||
@ -279,7 +295,8 @@ nu -c "kms status"
|
||||
|
||||
#### Cleanup
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Stop mock server
|
||||
kill $MOCK_SERVER_PID
|
||||
```
|
||||
@ -288,7 +305,8 @@ kill $MOCK_SERVER_PID
|
||||
|
||||
### Test Auto-Detection Priority
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 1: RustyVault has priority
|
||||
export RUSTYVAULT_ADDR="http://localhost:8200"
|
||||
export RUSTYVAULT_TOKEN="test-token"
|
||||
@ -313,7 +331,8 @@ nu -c "kms status"
|
||||
|
||||
### Test Error Handling
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test 1: Missing required flags
|
||||
nu -c "kms encrypt 'data' --backend age"
|
||||
# Expected: Error about missing --key recipient
|
||||
@ -334,7 +353,8 @@ nu -c "kms generate-key --backend rustyvault --spec INVALID"
|
||||
|
||||
### Test Binary Data
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Test handling of non-UTF8 data
|
||||
dd if=/dev/urandom bs=1024 count=1 | base64 > /tmp/random.b64
|
||||
|
||||
@ -356,7 +376,8 @@ fi
|
||||
|
||||
### Age Performance
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Benchmark encryption (1000 iterations)
|
||||
time for i in {1..1000}; do
|
||||
nu -c "kms encrypt 'test data' --backend age --key $AGE_RECIPIENT" > /dev/null
|
||||
@ -367,7 +388,8 @@ done
|
||||
|
||||
### RustyVault Performance
|
||||
|
||||
```bash
|
||||
```rust
|
||||
bash
|
||||
# Benchmark encryption (1000 iterations)
|
||||
time for i in {1..1000}; do
|
||||
nu -c "kms encrypt 'test data' --backend rustyvault --key provisioning-main" > /dev/null
|
||||
@ -378,7 +400,8 @@ done
|
||||
|
||||
### Memory Usage
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Monitor memory during operations
|
||||
while true; do
|
||||
nu -c "kms encrypt 'test data' --backend age --key $AGE_RECIPIENT" > /dev/null
|
||||
@ -392,17 +415,20 @@ done
|
||||
## Verification Checklist
|
||||
|
||||
### Compilation
|
||||
|
||||
- [x] `cargo check` passes
|
||||
- [x] `cargo build --release` succeeds
|
||||
- [x] Binary created in `target/release/nu_plugin_kms`
|
||||
- [x] File size reasonable (< 50MB)
|
||||
|
||||
### Plugin Registration
|
||||
|
||||
- [ ] Plugin registers with Nushell
|
||||
- [ ] All 4 commands visible in `plugin list`
|
||||
- [ ] Help text accessible for each command
|
||||
|
||||
### Age Backend
|
||||
|
||||
- [ ] Encryption works with recipient
|
||||
- [ ] Decryption works with identity file
|
||||
- [ ] Key generation produces valid key pair
|
||||
@ -410,6 +436,7 @@ done
|
||||
- [ ] Auto-detection works when env vars set
|
||||
|
||||
### RustyVault Backend
|
||||
|
||||
- [ ] Encryption works with Transit engine
|
||||
- [ ] Decryption works correctly
|
||||
- [ ] Data key generation works
|
||||
@ -417,6 +444,7 @@ done
|
||||
- [ ] Auto-detection works when env vars set
|
||||
|
||||
### HTTP Fallback
|
||||
|
||||
- [ ] Encryption works with HTTP service
|
||||
- [ ] Decryption works correctly
|
||||
- [ ] Data key generation works
|
||||
@ -424,12 +452,14 @@ done
|
||||
- [ ] Auto-detection works as fallback
|
||||
|
||||
### Error Handling
|
||||
|
||||
- [ ] Missing flags produce clear errors
|
||||
- [ ] Invalid inputs rejected gracefully
|
||||
- [ ] Network errors handled properly
|
||||
- [ ] Missing env vars reported clearly
|
||||
|
||||
### Integration
|
||||
|
||||
- [ ] Auto-detection priority correct
|
||||
- [ ] Multiple backends can coexist
|
||||
- [ ] Environment switching works
|
||||
@ -438,21 +468,25 @@ done
|
||||
## Success Criteria
|
||||
|
||||
✅ **Basic Functionality**
|
||||
|
||||
- All backends encrypt and decrypt successfully
|
||||
- Key generation works for all backends
|
||||
- Status command reports correctly
|
||||
|
||||
✅ **Robustness**
|
||||
|
||||
- Error messages are clear and actionable
|
||||
- No panics or crashes
|
||||
- Memory usage is stable
|
||||
|
||||
✅ **Performance**
|
||||
|
||||
- Operations complete in reasonable time
|
||||
- No memory leaks
|
||||
- Concurrent operations work
|
||||
|
||||
✅ **Usability**
|
||||
|
||||
- Auto-detection works as expected
|
||||
- Environment configuration is straightforward
|
||||
- Help text is clear
|
||||
@ -461,7 +495,8 @@ done
|
||||
|
||||
### Plugin Not Loading
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Check plugin is registered
|
||||
nu -c "plugin list" | grep kms
|
||||
|
||||
@ -474,7 +509,8 @@ nu -c "plugin list --version"
|
||||
|
||||
### Environment Variables Not Working
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Check env vars are set
|
||||
env | grep -E '(RUSTYVAULT|AGE|KMS)'
|
||||
|
||||
@ -484,7 +520,8 @@ bash -c 'export AGE_RECIPIENT=...; nu -c "kms status"'
|
||||
|
||||
### Compilation Errors
|
||||
|
||||
```bash
|
||||
```nushell
|
||||
bash
|
||||
# Clean build
|
||||
cargo clean
|
||||
|
||||
|
||||
2242
nu_plugin_mcp/Cargo.lock
generated
Normal file
2242
nu_plugin_mcp/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
27
nu_plugin_mcp/Cargo.toml
Normal file
27
nu_plugin_mcp/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[[bin]]
|
||||
name = "nu_plugin_mcp"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "nu_plugin_mcp"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package]
|
||||
name = "nu_plugin_mcp"
|
||||
version = "0.111.0"
|
||||
edition = "2021"
|
||||
description = "Nushell plugin for MCP server interaction — connect, discover, and call provisioning tools"
|
||||
authors = ["Provisioning Team"]
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
thiserror = "2.0"
|
||||
interprocess = "^2.3.1"
|
||||
nu-plugin = "0.111.0"
|
||||
nu-protocol = "0.111.0"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
12
nu_plugin_mcp/examples/iac_validate.nu
Normal file
12
nu_plugin_mcp/examples/iac_validate.nu
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env nu
|
||||
# Validate infrastructure config via MCP and display results
|
||||
|
||||
mcp connect provisioning-mcp-server --provisioning-path /opt/provisioning
|
||||
|
||||
let result = mcp tool call guidance_validate_config_file --payload {
|
||||
config_path: "provisioning/config/workspace.ncl"
|
||||
}
|
||||
|
||||
print $result
|
||||
|
||||
mcp disconnect
|
||||
12
nu_plugin_mcp/examples/rag_search.nu
Normal file
12
nu_plugin_mcp/examples/rag_search.nu
Normal file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env nu
|
||||
# Search provisioning documentation via RAG
|
||||
|
||||
mcp connect provisioning-mcp-server --provisioning-path /opt/provisioning
|
||||
|
||||
let docs = mcp tool call guidance_find_docs --payload {
|
||||
query: "nickel validation type-safe configuration"
|
||||
}
|
||||
|
||||
print $docs
|
||||
|
||||
mcp disconnect
|
||||
8
nu_plugin_mcp/examples/tool_discovery.nu
Normal file
8
nu_plugin_mcp/examples/tool_discovery.nu
Normal file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env nu
|
||||
# Discover all available MCP tools and display as a table
|
||||
|
||||
mcp connect provisioning-mcp-server --provisioning-path /opt/provisioning
|
||||
|
||||
mcp tools list | select name description | sort-by name | table
|
||||
|
||||
mcp disconnect
|
||||
192
nu_plugin_mcp/src/commands/call.rs
Normal file
192
nu_plugin_mcp/src/commands/call.rs
Normal file
@ -0,0 +1,192 @@
|
||||
use crate::McpPlugin;
|
||||
use nu_plugin::{EvaluatedCall, SimplePluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, Example, LabeledError, Record, Signature, Span, SyntaxShape, Type, Value,
|
||||
};
|
||||
use serde_json::Value as Json;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct McpToolCall;
|
||||
|
||||
impl SimplePluginCommand for McpToolCall {
|
||||
type Plugin = McpPlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"mcp tool call"
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Call a tool on the connected MCP server"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mcp tool call")
|
||||
.input_output_type(Type::Nothing, Type::Any)
|
||||
.required(
|
||||
"name",
|
||||
SyntaxShape::String,
|
||||
"Tool name (e.g. provision_status)",
|
||||
)
|
||||
.named(
|
||||
"payload",
|
||||
SyntaxShape::Record(vec![]),
|
||||
"Arguments to pass to the tool as a record",
|
||||
Some('a'),
|
||||
)
|
||||
.category(Category::Custom("provisioning".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example<'_>> {
|
||||
vec![
|
||||
Example {
|
||||
example: "mcp tool call provision_status",
|
||||
description: "Get provisioning infrastructure status",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "mcp tool call provision_query --payload {query: \"list all servers\"}",
|
||||
description: "Query infrastructure using natural language",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example:
|
||||
"mcp tool call guidance_find_docs --payload {query: \"nickel validation\"}",
|
||||
description: "Find relevant documentation",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
plugin: &McpPlugin,
|
||||
_engine: &nu_plugin::EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
_input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
let tool_name: String = call.req(0)?;
|
||||
let payload_val: Option<Value> = call.get_flag("payload")?;
|
||||
let span = call.head;
|
||||
|
||||
let arguments = match payload_val {
|
||||
Some(v) => nu_record_to_json(&v)
|
||||
.map_err(|e| LabeledError::new(format!("payload conversion: {e}")))?,
|
||||
None => Json::Object(Default::default()),
|
||||
};
|
||||
|
||||
let mut guard = plugin
|
||||
.session
|
||||
.lock()
|
||||
.map_err(|_| LabeledError::new("session mutex poisoned"))?;
|
||||
let session = guard
|
||||
.as_mut()
|
||||
.ok_or_else(|| LabeledError::new("not connected — run `mcp connect <binary>` first"))?;
|
||||
|
||||
let result = session
|
||||
.tool_call(&tool_name, arguments)
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
Ok(mcp_result_to_nu(result, span))
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert MCP tool result to a Nu value.
|
||||
/// MCP spec: result = { content: [{type: "text", text: "..."}, ...], isError?: bool }
|
||||
fn mcp_result_to_nu(result: Json, span: Span) -> Value {
|
||||
let is_error = result
|
||||
.get("isError")
|
||||
.and_then(|v| v.as_bool())
|
||||
.unwrap_or(false);
|
||||
|
||||
let text = result
|
||||
.get("content")
|
||||
.and_then(|c| c.as_array())
|
||||
.and_then(|arr| arr.first())
|
||||
.and_then(|item| item.get("text"))
|
||||
.and_then(|t| t.as_str())
|
||||
.unwrap_or("")
|
||||
.to_owned();
|
||||
|
||||
if is_error {
|
||||
let mut rec = Record::new();
|
||||
rec.push("error", Value::bool(true, span));
|
||||
rec.push("message", Value::string(text, span));
|
||||
Value::record(rec, span)
|
||||
} else {
|
||||
// Try to parse text as JSON for richer output; fall back to plain string
|
||||
if let Ok(json_val) = serde_json::from_str::<Json>(&text) {
|
||||
json_to_nu_value(json_val, span)
|
||||
} else {
|
||||
Value::string(text, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn json_to_nu_value(v: Json, span: Span) -> Value {
|
||||
match v {
|
||||
Json::Null => Value::nothing(span),
|
||||
Json::Bool(b) => Value::bool(b, span),
|
||||
Json::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
Value::int(i, span)
|
||||
} else {
|
||||
Value::float(n.as_f64().unwrap_or(0.0), span)
|
||||
}
|
||||
}
|
||||
Json::String(s) => Value::string(s, span),
|
||||
Json::Array(arr) => {
|
||||
let vals = arr.into_iter().map(|v| json_to_nu_value(v, span)).collect();
|
||||
Value::list(vals, span)
|
||||
}
|
||||
Json::Object(map) => {
|
||||
let mut rec = Record::new();
|
||||
for (k, v) in map {
|
||||
rec.push(k, json_to_nu_value(v, span));
|
||||
}
|
||||
Value::record(rec, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn nu_record_to_json(val: &Value) -> Result<Json, String> {
|
||||
match val {
|
||||
Value::Nothing { .. } => Ok(Json::Object(Default::default())),
|
||||
Value::Record { val, .. } => {
|
||||
let mut map = serde_json::Map::new();
|
||||
for (k, v) in val.iter() {
|
||||
map.insert(k.to_owned(), nu_value_to_json(v)?);
|
||||
}
|
||||
Ok(Json::Object(map))
|
||||
}
|
||||
_ => Err(format!(
|
||||
"payload must be a record, got {:?}",
|
||||
val.get_type()
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn nu_value_to_json(val: &Value) -> Result<Json, String> {
|
||||
match val {
|
||||
Value::Nothing { .. } => Ok(Json::Null),
|
||||
Value::Bool { val, .. } => Ok(Json::Bool(*val)),
|
||||
Value::Int { val, .. } => Ok(Json::Number((*val).into())),
|
||||
Value::Float { val, .. } => serde_json::Number::from_f64(*val)
|
||||
.map(Json::Number)
|
||||
.ok_or_else(|| format!("non-finite float: {val}")),
|
||||
Value::String { val, .. } => Ok(Json::String(val.clone())),
|
||||
Value::List { vals, .. } => {
|
||||
let arr: Result<Vec<_>, _> = vals.iter().map(nu_value_to_json).collect();
|
||||
Ok(Json::Array(arr?))
|
||||
}
|
||||
Value::Record { val, .. } => {
|
||||
let mut map = serde_json::Map::new();
|
||||
for (k, v) in val.iter() {
|
||||
map.insert(k.to_owned(), nu_value_to_json(v)?);
|
||||
}
|
||||
Ok(Json::Object(map))
|
||||
}
|
||||
other => Ok(Json::String(
|
||||
other.to_expanded_string(", ", &Default::default()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
91
nu_plugin_mcp/src/commands/connect.rs
Normal file
91
nu_plugin_mcp/src/commands/connect.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::session::McpSession;
|
||||
use crate::McpPlugin;
|
||||
use nu_plugin::{EvaluatedCall, SimplePluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, Example, LabeledError, Record, Signature, Span, SyntaxShape, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct McpConnect;
|
||||
|
||||
impl SimplePluginCommand for McpConnect {
|
||||
type Plugin = McpPlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"mcp connect"
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Connect to an MCP server by spawning a binary as a child process"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mcp connect")
|
||||
.input_output_type(Type::Nothing, Type::Record(vec![].into()))
|
||||
.required(
|
||||
"binary",
|
||||
SyntaxShape::String,
|
||||
"Path to the MCP server binary or command name on PATH",
|
||||
)
|
||||
.named(
|
||||
"provisioning-path",
|
||||
SyntaxShape::Filepath,
|
||||
"Set PROVISIONING_PATH env var for the spawned server",
|
||||
Some('p'),
|
||||
)
|
||||
.category(Category::Custom("provisioning".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example<'_>> {
|
||||
vec![
|
||||
Example {
|
||||
example: "mcp connect provisioning-mcp-server",
|
||||
description: "Connect to the provisioning MCP server on PATH",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "mcp connect ./target/release/provisioning-mcp-server --provisioning-path /opt/provisioning",
|
||||
description: "Connect with explicit provisioning path",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
plugin: &McpPlugin,
|
||||
_engine: &nu_plugin::EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
_input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
let binary: String = call.req(0)?;
|
||||
let provisioning_path: Option<String> = call.get_flag("provisioning-path")?;
|
||||
let span = call.head;
|
||||
|
||||
let mut guard = plugin
|
||||
.session
|
||||
.lock()
|
||||
.map_err(|_| LabeledError::new("session mutex poisoned"))?;
|
||||
|
||||
if guard.is_some() {
|
||||
return Err(LabeledError::new(
|
||||
"already connected — run `mcp disconnect` before reconnecting",
|
||||
));
|
||||
}
|
||||
|
||||
let session = McpSession::connect(&binary, provisioning_path.as_deref())
|
||||
.map_err(|e| LabeledError::new(e.to_string()))?;
|
||||
|
||||
*guard = Some(session);
|
||||
drop(guard);
|
||||
|
||||
Ok(connected_record(&binary, span))
|
||||
}
|
||||
}
|
||||
|
||||
fn connected_record(binary: &str, span: Span) -> Value {
|
||||
let mut rec = Record::new();
|
||||
rec.push("status", Value::string("connected", span));
|
||||
rec.push("binary", Value::string(binary, span));
|
||||
Value::record(rec, span)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user