Skip to content

機能仕様書: Rust版 unity-cli 置換・UPM統合・TDD整備 #82

@akiojin

Description

@akiojin

Spec

機能仕様書: Rust版 unity-cli 置換・UPM統合・TDD整備

要件ID: SPEC-83d9d7ee
作成日: 2026-02-17
ステータス: 実装完了
関連文書: ベースライン方針と差分棚卸し
入力: ユーザー説明: "unity-cli を CLI 化し、Node.js から Rust へ置換。仕様と TDD も整備する。UPM同梱・Cargo配布・LSP同梱も行う"

ユーザーシナリオ&テスト (必須)

ユーザーストーリー1 - Rust CLIでUnityコマンドを直接実行したい (優先度: P1)

開発者が Node.js 実行基盤を介さず、Rust 製 unity-cli から Unity TCP に直接接続してコマンドを実行したい。

この優先度の理由: 基盤置換の中心価値であり、これが無いと移行は成立しないため。

独立テスト: unity-cli raw ping --json '{}' が Unity TCP 応答を受け取れることを確認する。

受け入れシナリオ:

  1. 前提 Unity が TCP 待受中、実行 unity-cli system ping結果 ping 応答が表示される。
  2. 前提 任意ツール名とJSONパラメータを指定、実行 unity-cli raw <tool> --json {...}結果 Unity 応答が JSON で返る。

ユーザーストーリー2 - マルチインスタンスを安全に切り替えたい (優先度: P1)

複数 Unity インスタンス運用時に、listset-active で接続先を安全に管理したい。

この優先度の理由: 誤送信防止は自動化導入時の必須要件であり、運用事故を直接防ぐため。

独立テスト: 到達可能ポート/到達不能ポートを使って、instances listinstances set-active の成功/失敗を確認する。

受け入れシナリオ:

  1. 前提 指定ポートに Unity が待受中、実行 unity-cli instances list --ports 6400結果 status=up が返る。
  2. 前提 到達不能ポート指定、実行 unity-cli instances set-active host:port結果 unreachable エラーで失敗する。

ユーザーストーリー3 - 仕様とTDD前提で保守できる状態にしたい (優先度: P2)

将来の機能追加時に、仕様/計画/タスクとテストが揃った状態で開発を継続したい。

この優先度の理由: CLI置換は長期施策のため、仕様欠落やテスト不足を残すと回帰リスクが高くなるため。

独立テスト: spec.md / plan.md / tasks.md が存在し、cargo test が通ることを確認する。

受け入れシナリオ:

  1. 前提 新しい CLI 機能を追加する、実行 tasks.md の RED→GREEN→REFACTOR 手順に従う、結果 仕様と実装の追跡可能性を維持できる。
  2. 前提 変更を加える、実行 cargo test を実行、結果 追加した回帰テストが常に通る。

ユーザーストーリー4 - Unity側パッケージとCargo配布を同時に運用したい (優先度: P1)

unity-cli リポジトリだけで CLI 本体・Unity UPM パッケージ・LSP を一体で保守し、cargo install と UPM URL の両方を提供したい。

この優先度の理由: 今後の保守対象が unity-cli のみであり、配布導線の分断を避ける必要があるため。

独立テスト: unity-cli/README.md に Cargo install 手順と UPM URL が記載され、UnityCliBridge/Packages/unity-cli-bridge/package.json のメタデータが akiojin/unity-cli を参照することを確認する。

受け入れシナリオ:

  1. 前提 Unity Package Manager で Git URL 指定、実行 https://github.com/akiojin/unity-cli.git?path=UnityCliBridge/Packages/unity-cli-bridge を追加、結果 com.akiojin.unity-cli-bridge が導入できる。
  2. 前提 Rust 環境がある、実行 cargo install unity-cli(または git install)、結果 unity-cli コマンドを実行できる。
  3. 前提 LSP 連携が必要、実行 UNITY_CLI_LSP_MODE=auto で script/index 系を呼び出す、結果 LSP利用またはRust実装フォールバックで処理できる。

エッジケース

  • Unity から未フレームJSONが返る場合でも、CLI は応答を安全に解釈できること。
  • --json にオブジェクト以外(配列/数値など)が渡された場合、送信前に失敗させること。
  • instances レジストリファイルが欠落/破損していても、再初期化して継続できること。

要件 (必須)

