プラグインマニフェストとパッケージング
schema version 2、3、4 の plugin descriptor を定義し、ビルドした JAR を配布する。
すべての Turboism plugin JAR には、次の場所に descriptor が正確に 1 つあります。
META-INF/turboism/plugin.jsondescriptor は "format": "turboism.plugin.meta" と schemaVersion を宣言します。Runtime が受け入れる schema version は 2、3、4 で、対応する contract に対して厳格に検証し、descriptor を自動で upgrade することはありません。
| バージョン | 契約 |
|---|---|
| 2 | 基本的な lifecycle、entrypoint、API range、dependency、permission、resource、localization。 |
| 3 | 必須の category フィールドと任意の tags を追加します(first-party plugin が使用しているのは v3 です)。 |
| 4 | 宣言された cross-plugin event contract(eventExports と eventImports)を追加します。 |
schema version 1 はロードされません。未知のフィールドは無視されず、拒否されます。
Manifest の例
{
"format": "turboism.plugin.meta",
"schemaVersion": 3,
"id": "dev.example.plugin.hello",
"name": "Hello Plugin",
"version": "0.1.0",
"description": "Minimal Turboism plugin lifecycle example.",
"category": "workflow",
"tags": ["example", "lifecycle"],
"entrypoints": [
"dev.example.plugin.HelloPlugin"
],
"turboismApi": "[0.1.0,0.2.0)",
"authors": [
{ "name": "Example Author" }
],
"license": "MIT",
"website": "https://example.org/hello-plugin",
"resources": [],
"i18n": {
"baseName": "META-INF/turboism/i18n/messages",
"locales": []
},
"dependencies": [],
"permissions": [],
"capabilities": [],
"environment": {
"requiresCubism": false,
"ui": "none"
}
}必須フィールドは id、name、version、entrypoints、turboismApi、authors、website、resources、i18n です。schema 3 ではさらに category が必須です。
Entrypoint のルール
各 entrypoint は次を満たさなければなりません。
- 同じ plugin JAR 内に存在する。
- public である。
TurboismPluginまたは subinterface を実装する。- public no-argument constructor を公開する。
複数の entrypoint は、1 つの plugin identity、descriptor、ClassLoader、PluginContext、DisposableScope、permission set、configuration namespace、storage namespace、resource、localization declaration を共有します。
construct/init/enable: manifest order
disable/shutdown: reverse manifest orderconstruct、initialization、enablement の途中で failure が発生すると、JAR 全体が rollback されます。
Category と tags
category は 2〜32 文字の小文字 kebab-case token でなければなりません。レビュー済みの first-party category は modeling、workflow、appearance、analysis、performance、integration、system、development です。形式が正しいものの登録されていない category もロードされ、other として提示され、構造化された PLUGIN_CATEGORY_UNKNOWN diagnostic を出力します。
tags は任意で、2〜32 文字の小文字 kebab-case token を最大 12 個保持し、permission や capability を持ちません。
Dependency
{
"id": "dev.example.plugin.base",
"version": "[1.0.0,2.0.0)",
"type": "required",
"ordering": "after",
"reason": "Uses the base plugin contract."
}typeはrequiredまたはoptionalです。orderingはnone、before、またはafterです。- dependency ID は reverse-domain syntax を使います。
- version range は Turboism version-range grammar を使います。
dependency record は resolution と ordering を制御します。別 plugin の private implementation package を public Java dependency にするものではありません。
Permission
各 permission record には、既知の ID、application または user scope、空でない reason が含まれます。
{
"id": "turboism.action.register",
"scope": "application",
"reason": "Registers the Hello action."
}plugin が呼び出す SDK service に必要な permission だけを宣言してください。permission は Provider の availability を保証せず、operation validation を迂回するものでもありません。
Resource と localization
Resource root は / で終わる正規化済みの相対 prefix です。
"resources": ["icons/"],
"i18n": {
"baseName": "META-INF/turboism/i18n/messages",
"locales": ["base", "en", "zh-Hans"]
}その場合、JAR には次が含まれていなければなりません。
icons/hello.png
META-INF/turboism/i18n/messages.properties
META-INF/turboism/i18n/messages_en.properties
META-INF/turboism/i18n/messages_zh_Hans.properties宣言した root と catalog は存在しなければなりません。通常の class 以外の resource は、宣言された root に属していなければなりません。path traversal、absolute path、backslash、空の segment、undeclared resource は拒否されます。
サポートされる runtime locale は en、ja、ko、zh-Hans、zh-Hant と、base bundle です。manifest の locale ID は scripted form(zh-Hans)を使用し、resource bundle のファイル名は Java の underscore form(messages_zh_Hans.properties)を使用します。
Cross-plugin event contract(schema 4)
schema 4 では、plugin が所有および消費する public event type を宣言できるため、Runtime は ClassLoader delegation なしでそれらを解決できます。
"eventExports": [
{
"id": "dev.example.event.hello",
"contractVersion": "1.0.0",
"eventType": "dev.example.api.HelloEvent",
"abiSha256": "<sha256 of the event type bytes>"
}
],
"eventImports": [
{
"provider": "dev.example.plugin.base",
"eventId": "dev.example.event.base-status",
"contractVersion": "1.0.0",
"eventType": "dev.example.api.BaseStatusEvent",
"abiSha256": "<sha256 of the event type bytes>"
}
]eventImports の entry は "required": true を持つこともでき、その provider contract が認定されることを要求します。Runtime はすべての entry について宣言された ABI digest を検証し、plugin 内で重複する export ID や event type を拒否し、認定された provider contract に解決しない import を拒否します。
Plugin ID は、少なくとも 1 つのドットを含む reverse-domain syntax を使用します(dev.example.plugin.hello)。event ID は小文字の dot/dash token 形式を使用します。
build と検証
repository 内の plugin module では、次を実行します。
./gradlew :plugins:hello:test :plugins:hello:jar validatePluginMeta \
--no-daemon --console=plainrepository は Java 17 を使用し、module のビルド結果を次の下に書き込みます。
build/worktree/<worktreeId>/<module>/libs/libs/ にある JAR がリリース用ファイルです。wrapper archive も別個の packaging step もありません。
厳格な JAR 検証
JAR 自体がインストール成果物です。Runtime は選択された JAR を信頼できないローカル入力として扱い、次を検証します。
- 通常ファイルで、source chain にシンボリックリンクがなく、raw size、entry ごとの size、総展開量、entry 数、圧縮率の上限の範囲内である。
META-INF/turboism/plugin.jsonが正確に 1 つ。- descriptor の ID、version、API range の整合性。
- コピーされた SDK、Runtime、test、test-framework、Live2D class がない。
- native binary や installer payload がない。
- ネストされた JAR がない。
- 宣言された entrypoint、resource root、i18n catalog が存在する。
- 未宣言の通常 resource がない。
マネージドインストールは検証済み JAR をステージングし、Cubism の再起動後に適用します。任意の ZIP や JAR の名前を変更して plugin を作成しないでください。常に Gradle build が生成した JAR を配布してください。