- ホーム
- Documentation
- 拡張機能
- Gemini マニフェスト拡張 (`gemini-extension.json`)
Gemini マニフェスト拡張 (`gemini-extension.json`)
このドキュメントでは、コーディングエージェントが Gemini スタイルのマニフェスト拡張 (gemini-extension.json) を検出し、extensions ケーパビリティとしてパースする方法について説明します。
TypeScript/JavaScript 拡張モジュールのロード(extensions/*.ts、index.ts、package.json xcsh.extensions)については、extension-loading.md に記載されており、本ドキュメントでは扱いません。
実装ファイル
Section titled “実装ファイル”../src/discovery/gemini.ts../src/discovery/builtin.ts../src/discovery/helpers.ts../src/capability/extension.ts../src/capability/index.ts../src/extensibility/extensions/loader.ts
Gemini プロバイダー(id: gemini、優先度 60)は extensions ローダーを登録し、2 つの固定ルートをスキャンします。
- ユーザー:
~/.gemini/extensions - プロジェクト:
<cwd>/.gemini/extensions
パス解決は getUserPath() / getProjectPath() を通じて ctx.home および ctx.cwd から直接行われます。
重要なスコープルール: プロジェクトのルックアップは cwd のみ です。親ディレクトリをたどることはありません。
ディレクトリスキャンのルール
Section titled “ディレクトリスキャンのルール”各ルート(~/.gemini/extensions および <cwd>/.gemini/extensions)に対して、検出処理は以下を行います。
readDirEntries(root)を実行- 直接の子ディレクトリのみを保持(
entry.isDirectory()) - 各子
<name>に対して、正確に以下のみを読み取ろうとする:<root>/<name>/gemini-extension.json
1 ディレクトリレベルを超えた再帰的スキャンは行いません。
隠しディレクトリ
Section titled “隠しディレクトリ”Gemini マニフェスト検出では、ドットプレフィックスのディレクトリ名をフィルタリングしません。隠し子ディレクトリが存在し gemini-extension.json を含む場合、そのディレクトリは対象として扱われます。
欠落または読み取り不能なファイル
Section titled “欠落または読み取り不能なファイル”gemini-extension.json が欠落しているか読み取り不能な場合、そのディレクトリは警告なしにスキップされます(警告なし)。
マニフェストの形式(実装ベース)
Section titled “マニフェストの形式(実装ベース)”ケーパビリティ型はこのマニフェスト形式を定義します。
interface ExtensionManifest { name?: string; description?: string; mcpServers?: Record<string, Omit<MCPServer, "name" | "_source">>; tools?: unknown[]; context?: unknown;}検出時の動作は意図的に緩やかです。
- JSON のパース成功が必須です。
- JSON の構文を超えたフィールドの型や内容に対する実行時スキーマ検証は行いません。
- パースされたオブジェクトはケーパビリティアイテムの
manifestとして保存されます。
名前の正規化
Section titled “名前の正規化”Extension.name は以下のように設定されます。
manifest.nameがnull/undefinedでない場合はその値を使用- それ以外の場合は拡張ディレクトリ名を使用
ここでは文字列型の強制は適用されません。
ケーパビリティアイテムへのマテリアライズ
Section titled “ケーパビリティアイテムへのマテリアライズ”有効にパースされたマニフェストは 1 つの Extension ケーパビリティアイテムを生成します。
{ name: manifest.name ?? <directory-name>, path: <extension-directory>, manifest: <parsed-json>, level: "user" | "project", _source: { provider: "gemini", providerName: "Gemini CLI" // ケーパビリティレジストリによって付与 path: <absolute-manifest-path>, level: "user" | "project" }}注意事項:
_source.pathはcreateSourceMeta()によって絶対パスに正規化されます。extensionsに対するレジストリレベルのケーパビリティ検証では、nameとpathの存在のみを確認します。- マニフェストの内部要素(
mcpServers、tools、context)は検出時には検証されません。
エラー処理と警告のセマンティクス
Section titled “エラー処理と警告のセマンティクス”警告が発出される場合
Section titled “警告が発出される場合”- マニフェストファイルに無効な JSON が含まれる場合:
- 警告フォーマット:
Invalid JSON in <manifestPath>
- 警告フォーマット:
警告が発出されない場合(サイレントスキップ)
Section titled “警告が発出されない場合(サイレントスキップ)”extensionsディレクトリが存在しない- 子ディレクトリに
gemini-extension.jsonがない - マニフェストファイルが読み取り不能
- マニフェストの JSON が構文的には有効だが意味的に不完全または不規則
つまり、部分的な有効性は受け入れられ、JSON の構文エラーのみが警告を発出します。
他のソースとの優先順位と重複排除
Section titled “他のソースとの優先順位と重複排除”extensions ケーパビリティはケーパビリティレジストリによってプロバイダー横断で集約されます。
このケーパビリティの現在のプロバイダー:
native(packages/coding-agent/src/discovery/builtin.ts)優先度100gemini(packages/coding-agent/src/discovery/gemini.ts)優先度60
重複排除キーは ext.name(extensionCapability.key = ext => ext.name)です。
クロスプロバイダーの優先順位
Section titled “クロスプロバイダーの優先順位”重複する拡張名については、優先度の高いプロバイダーが勝ちます。
nativeとgeminiの両方が拡張名fooを出力する場合、native のアイテムが保持されます。- 優先度の低い重複は
_shadowed = trueの状態でresult.allにのみ保持されます。
プロバイダー内の順序の影響
Section titled “プロバイダー内の順序の影響”重複排除は「最初に見つかったものが優先」であるため、プロバイダーローカルのアイテム順序が重要です。
- Gemini ローダーは ユーザーを先に、次にプロジェクトを追加します。
- そのため、
~/.gemini/extensionsと<cwd>/.gemini/extensionsの間で名前が重複する場合、ユーザーのエントリが保持され、プロジェクトのエントリがシャドウされます。
対照的に、native プロバイダーは getConfigDirs() において異なる順序(project を先に、次に user)でコンフィグディレクトリを構築するため、native プロバイダー内でのシャドウイングの方向は逆になります。
ユーザーとプロジェクトの動作まとめ
Section titled “ユーザーとプロジェクトの動作まとめ”Gemini マニフェスト固有の動作として:
- ユーザーおよびプロジェクトの両ルートがロードのたびにスキャンされます。
- プロジェクトルートは
<cwd>/.gemini/extensionsに固定されます(祖先ディレクトリへのウォークなし)。 - Gemini ソース内での名前の重複はユーザー優先で解決されます。
- 優先度の高いプロバイダー(特に native)との名前の重複は優先度によって失われます。
境界: 検出メタデータとランタイム拡張ロード
Section titled “境界: 検出メタデータとランタイム拡張ロード”gemini-extension.json の検出は現在、ケーパビリティメタデータ(Extension アイテム)にフィードされます。実行可能な TS/JS 拡張モジュールを直接ロードするものではありません。
ランタイムモジュールロード(discoverAndLoadExtensions() / loadExtensions())は extension-modules と明示的なパスを使用し、現在は自動検出されたモジュールをプロバイダー native のみにフィルタリングしています。
実際的な意味合い:
- Gemini マニフェスト拡張はケーパビリティレコードとして検出可能です。
- それ自体では、拡張ローダーパイプラインによってランタイム拡張モジュールとして実行されることはありません。
この境界は現在の実装において意図的なものであり、マニフェスト検出と実行可能モジュールのロードが乖離する可能性がある理由を説明しています。