> For AI agents: the complete documentation index is available at https://renmori.mewbaka.cn/ja/llms.txt, the full documentation bundle is available at https://renmori.mewbaka.cn/ja/llms-full.txt.

# オープン部分とクローズド部分のインターフェース

RenMori はオープンコアの構成をとっています。オープンソースの `renmori` コマンドラインツールは統合の起点であり、設定の解析、出力先とバックアップの準備、ユーザー向けの処理フローの制御を担い、ベースラインコンテナ形式を常に同梱しています。強力な保護（ビルドごとの多態化エンジン、実行時の鍵導出、ネイティブコアとランチャー）はクローズドプラグインに含まれ、ビルド済みのコンポーネントとして配布され、ソースとして配布されることはありません。

このページでは、両者の間の安定したプロセス契約を定義します。この契約は、オープンソースのツールとクローズドプラグインがそれぞれ独立してバージョン管理とリリースを行えるように公開されており、クローズドなのはプラグインの実装のみです。

## 検出

オープンソースのツールは、次の順序でプラグインを探します。

- `renmori protect` の `--plugin <path>` 引数
- 環境変数 `RENMORI_PLUGIN`
- プラグインが見つからない場合：ツールはベースライン形式で実行し、ベースライン以外の `strength` はすべて拒否する

`<path>` には実行ファイル、またはオープンソースのツールが現在の Python インタープリタで実行する `.py` スクリプトを指定します。プラグインが使用されるのは `capabilities` のハンドシェイク（後述）が成功した場合のみで、ハンドシェイクに失敗したプラグインは存在しないものとして扱われ、ベースラインの経路がとられます。

