# Plugin Development

Developing Nushell plugins for performance-critical operations in the Provisioning platform.

## Plugin Overview

Nushell plugins provide 10-50x performance improvement over HTTP APIs through native Rust implementations.

### Available Plugins

| Plugin | Purpose | Performance Gain | Language |
| ------ | ------- | ---------------- | -------- |
| nu_plugin_auth | Authentication and OS keyring | 5x faster | Rust |
| nu_plugin_kms | KMS encryption operations | 10x faster | Rust |
| nu_plugin_orchestrator | Orchestrator queries | 30x faster | Rust |

## Plugin Architecture

Plugins communicate with Nushell via MessagePack protocol:

```text
Nushell ←→ MessagePack ←→ Plugin Process
  ↓                           ↓
Script                    Native Rust
```

## Creating a Plugin

### Plugin Template

Generate plugin scaffold:

```bash
# Create new plugin
cargo new --lib nu_plugin_myfeature
cd nu_plugin_myfeature
```

Add dependencies to `Cargo.toml`:

```toml
[package]
name = "nu_plugin_myfeature"
version = "0.1.0"
edition = "2021"

[dependencies]
nu-plugin = "0.109.0"
nu-protocol = "0.109.0"
serde = {version = "1.0", features = ["derive"]}
```

### Plugin Implementation

Implement plugin interface:

```rust
// src/lib.rs
use nu_plugin::{EvaluatedCall, LabeledError, Plugin};
use nu_protocol::{Category, PluginSignature, SyntaxShape, Type, Value};

pub struct MyFeaturePlugin;

impl Plugin for MyFeaturePlugin {
    fn signature(&self) -> Vec<PluginSignature> {
        vec![
            PluginSignature::build("my-feature")
                .usage("Perform my feature operation")
                .required("input", SyntaxShape::String, "input value")
                .input_output_type(Type::String, Type::String)
                .category(Category::Custom("provisioning".into())),
        ]
    }

    fn run(
        &mut self,
        name: &str,
        call: &EvaluatedCall,
        input: &Value,
    ) -> Result<Value, LabeledError> {
        match name {
            "my-feature" => self.my_feature(call, input),
            _ => Err(LabeledError {
                label: "Unknown command".into(),
                msg: format!("Unknown command: {}", name),
                span: None,
            }),
        }
    }
}

impl MyFeaturePlugin {
    fn my_feature(&self, call: &EvaluatedCall, _input: &Value) -> Result<Value, LabeledError> {
        let input: String = call.req(0)?;

        // Perform operation
        let result = perform_operation(&input);

        Ok(Value::string(result, call.head))
    }
}

fn perform_operation(input: &str) -> String {
    // Your implementation here
    format!("Processed: {}", input)
}

// Plugin entry point
fn main() {
    nu_plugin::serve_plugin(&mut MyFeaturePlugin, nu_plugin::MsgPackSerializer {})
}
```

### Building Plugin

```bash
# Build release version
cargo build --release

# Install plugin
nu -c 'plugin add target/release/nu_plugin_myfeature'
nu -c 'plugin use myfeature'

# Test plugin
nu -c 'my-feature "test input"'
```

## Plugin Performance Optimization

### Benchmarking

```rust
use std::time::Instant;

pub fn benchmark_operation() {
    let start = Instant::now();

    // Operation to benchmark
    perform_expensive_operation();

    let duration = start.elapsed();
    eprintln!("Operation took: {:?}", duration);
}
```

### Caching

Implement caching for expensive operations:

```rust
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

pub struct CachedPlugin {
    cache: Arc<Mutex<HashMap<String, String>>>,
}

impl CachedPlugin {
    fn get_or_compute(&self, key: &str) -> String {
        let mut cache = self.cache.lock().unwrap();

        if let Some(value) = cache.get(key) {
            return value.clone();
        }

        let value = expensive_computation(key);
        cache.insert(key.to_string(), value.clone());
        value
    }
}
```

## Testing Plugins

### Unit Tests

```rust
#[cfg(test)]
mod tests {
    use super::*;
    use nu_protocol::{Span, Value};

    #[test]
    fn test_my_feature() {
        let plugin = MyFeaturePlugin;
        let input = Value::string("test", Span::test_data());
        let result = plugin.my_feature(&mock_call(), &input).unwrap();

        assert_eq!(result.as_string().unwrap(), "Processed: test");
    }

    fn mock_call() -> EvaluatedCall {
        // Mock EvaluatedCall for testing
        todo!()
    }
}
```

### Integration Tests

```nushell
# tests/test_plugin.nu
use std assert

def test_plugin_functionality [] {
    let result = my-feature "test input"
    assert equal $result "Processed: test input"
}

def main [] {
    test_plugin_functionality
    print "Plugin tests passed"
}
```

## Plugin Best Practices

- Keep plugin logic focused and single-purpose
- Minimize dependencies to reduce binary size
- Use async operations for I/O-bound tasks
- Implement proper error handling
- Document all plugin commands
- Version plugins with semantic versioning
- Provide fallback to HTTP API if plugin unavailable
- Cache expensive computations
- Profile and benchmark performance improvements

## Related Documentation

- [Build System](build-system.md) - Building Rust plugins
- [Extension Development](extension-development.md) - Extension basics
- [Testing](testing.md) - Testing strategies