機能要件

  • FR-001: unity-cli は Rust 実装として提供され、raw, tool call, system ping, scene create, instances list, instances set-active を実行できる必要がある。
  • FR-002: Unity 通信は TCP 4byte length + JSON の既存フレーミング互換で送受信する必要がある。
  • FR-003: 応答は --output text|json で切替可能で、JSONモードでは機械可読形式で出力する必要がある。
  • FR-004: 設定は UNITY_CLI_* のみ受理し、legacy MCPプレフィックス変数はエラーとして扱う必要がある。
  • FR-005: インスタンス切替情報はローカルレジストリに保存し、list で active 状態を表示できる必要がある。
  • FR-006: 仕様ドキュメントとして spec.md, plan.md, tasks.md を作成し、移行方針と作業順序を定義する必要がある。
  • FR-007: TDD 準拠のため、少なくともパラメータ検証・TCP応答処理・インスタンス切替に対する自動テストを実装する必要がある。
  • FR-008: 呼び出し方法を Codex/Claude 双方のスキルとして提供する必要がある。
  • FR-009: unity-cli リポジトリ内に Unity UPM パッケージ(UnityCliBridge/Packages/unity-cli-bridge)を同梱する必要がある。
  • FR-010: Unity 側の主要公開名は UnityCliBridge を使用せず、UnityCliBridge 系名称へ統一する必要がある。
  • FR-011: LSP 実装は unity-cli/lsp として同梱し、Rust CLI から UNITY_CLI_LSP_MODE で利用可否を制御できる必要がある。
  • FR-012: Cargo 配布要件として cargo install unity-cli 導線を README と Cargo.toml メタデータで提供する必要がある。
  • FR-013: 性能方針として script/index 系ローカル処理は Rust 実装を維持し、LSP 失敗時は即時フォールバックして性能劣化を回避する必要がある。

主要エンティティ

  • RuntimeConfig: CLI 実行時の host/port/timeout を保持し、環境変数とCLI引数を統合する。
  • UnityClient: Unity TCP への接続、フレーム送信、応答正規化を担う。
  • InstanceRegistry: active 接続先と既知インスタンスを管理するローカル永続状態。

成功基準 (必須)

測定可能な成果

  • SC-001: cargo test --manifest-path unity-cli/Cargo.toml が成功し、CLI コア挙動の回帰テストが自動実行される。
  • SC-002: unity-cli --help で主要サブコマンドが表示される。
  • SC-003: instances list は到達可能ポートを up、到達不能ポートを down と識別できる。
  • SC-004: 旧repo README に移行ガイドとコマンド対応表が記載される。
  • SC-005: unity-cli/README.md に Cargo install 手順が記載される。
  • SC-006: UnityCliBridge/Packages/unity-cli-bridge/package.jsonnamecom.akiojin.unity-cli-bridge で、repositoryakiojin/unity-cli を指す。
  • SC-007: UNITY_CLI_LSP_MODE=off(既定)で既存 cargo test が成功し、UNITY_CLI_LSP_MODE=auto|required で LSP 経路を選択可能である。

Plan

実装計画: Rust版 unity-cli 置換・UPM統合・TDD整備

要件ID: SPEC-83d9d7ee | 日付: 2026-02-17 | 仕様: spec.md
入力: /specs/SPEC-83d9d7ee/spec.md の機能仕様

概要

Node.js ベースの実行導線を Rust 製 unity-cli に置換し、Unity TCP 直結の CLI を提供する。合わせて unity-cli リポジトリ内に UPM パッケージ(UnityCliBridge)と LSP 実装を同梱し、Cargo 配布導線と TDD を整備する。

技術コンテキスト

言語/バージョン: Rust 1.91+
主要依存関係: tokio, clap, serde, serde_json, anyhow, tracing
ストレージ: ローカル JSON (instances.json)
テスト: cargo test
対象プラットフォーム: macOS / Linux / Windows 上の Rust CLI
プロジェクトタイプ: single (new unity-cli crate inside workspace)
パフォーマンス目標: script/index 系ローカル処理で既存実装以上(P50/P95)を維持し、LSP失敗時はRust実装へフォールバック
制約: Unity TCP 既存プロトコル互換(length+JSON)を保持
スケール/スコープ: まずコアサブコマンド + raw fallback を提供

憲章チェック

  • シンプルさ: 新規実装は unity-cli ディレクトリへ分離し、既存 Node 本体は改変しない方針で複雑度を抑制。
  • TDD: パーサー/通信/インスタンス切替に対するテストを先に定義し、実装整合を確認。
  • 可観測性: --output json と明確なエラーメッセージでデバッグ可能性を維持。
  • ドキュメント: 旧READMEへ移行ガイドを追記し、運用導線を明示。