:::tip 現在の CLI の動作
現在の CLI は、上記の明示的なパスに加えてローカルキャッシュも確認し、必要に応じて公開リリースからプラグインをダウンロードし、`SHA256SUMS` で検証してキャッシュに保存します。`strength` が未設定の場合のデフォルトはフル保護で、利用可能なプラグインがなければ実行は失敗します。`--strength auto` はプラグインがない場合にベースラインへフォールバックし、`--strength baseline` はプラグインを一切ダウンロードしません。[保護強度とクローズドプラグイン](https://renmori.mewbaka.cn/ja/cli/plugin.md)を参照してください。
:::

## 通信方式

各呼び出しは短時間で終了する 1 つのサブプロセスであり、最初の引数で操作を選択します。リクエストが必要な場合は **stdin** 上の単一の JSON オブジェクトとして渡し、レスポンスは **stdout** 上の単一の JSON オブジェクトとして返します。人が読むためのログはすべて **stderr** に出力するため、stdout は常に機械で解析可能な状態に保たれます。終了コードは成功時に 0、失敗時に 0 以外です。フィールド名と列挙値はすべて ASCII で、ロケールに依存しません。

リクエストとレスポンスのオブジェクトはいずれも整数のフィールド `interface` を持ちます。オープンソースのツールは自身が対応する最も高いバージョンを送信し、そのバージョンが `capabilities` に含まれていないプラグインは拒否します。

## 操作

### `capabilities`

リクエスト本体はありません。プラグインは自身を説明する JSON オブジェクトを出力し、終了コード 0 で終了します。

| フィールド       | 意味                             |
| ----------- | ------------------------------ |
| `interface` | プラグインが対応するインターフェースの最も高いバージョン   |
| `name`      | プラグインの表示名                      |
| `version`   | プラグインのリリースバージョン                |
| `strengths` | プラグインが受け付ける `strength` の値（強い順） |
| `platforms` | プラグインが生成できる対象プラットフォームのキー       |

### `protect`

stdin で渡すリクエストオブジェクトは次のとおりです。

| フィールド        | 意味                                                                  |
| ------------ | ------------------------------------------------------------------- |
| `interface`  | オープンソースのツールが選択したインターフェースのバージョン                                      |
| `source_dir` | 読み込む配布用ビルド。プラグインはこれを変更してはならない                                       |
| `output_dir` | 保護済みビルドの書き込み先。プラグインが作成し、事前に存在していてはならない                              |
| `strength`   | プラグインが宣言した `strengths` のいずれか                                        |
| `platforms`  | 対象プラットフォームのキーの明示的なリスト、または `source_dir/lib/py3-*` から自動検出する場合は `null` |
| `launcher`   | 鍵をネイティブランチャーに紐付け、ランチャーを同梱するかどうか                                     |
| `exclude`    | コンテナに含めないファイルを指定する、ゲーム相対の glob パターン                                 |
| `chunk_size` | コンテナのチャンクサイズ（バイト単位）、またはプラグインのデフォルトを使う場合は `null`                     |
| `lockdown`   | ビルド内で開発者コンソール、開発者モード、データエクスポート用サブコマンドを無効化するかどうか                     |
| `keys`       | 鍵の素材または鍵の取得元の指定のために予約されたオブジェクト。デフォルトは空                              |

プラグインは `source_dir` を `output_dir` にコピーし、すべてのアセットと Ren'Py スクリプトを多態化されたコンテナに格納し、対象プラットフォームごとのネイティブコア（要求された場合はランチャーも）を同梱し、ランタイムの拡張を書き込み、格納した平文の元ファイルを削除したうえで、stdout に次のレスポンスオブジェクトを出力します。

| フィールド              | 意味                                     |
| ------------------ | -------------------------------------- |
| `interface`        | このレスポンスのインターフェースのバージョン                 |
| `status`           | `"ok"`                                 |
| `strength`         | 実際に適用された強度                             |
| `platforms`        | 生成された対象プラットフォームのキー                     |
| `container`        | `game/` 以下のコンテナのファイル名                  |
| `container_sha256` | コンテナの SHA-256（16 進表記）                  |
| `files`            | 格納されたエントリの数                            |
| `scripts`          | 変換されたスクリプトの数                           |
| `cores`            | 同梱されたネイティブコアごとの `{platform, filename}` |
| `launcher`         | プラットフォームごとのランチャーのファイル名、または `null`      |

失敗した場合、プラグインは `{"interface": N, "status": "error", "message": "<reason>"}` を出力し、0 以外の終了コードで終了します。オープンソースのツールはそのメッセージを報告して実行時エラーの終了コードで終了し、可能な限り不完全な `output_dir` を残さないようにします。

## 責任の分担

- オープンソースのツールが担うもの：引数と `renmori.toml` の解析、出力先とバックアップの決定およびそれに伴うコピーや移動、事前の概要表示と確認、レスポンスから書き出すビルドマニフェスト、そしてローカライズされたすべての出力
- プラグインが担うもの：コンテナ形式とそのビルドごとのランダム化、鍵導出、ネイティブコアとランチャー、そして `output_dir` 以下のディスク上の最終的な結果

インプレース保護は、プラグインに対しては単純な `source_dir` → `output_dir` の組として表現されます。オープンソースのツールはまず元のビルドを別の場所（バックアップ、または後で破棄する一時ディレクトリ）に移し、元のパスを `output_dir` として渡すため、プラグインがインプレースのモードを持つ必要はありません。

## バージョン管理と完全性

`interface` は、リクエストまたはレスポンスの形式に互換性のない変更があった場合にのみ増加します。プラグインは複数のバージョンに同時に対応でき、オープンソースのツールは両者が共通して対応する最も高いバージョンを選択します。任意のフィールドを追加するだけの変更では、バージョンは上がりません。

プラグインが生成したビルドは、第三者がオープンなフレームワークと自作の弱いエンジンで組み立てたビルドと区別できるようにすることを意図しています。ビルドマニフェストには、ランタイムが検査するビルドフィンガープリントを含めることができます。この紐付けはクローズドのコンポーネントと共に定義されるものであり、この公開された契約の対象外です。
