チャンネルプラグインのパッケージング(official / steam)
チャンネルプラグイン(Discord、Feishu、Telegram、Slack、WhatsApp など)は事前ビルド済みアーティファクトとしてインストーラーと共に配布されます。このドキュメントでは、ソースコードから実行時までの完全なパス、ビルドチャンネル(official / steam)間のパッケージングの違い、そして steam チャンネルでかつてプラグインが欠落していた理由と現在の監査による防止策を説明します。
2 つの検出ディレクトリ
実行時に ChannelPluginLoader は2 つのディレクトリからチャンネルプラグインを検出します。pluginsDir は bundledDir より優先度が高くなります(type が同じ場合は上書き):
| ディレクトリ | パス | 読み書き | ソース |
|---|---|---|---|
ユーザーインストール(pluginsDir) | <userData>/channel-plugins/ | 読み書き | Marketplace ダウンロード / ローカルインストール |
組み込み(bundledDir) | <resources>/bundled-channel-plugins/ | 読み取り専用 | インストーラーと共に配布 |
関連コード:
packages/desktop/app/main/services/capabilities/integrations/channel/ChannelPluginLoader.ts、packages/desktop/app/main/bootstrap/capabilities-channel.ts。
bundledDir の解決は bootstrap/index.ts にあります:
const channelBundledDir = isDev
? path.join(__dirname, '..', '..', '..', 'elftia-channels', 'dist-plugins') // Dev mode: workspace source directory
: path.join(process.resourcesPath, 'bundled-channel-plugins'); // Packaged mode: copy under resources
ChannelPluginLoader は構築時に bundledDir の存在確認を行います:
this.bundledDir = bundledDir && existsSync(bundledDir) ? bundledDir : null;
重要な意味:パッケージ済みの <resources>/bundled-channel-plugins/ が存在しない場合、bundledDir は null に設定され、discover() は <userData>/channel-plugins/ ディレクトリのみを対象とします。新規インストールの場合、このディレクトリは空のため → チャンネルプラグインが 0 件発見される → チャンネルページに利用可能なプラグインが存在しない。
ソースコードからインストーラーへ
チャンネルプラグインのソースコードビルドアーティファクトはワークスペースディレクトリに格納されます:
packages/elftia-channels/dist-plugins/
├── discord/
├── feishu/
├── telegram/
├── slack/
├── whatsapp/
└── … (total ~26)
packages/elftia-channels/dist-pluginsは事前ビルド済みアーティファクトディレクトリであり、build:official/build:steamのインラインビルドチェーンには含まれません。パッケージング前に既に存在している必要があります。
パッケージング時に、electron-builder の extraResources がそれを resources/bundled-channel-plugins にコピーします。両方のビルドチャンネルでこれを宣言する必要があります:
# Both electron/electron-builder.official.yml and electron/electron-builder.steam.yml need:
extraResources:
- from: packages/elftia-channels/dist-plugins
to: bundled-channel-plugins
filter:
- "**/*"
official と steam のパッケージングの違い
| 項目 | official | steam |
|---|---|---|
| 設定ファイル | electron/electron-builder.official.yml | electron/electron-builder.steam.yml |
renderer-extension/byo-providers | 含まれる(BYO は official の核心的な約束) | 除外(Steam コンプライアンスの分離、明示的な負のフィルターマッチ) |
bundled-channel-plugins | 含まれる | 同様に含める必要がある |
チャンネルプラグインは BYO コンプライアンスの分離とは無関係:チャンネルプラグインはユーザー自身のボットトークン(Discord ボットトークン、Telegram ボットトークンなど)を使用しており、Steam が拒否する「BYO LLM プロバイダーキー / サイト外決済」カテゴリーには属しません。Steam チャンネルのコンプライアンス上の唯一の除外は renderer-extension/byo-providers であり、チャンネルプラグインは除外リストに含まれていません。
過去のバグ:steam.yml の設定漏れ
electron-builder.steam.yml の extraResources には、かつて bundled-channel-plugins が完全に欠落していました(git の全履歴に一度も現れていません)。影響:
- Steam パッケージに
resources/bundled-channel-plugins/ディレクトリがない; - 実行時に
channelBundledDirが存在しないパスを指す →ChannelPluginLoader.bundledDir = null; discover()は空のユーザーディレクトリのみをスキャン → チャンネルプラグインが 0 件発見される;- ユーザー体験:Steam 版はチャンネルプラグインを使用できないが、official 版は正常に動作する。
この漏れは意図的なコンプライアンス上の分離ではありませんでした(意図的な除外はすべてコメント付きの負の filter マッチを持っています)。steam.yml が official.yml からフォークされた際に見落とされた extraResources の追記漏れでした。
監査のフォールバック:verify:steam-package
scripts/verify-steam-packaging.mts(npm run verify:steam-package、現在は build:steam チェーンの末尾に統合)は4 つの不変条件を検証します:
| 不変条件 | 意味 |
|---|---|
byo-providers ABSENT | Steam パッケージは renderer-extension/byo-providers を含まない(コンプライアンス) |
design-studio PRESENT | Steam パッケージは renderer-extension/design-studio を含む |
channel === 'steam' | チャンネルメタデータが steam である |
bundled-channel-plugins PRESENT | Steam パッケージに少なくとも 1 つのチャンネルプラグインが含まれる ← 今回新規追加 |
終了コードの契約:0 は全て合格;2 は少なくとも 1 つの違反;1 は入力が利用不可。
監査には 2 つのモードがあります(優先度順):
- MODE 1(パッケージング済み、権威):
release/steam/<platform>-unpacked/…/resources/plugins/renderer-extension/が存在する場合、実際のアーティファクトを直接監査します。チャンネルプラグイン数 = 同じ階層のresources/bundled-channel-plugins/のサブディレクトリ数。 - MODE 2(ステージング ドライラン、フォールバック):
electron-builder.steam.ymlのextraResourcesエントリを解析してbundled-channel-pluginsにマップし、from:のソースディレクトリのサブディレクトリを数えます。エントリがない → 0 と見なす → 不変条件失敗(これがまさに今回防ぎたい設定漏れです)。
歴史的な教訓:以前の監査は
renderer-extensionのみを対象とし、チャンネルプラグインはスコープ外でした。そのため、パッケージにチャンネルプラグインが 0 件でも監査はパスしていました。新しいbundled-channel-plugins PRESENT不変条件がこの盲点を塞ぎます。
変更 / 検証チェックリスト
チャンネルプラグインのパッケージングを追加または調整する際:
-
electron-builder.steam.ymlとofficial.ymlの両方でpackages/elftia-channels/dist-plugins → bundled-channel-pluginsを宣言している; - パッケージング前に
packages/elftia-channels/dist-plugins/がビルド済みで空でない; - 再ビルド:
npm run build:steam:win(古いrelease/steam/win-unpacked/は前回のビルドのため、MODE 1 監査はそれを使用します。再ビルド後に監査すること); - アーティファクトの確認:
release/steam/win-unpacked/resources/bundled-channel-plugins/にすべてのプラグインディレクトリが含まれている; - 監査合格:
npm run verify:steam-packageの終了コードが0、[PASS] bundled-channel-plugins PRESENT; - 実行時確認:メインプロセスのログに
Channel plugin directories … bundledExists: trueとChannel plugin discover: found N plugin(s)(N > 0)が表示される。