プロジェクト構造

specs/SPEC-83d9d7ee/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── cli-commands.md
└── tasks.md

unity-cli/
├── Cargo.toml
├── src/
│   ├── main.rs
│   ├── cli.rs
│   ├── config.rs
│   ├── transport.rs
│   ├── instances.rs
│   ├── lsp.rs
│   ├── local_tools.rs
│   └── tool_catalog.rs
├── lsp/
│   ├── Program.cs
│   ├── Server.csproj
│   └── Server.Tests.csproj
├── UnityCliBridge/
│   └── Packages/unity-cli-bridge/
├── README.md
└── RELEASE.md

scripts/
└── export-unity-cli-subtree.sh

.github/workflows/
└── unity-cli-release.yml

Phase 0: リサーチ

  • Unity TCP 応答のフレーム有無差分を吸収する方針を確定。
  • UNITY_CLI_* のみ受理する設定方針を決定。
  • ローカルインスタンス管理の保存先(OS標準config)を決定。

Phase 1: 設計

  • CLI インターフェース(サブコマンドと引数)を定義。
  • RuntimeConfig / UnityClient / InstanceRegistry の責務分離を確定。
  • エラー出力契約(text/json)を定義。
  • スキル導線(Codex/Claude)を unity-cli-usage として統一。

Phase 2: TDD実装

  • RED: 失敗するテスト(パース検証・通信失敗/成功・インスタンス到達性)を追加。
  • GREEN: 最小実装でテストを通す。
  • REFACTOR: 設定解決/通信処理/インスタンス管理を分離して可読化。

Phase 3: UPM/LSP/Cargo 導線

  • Unity 側実装を unity-cli/UnityCliBridge/Packages/unity-cli-bridge へ移行。
  • Unity 側公開名を UnityCliBridge に統一(UnityCliBridge 名称を排除)。
  • LSP 実装を unity-cli/lsp へ同梱し、Rust 側の UNITY_CLI_LSP_MODE 連携を追加。
  • Cargo.toml メタデータを crates.io 公開に対応させ、cargo install 手順を明文化。

Phase 4: 移行ドキュメント

  • README / README.ja に unity-cli 置換方針とコマンド対応表を追加。
  • Claude plugin marketplace と unity-cli スキルを登録。
  • Codex スキル unity-cli-usage を追加。
  • 専用repo切り出し用に subtree export スクリプトと release workflow を整備。

実装完了の判定

  • cargo test --manifest-path unity-cli/Cargo.toml が成功。
  • CLI ヘルプが期待サブコマンドを表示。
  • script/index ローカルツール(build_index, update_index, get_symbols, find_symbol, find_refs)が実行できる。
  • Unity UPM パッケージが akiojin/unity-cli 配下の Git URL で導入できる。
  • Cargo install 導線(cargo install unity-cli)が README と Cargo metadata に反映される。
  • spec/plan/tasks が完成し、追加機能時の作業手順が決まっている。

Tasks

タスク: Rust版 unity-cli 置換とTDD整備

入力: /specs/SPEC-83d9d7ee/
前提条件: spec.md, plan.md

Phase 1: 仕様整備

  • T001 specs/SPEC-83d9d7ee/spec.md にユーザーストーリー・FR・成功基準を定義
  • T002 specs/SPEC-83d9d7ee/plan.md に技術方針と実装フェーズを定義
  • T003 specs/SPEC-83d9d7ee/tasks.md に実行順序と完了判定を記述

Phase 2: TDD (RED→GREEN→REFACTOR)

  • T004 [US1] src/main.rs に JSONパラメータ検証・ポートCSV解析のユニットテストを追加
  • T005 [US1] src/transport.rs に framed応答の成功/失敗テストを追加
  • T006 [US2] src/instances.rs に parse_id/到達性/切替失敗テストを追加
  • T007 [US1][US2] cargo test --all-targets を実行し、テスト成功を確認

Phase 3: 実装

  • T008 [US1] unity-cli のサブコマンド (raw/tool/system/scene/instances) を実装
  • T009 [US1] Unity TCP transport 実装(framed送受信 + fallback JSONパース)
  • T010 [US2] ローカルインスタンスレジストリ実装(list/set-active)
  • T011 [US1] UNITY_CLI_* + UNITY_CLI_* 互換の設定解決を実装

