mcpField
N
nushell-plugin-builder

nushell-plugin-builder

github.com/ypares开发3045 次安装今天更新
代码仓库

关于 nushell-plugin-builder

Nushell Plugin Builder 是面向 Rust 开发者的技能,用于创建扩展 Nushell 命令和数据处理能力的插件。它涵盖命令定义、流式处理、序列化、测试及安装流程。

主要功能

  1. 01脚手架生成插件项目
  2. 02定义命令签名与参数
  3. 03支持值处理和流式处理
  4. 04选择 MsgPack 或 JSON 序列化
  5. 05提供测试与调试指导

适用场景

  1. 01创建 Nushell 自定义命令
  2. 02构建处理大型数据集的流式插件
  3. 03开发访问 HTTP API 或文件系统的插件
  4. 04测试并注册 Rust 插件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ypares/agent-skills --skill nushell-plugin-builder

安装后在 Claude Code 中输入/nushell-plugin-builder确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/plugin-template/
.gitignore
Cargo.toml
README.md
assets/plugin-template/src/
main.rs
references/
advanced-features.md
examples.md
plugin-protocol.md
testing-debugging.md
scripts/
init_plugin.py

详细介绍

Nushell 插件构建器

概述

此技能可帮助你使用 Rust 创建 Nushell 插件。插件是独立的可执行文件,可通过自定义命令、数据转换和集成扩展 Nushell。

快速入门

1. 创建插件项目
cargo new nu_plugin_<name>
cd nu_plugin_<name>
cargo add nu-plugin nu-protocol
2. 插件基本结构
use nu_plugin::{EvaluatedCall, MsgPackSerializer, serve_plugin};
use nu_plugin::{EngineInterface, Plugin, PluginCommand, SimplePluginCommand};
use nu_protocol::{LabeledError, Signature, Type, Value};

struct MyPlugin;

impl Plugin for MyPlugin {
    fn version(&self) -> String {
        env!("CARGO_PKG_VERSION").into()
    }

    fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
        vec![Box::new(MyCommand)]
    }
}

struct MyCommand;

impl SimplePluginCommand for MyCommand {
    type Plugin = MyPlugin;

    fn name(&self) -> &str {
        "my-command"
    }

    fn signature(&self) -> Signature {
        Signature::build("my-command")
            .input_output_type(Type::String, Type::Int)
    }

    fn run(
        &self,
        _plugin: &MyPlugin,
        _engine: &EngineInterface,
        call: &EvaluatedCall,
        input: &Value,
    ) -> Result<Value, LabeledError> {
        match input {
            Value::String { val, .. } => {
                Ok(Value::int(val.len() as i64, call.head))
            }
            _ => Err(LabeledError::new("Expected string input")
                .with_label("requires string", call.head))
        }
    }
}

fn main() {
    serve_plugin(&MyPlugin, MsgPackSerializer)
}
3. 构建和安装
# Build
cargo build --release

# Install to cargo bin
cargo install --path . --locked

# Register with nushell
plugin add ~/.cargo/bin/nu_plugin_<name>  # Add .exe on Windows
plugin use <name>

# Test
"hello" | my-command

命令类型

SimplePluginCommand

用于处理单个值的命令:

  • 输入:&Value
  • 输出:Result<Value, LabeledError>
  • 适用于:转换、简单筛选、单值操作
PluginCommand

用于处理流的命令:

  • 输入:PipelineData
  • 输出:Result<PipelineData, LabeledError>
  • 适用于:流式转换、惰性处理、大型数据集

有关流式处理示例,请参阅 references/advanced-features.md。

定义命令签名

输入与输出类型
use nu_protocol::{Signature, Type};

Signature::build("my-command")
    .input_output_type(Type::String, Type::Int)

常见类型:String、Int、Float、Bool、List(Box<Type>)、Record(...)、Any

参数
Signature::build("my-command")
    // Named flags
    .named("output", SyntaxShape::Filepath, "output file", Some('o'))
    .switch("verbose", "enable verbose output", Some('v'))
    // Positional arguments
    .required("input", SyntaxShape::String, "input value")
    .optional("count", SyntaxShape::Int, "repeat count")
    .rest("files", SyntaxShape::Filepath, "files to process")
访问参数
fn run(&self, call: &EvaluatedCall, ...) -> Result<Value, LabeledError> {
    let output: Option<String> = call.get_flag("output")?;
    let verbose: bool = call.has_flag("verbose")?;
    let input: String = call.req(0)?;  // First positional
    let count: Option<i64> = call.opt(1)?;  // Second positional
    let files: Vec<String> = call.rest(2)?;  // Remaining args
}

错误处理

始终返回包含跨度信息的 LabeledError:

Err(LabeledError::new("Error message")
    .with_label("specific issue", call.head))

这样用户就能准确了解命令中的错误发生位置。

序列化

MsgPackSerializer(推荐)

  • 二进制格式,速度快得多
  • 用于生产环境中的插件

JsonSerializer

  • 基于文本,易于阅读
  • 适用于调试

在 main() 中选择:

serve_plugin(&MyPlugin, MsgPackSerializer)  // Production
// serve_plugin(&MyPlugin, JsonSerializer)  // Debug

常见模式

字符串转换
Value::String { val, .. } => {
    Ok(Value::string(val.to_uppercase(), call.head))
}
列表生成
let items = vec![
    Value::string("a", call.head),
    Value::string("b", call.head),
];
Ok(Value::list(items, call.head))
记录(表格行)
use nu_protocol::record;

Ok(Value::record(
    record! {
        "name" => Value::string("example", call.head),
        "size" => Value::int(42, call.head),
    },
    call.head,
))
表格(记录列表)
let records = vec![
    Value::record(record! { "name" => Value::string("a", span) }, span),
    Value::record(record! { "name" => Value::string("b", span) }, span),
];
Ok(Value::list(records, call.head))

完整的可运行示例(包括以下内容),请参阅 references/examples.md:

  • 筛选流
  • HTTP API 调用
  • 文件系统操作
  • 多命令插件

开发工作流

迭代开发
# Build
cargo build

# Test (debug build)
plugin add target/debug/nu_plugin_<name>
plugin use <name>
"test" | my-command

# After changes, reload
plugin rm <name>
plugin add target/debug/nu_plugin_<name>
plugin use <name>
自动化测试
[dev-dependencies]
nu-plugin-test-support = "0.109.1"
#[cfg(test)]
mod tests {
    use nu_plugin_test_support::PluginTest;

    #[test]
    fn test_command() -> Result<(), nu_protocol::ShellError> {
        PluginTest::new("myplugin", MyPlugin.into())?
            .test_examples(&MyCommand)
    }
}

有关调试技巧和故障排除,请参阅 references/testing-debugging.md。

高级功能

流式数据

若要惰性处理大型数据集,请使用 PipelineData:

impl PluginCommand for MyCommand {
    fn run(&self, input: PipelineData, ...) -> Result<PipelineData, LabeledError> {
        let filtered = input.into_iter().filter(|v| /* condition */);
        Ok(PipelineData::ListStream(ListStream::new(filtered, span, None), None))
    }
}
引擎交互
// Get environment variables
let home = engine.get_env_var("HOME")?;

// Set environment variables (before response)
engine.add_env_var("MY_VAR", Value::string("value", span))?;

// Get plugin config from $env.config.plugins.<name>
let config = engine.get_plugin_config()?;

// Get current directory for path resolution
let cwd = engine.get_current_dir()?;
自定义值

定义可扩展 Nushell 内置类型的自定义数据类型。完整指南请参阅 references/advanced-features.md。

重要限制

Stdio 限制

  • 插件不能使用 stdin/stdout(它们保留给协议使用)
  • 尝试访问 stdio 前,请检查 engine.is_using_stdio()

路径处理

  • 始终使用相对于 engine.get_current_dir() 的路径
  • 切勿假定当前工作目录

版本兼容性

  • nu-plugin 和 nu-protocol 的版本应匹配
  • 两者都应与目标 Nushell 版本匹配

参考文档

  • references/plugin-protocol.md - 协议详情、序列化、生命周期
  • references/advanced-features.md - 流式处理、EngineInterface、自定义值
  • references/examples.md - 完整的可运行示例和模式
  • references/testing-debugging.md - 开发工作流、调试、故障排除

外部资源

模板脚本

使用 scripts/init_plugin.py 按照合适的结构搭建新插件:

python3 scripts/init_plugin.py <plugin-name> [--output-dir <path>]

此脚本会创建一个完整的可运行插件模板,可供你自定义。

评论

支持 Markdown