mcpField
N
nushell-plugin-builder

nushell-plugin-builder

github.com/ypares開発3045 回インストール1 日前に更新
リポジトリ

nushell-plugin-builder について

Nushell Plugin Builderは、Nushellのコマンドやデータ処理を拡張するプラグインを作るRust開発者向けスキルです。コマンド定義、ストリーミング、シリアライズ、テスト、インストールを扱います。

主な機能

  1. 01プラグインプロジェクトのひな形作成
  2. 02コマンドシグネチャと引数の定義
  3. 03値とデータストリームの処理
  4. 04MsgPackまたはJSONのシリアライズ選択
  5. 05テストとデバッグのガイド

活用シーン

  1. 01Nushellのカスタムコマンド作成
  2. 02大規模データ向けストリーミングプラグインの構築
  3. 03HTTP APIやファイルシステムを扱うプラグインの開発
  4. 04Rustプラグインのテストと登録

インストール

コマンドをコピーしてターミナルで実行します。

$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 を参照してください。

重要な制約

標準入出力の制限

  • プラグインは stdin/stdout を使用できません(プロトコル用に予約されています)
  • 標準入出力にアクセスする前に、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>]

これにより、カスタマイズしてすぐに使える、完全に動作するプラグインテンプレートが作成されます。

コメント