Phase 4: 移行導線とスキル

  • T012 [US3] README.md / README.ja.md に移行ガイドとコマンド対応表を追記
  • T013 [US3] Codex スキル unity-cli-usage/SKILL.md を追加
  • T014 [US3] Claude plugin unity-cli とスキルを追加
  • T015 [US3] .claude-plugin/marketplace.jsonunity-cli エントリを追加

Phase 5: 残課題(次スプリント)

  • T016 [US1] 108ツール名を unity-cli tool <tool> で直接指定可能にした(catalog検証付き)
  • T017 [US1] script/index 系ローカル処理の Rust 移植(find_symbol/find_refs/get_symbols/build_index/update_index
  • T018 [US3] 新規 unity-cli 専用リポジトリへの切り出しとリリース導線整備(subtree export script + release workflow)
  • T019 [US1] read/search/list_packages のローカル処理を Rust 側へ移植

Phase 6: UPM/LSP/Cargo 移行反映

  • T020 [US4] UnityCliBridge/Packages/unity-cli-bridge を同梱し、UPM URL を akiojin/unity-cli に統一
  • T021 [US4] Unity 側公開名を UnityCliBridge に統一(UnityCliBridge 名称を排除)
  • T022 [US4] csharp-lsplsp に改名し、LSPテスト導線を更新
  • T023 [US4] Rust 側に src/lsp.rs を追加し、get_symbols/find_symbol/find_refs/build_index のLSP経路(UNITY_CLI_LSP_MODE)を実装
  • T024 [US4] Cargo.tomlREADME.md を crates.io 配布向け(cargo install)に更新

Phase 7: 開発環境一式移行(本対応)

  • T025 [US4] .claude-plugin/.claude/.codex/skills/.github/.husky/.specify/configs/docs/scripts/specs/templatesunity-cli 向けに移行し、unity-mcp-server 依存表記を整理
  • T026 [US4] CI/Hook/チェックを Rust + LSP 前提へ更新(test.yml, lint.yml, .specify/scripts/checks, .husky
  • T027 [US4] Docker 設定を UNITY_CLI_* 主体に更新し、互換 UNITY_CLI_* を明示
  • T028 [US4] ライセンス運用を更新し、MIT保持 + 利用アプリへの表記推奨文を README/CONTRIBUTING/UPM README に追加
  • T029 [US4] 検証を実施(cargo fmt --check, cargo clippy -D warnings, cargo test --all-targets, pnpm run lint:mddotnet test は CI 実施対象として維持)

依存関係

  • T001-T003 完了後に T004-T007 を実施
  • T004-T007 完了後に T008-T011 を確定
  • T008-T011 完了後に T012-T015 を確定
  • T016-T019 を完了済み

実行メモ

  • TDD順序は必ず RED→GREEN→REFACTOR。
  • CLI互換は raw 経路を最終フォールバックとして維持する。

TDD

TODO

Research

Research: SPEC-83d9d7ee

1. Unity TCPプロトコル互換

決定

  • Rust 側でも「4byte big-endian length + JSON payload」を標準フレームとして採用する。
  • 例外的に unframed JSON が返るケースに備え、受信時は fallback パースを持つ。

理由

  • 既存 Unity 側実装は framed JSON を前提としているため、互換維持が最小リスク。
  • 一部テスト/デバッグ経路では unframed が混在するため、防御的パースが必要。

代替案

  • 完全 framed 強制: テスト互換性を落とすため却下。

2. 設定キー移行

決定

  • 正規キーを UNITY_CLI_* とし、UNITY_CLI_* を後方互換として読み込む。

理由

  • CLI 名称変更に合わせた明示的な設定体系が必要。
  • 既存環境変数を維持することで移行コストを下げられる。

3. インスタンス管理保存先

決定

  • OS標準 config ディレクトリ配下 unity-cli/instances.json を使用する。
  • テストでは UNITY_CLI_REGISTRY_PATH で保存先を上書き可能にする。

理由

  • ホーム直下への散在を防ぎ、CLI 設定の一貫性を保つ。
  • テストで実ユーザー環境を汚さないため。

4. TDD対象

決定

  • まず以下3領域を自動テスト対象に固定する。
    • パラメータ検証(JSON object / ports)
    • 通信処理(成功/失敗応答)
    • インスタンス切替(到達性判定・失敗系)

理由

  • 置換初期で回帰しやすい核を先に固定し、以後の機能追加の安全性を担保するため。

5. LSP同梱方針

決定

  • LSP 実装は unity-cli/lsp として同梱し、Rust 側では UNITY_CLI_LSP_MODE で有効化を制御する。
  • 既定値は off とし、性能劣化を避けるため Rust ローカル実装をデフォルト経路にする。

理由

  • ユーザー要求の「LSP同梱移行」を満たしつつ、cargo test/ローカル実行の安定性を維持するため。
  • LSP 実行環境(dotnet/配布バイナリ)がない環境でも CLI の基本機能を維持するため。

6. Unity UPM統合

決定

  • Unity 側は UnityCliBridge/Packages/unity-cli-bridge に移設し、パッケージ名を com.akiojin.unity-cli-bridge とする。

理由

  • 今後の保守対象を unity-cli のみに一本化するという運用方針に合わせるため。

Data Model

Data Model: SPEC-83d9d7ee

RuntimeConfig

フィールド 説明
host String Unity接続先ホスト
port u16 Unity接続先ポート
timeout Duration 接続/送受信タイムアウト

UnityRequest

フィールド 説明
id String コマンドID
type String Unity command type (ping, create_scene, etc.)
params Object コマンド引数JSON

UnityResponse (正規化前)

フィールド 説明
status String? success / error
success Bool? 互換用成功フラグ
result Value? 正常系ペイロード
data Value? 互換ペイロード
error String? エラーメッセージ
code String? エラーコード

InstanceRecord

フィールド 説明
id String host:port 形式
host String 接続先ホスト
port u16 接続先ポート

Registry

フィールド 説明
active_id Option<String> 現在アクティブなID
entries Vec<InstanceRecord> 既知インスタンス一覧

InstanceStatus (出力)

フィールド 説明
id String host:port
status String up / down
last_checked_at String Unix秒文字列
active bool アクティブ判定

SetActiveResult (出力)

フィールド 説明
active_id String 更新後アクティブID
previous_id Option<String> 更新前アクティブID

Quickstart

Quickstart: SPEC-83d9d7ee

1. Build

cargo build --manifest-path unity-cli/Cargo.toml

1.1 Cargo install

cargo install --path unity-cli

2. Connectivity check

cargo run --manifest-path unity-cli/Cargo.toml -- system ping

3. Generic Unity command call

cargo run --manifest-path unity-cli/Cargo.toml -- raw create_scene --json '{"sceneName":"MainScene"}'

3.1 Tool catalog and direct invocation

cargo run --manifest-path unity-cli/Cargo.toml -- tool list
cargo run --manifest-path unity-cli/Cargo.toml -- tool ping --json '{}'

3.2 Local script/index workflow (Rust)

export UNITY_PROJECT_ROOT=/path/to/UnityProject
cargo run --manifest-path unity-cli/Cargo.toml -- --output json tool build_index --json '{"excludePackageCache":true}'
cargo run --manifest-path unity-cli/Cargo.toml -- --output json tool find_symbol --json '{"name":"MyClass","kind":"class","exact":true}'
cargo run --manifest-path unity-cli/Cargo.toml -- --output json tool find_refs --json '{"name":"MyClass","pageSize":20}'
cargo run --manifest-path unity-cli/Cargo.toml -- --output json tool update_index --json '{"paths":["Assets/Scripts/MyClass.cs"]}'

3.3 LSP path and mode

export UNITY_CLI_LSP_MODE=auto
export UNITY_CLI_LSP_COMMAND=\"dotnet run --project lsp/Server.csproj --configuration Release\"

LSP source is bundled at unity-cli/lsp/.

4. Instance safety workflow

cargo run --manifest-path unity-cli/Cargo.toml -- instances list --ports 6400,6401
cargo run --manifest-path unity-cli/Cargo.toml -- instances set-active localhost:6401

5. JSON output mode

cargo run --manifest-path unity-cli/Cargo.toml -- --output json system ping

6. TDD verification

cargo test --manifest-path unity-cli/Cargo.toml

LSP tests:

dotnet test unity-cli/lsp/Server.Tests.csproj

7. Dedicated repository export (T018)

./scripts/export-unity-cli-subtree.sh git@github.com:akiojin/unity-cli.git main unity-cli-v0.1.0

Contracts

Migrated from local files. See artifact comments below.

Checklists

Artifact files under checklists/ are managed in issue comments with checklist:<name> entries.

Acceptance Checklist

  • Add acceptance checklist

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions