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

# 插件接口

RenMori 采用开放核心架构。开源的 `renmori` 命令行工具是集成点：它负责解析配置、准备输出目录与备份、驱动面向用户的流程，并始终内置基线容器格式。强保护部分，即逐构建多态引擎、运行时密钥派生以及原生核心与启动器，位于一个闭源插件之中，以预构建组件的形式分发，从不以源码形式分发。

本页定义二者之间稳定的进程契约。该契约是公开的，使开源工具与闭源插件能够各自独立地进行版本管理与发布；只有插件的实现是闭源的。

## 插件发现

开源工具按以下顺序定位插件：

- `renmori protect` 的 `--plugin <path>` 参数
- `RENMORI_PLUGIN` 环境变量
- 未找到插件：工具使用基线格式运行，并拒绝任何非基线的 `strength`

`<path>` 是一个可执行文件，或一个由开源工具以当前 Python 解释器运行的 `.py` 脚本。插件只有在 `capabilities` 握手（见下文）成功之后才会被使用；握手失败的插件视为不存在，转而使用基线路径。

:::tip 当前 CLI 的行为
当前版本的 CLI 在上述显式路径之外，还会查找本地缓存，并在需要时从公开 Release 下载插件、按 `SHA256SUMS` 校验后写入缓存。未设置 `strength` 时默认使用完整保护，若没有可用的插件则运行失败；`--strength auto` 在无插件时回退到基线；`--strength baseline` 从不下载插件。详见 [闭源插件](https://renmori.mewbaka.cn/cli/plugin.md)。
:::

## 传输方式

每次调用都是一个短生命周期的子进程，第一个参数用于选择操作。需要请求体时，请求是 **stdin** 上的单个 JSON 对象；响应是 **stdout** 上的单个 JSON 对象。所有供人阅读的日志均写入 **stderr**，以保证 stdout 可被机器解析。成功时退出码为 0，失败时为非零值。所有字段名与枚举值均为 ASCII，且与区域设置无关。

请求与响应对象都携带一个整数字段 `interface`。开源工具发送其支持的最高版本，并拒绝 `capabilities` 中不包含该版本的插件。

## 操作

### `capabilities`

无请求体。插件输出一个描述自身的 JSON 对象，并以 0 退出：

| 字段          | 含义                          |
| ----------- | --------------------------- |
| `interface` | 插件支持的最高接口版本                 |
| `name`      | 插件显示名称                      |
| `version`   | 插件发布版本                      |
| `strengths` | 插件接受的 `strength` 取值，按由强到弱排列 |
| `platforms` | 插件能够产出的目标平台键                |

### `protect`

stdin 上的请求对象：

| 字段           | 含义                                                  |
| ------------ | --------------------------------------------------- |
| `interface`  | 开源工具选定的接口版本                                         |
| `source_dir` | 待读取的发行版构建；插件不得修改它                                   |
| `output_dir` | 受保护构建的写入位置；由插件创建，且必须事先不存在                           |
| `strength`   | 插件所声明的 `strengths` 之一                               |
| `platforms`  | 显式的目标平台键列表，或 `null` 表示从 `source_dir/lib/py3-*` 自动探测 |
| `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                       |
| `files`            | 已封装的条目数                               |
| `scripts`          | 已变换的脚本数                               |
| `cores`            | 每个已分发的原生核心对应一条 `{platform, filename}` |
| `launcher`         | 各平台的启动器文件名，或 `null`                   |

失败时，插件输出 `{"interface": N, "status": "error", "message": "<reason>"}` 并以非零值退出。开源工具会报告该消息，以其运行时失败退出码退出，并尽可能不留下不完整的 `output_dir`。

## 职责划分

- 开源工具负责：参数与 `renmori.toml` 的解析、输出与备份的决策及其所涉及的复制或移动、执行前的摘要与确认、根据响应写出的构建清单，以及全部本地化输出
- 插件负责：容器格式及其逐构建随机化、密钥派生、原生核心与启动器，以及 `output_dir` 下的最终磁盘内容

对插件而言，原地保护同样表达为一对普通的 `source_dir` → `output_dir`：开源工具先将原目录移开（移至备份目录，或移至事后丢弃的临时目录），再将原路径作为 `output_dir` 传入，因此插件无需支持原地模式。

## 版本与完整性

只有当请求或响应的结构发生破坏性变更时，`interface` 才会递增。一个插件可以同时支持多个版本，开源工具会选择双方共同支持的最高版本。新增的可选字段不会使版本号递增。

由插件产出的构建，应当能够与第三方使用开放框架加手写弱引擎拼装出的构建相区分：构建清单中可以携带一个由运行时校验的构建指纹。该绑定机制随闭源组件一同定义，不在本公开契约的范围之内。
