- ホーム
- Documentation
- 拡張機能
- 拡張機能の読み込み(TypeScript/JavaScript モジュール)
拡張機能の読み込み(TypeScript/JavaScript モジュール)
このドキュメントでは、コーディングエージェントが起動時に拡張機能モジュール(.ts/.js)を検出し読み込む方法について説明します。
gemini-extension.json マニフェスト拡張機能については対象外です(別途ドキュメント化されています)。
このサブシステムの機能
Section titled “このサブシステムの機能”拡張機能の読み込みは、モジュールエントリファイルのリストを構築し、各モジュールを Bun でインポートし、そのファクトリを実行して、以下を返します:
- 読み込まれた拡張機能の定義
- パスごとの読み込みエラー(全体の読み込みを中断しない)
- 後で
ExtensionRunnerが使用する共有の拡張機能ランタイムオブジェクト
主要な実装ファイル
Section titled “主要な実装ファイル”src/extensibility/extensions/loader.ts— パス検出 + インポート/実行src/extensibility/extensions/index.ts— 公開エクスポートsrc/extensibility/extensions/runner.ts— 読み込み後のランタイム/イベント実行src/discovery/builtin.ts— 拡張機能モジュール用のネイティブ自動検出プロバイダーsrc/config/settings.ts— マージされたextensions/disabledExtensions設定の読み込み
拡張機能読み込みへの入力
Section titled “拡張機能読み込みへの入力”1) 自動検出されたネイティブ拡張機能モジュール
Section titled “1) 自動検出されたネイティブ拡張機能モジュール”discoverAndLoadExtensions() は、まず検出プロバイダーに extension-module ケイパビリティ項目を問い合わせ、次にプロバイダー native の項目のみを保持します。
有効なネイティブの場所:
- プロジェクト:
<cwd>/.xcsh/extensions - ユーザー:
~/.xcsh/agent/extensions
パスルートはネイティブプロバイダー(SOURCE_PATHS.native)から取得されます。
注意事項:
- ネイティブの自動検出は現在
.xcshベースです。 - レガシー
.piはpackage.jsonマニフェストキー(pi.extensions)では引き続き受け入れられますが、ここではネイティブルートとしては使用されません。
2) 明示的に設定されたパス
Section titled “2) 明示的に設定されたパス”自動検出の後、設定されたパスが追加・解決されます。
メインセッション起動パス(sdk.ts)における設定パスのソース:
- CLI で指定されたパス(
--extension/-e、および--hookも拡張機能パスとして扱われます) - 設定の
extensions配列(グローバル + プロジェクト設定のマージ)
グローバル設定ファイル:
~/.xcsh/agent/config.yml(またはPI_CODING_AGENT_DIRによるカスタムエージェントディレクトリ)
プロジェクト設定ファイル:
<cwd>/.xcsh/settings.json
例:
extensions: - ~/my-exts/safety.ts - ./local/ext-pack{ "extensions": ["./.xcsh/extensions/my-extra"]}有効化/無効化の制御
Section titled “有効化/無効化の制御”検出の無効化
Section titled “検出の無効化”- CLI:
--no-extensions - SDK オプション:
disableExtensionDiscovery
動作の違い:
- SDK:
disableExtensionDiscovery=trueの場合でも、loadExtensions()を通じてadditionalExtensionPathsは読み込まれます。 - CLI パスの構築(
main.ts)では、--no-extensionsが設定されると CLI 拡張機能パスがクリアされるため、そのモードでは明示的な-e/--hookは転送されません。
特定の拡張機能モジュールの無効化
Section titled “特定の拡張機能モジュールの無効化”disabledExtensions 設定は拡張機能 ID 形式でフィルタリングします:
extension-module:<derivedName>
derivedName はエントリパスに基づきます(getExtensionNameFromPath)。例:
/x/foo.ts->foo/x/bar/index.ts->bar
例:
disabledExtensions: - extension-module:fooパスとエントリの解決
Section titled “パスとエントリの解決”パスの正規化
Section titled “パスの正規化”設定されたパスの場合:
- Unicode スペースの正規化
~の展開- 相対パスの場合、現在の
cwdに対して解決
設定されたパスがファイルの場合
Section titled “設定されたパスがファイルの場合”モジュールエントリ候補として直接使用されます。
設定されたパスがディレクトリの場合
Section titled “設定されたパスがディレクトリの場合”解決順序:
- そのディレクトリ内の
package.jsonにxcsh.extensions(またはレガシーpi.extensions)がある場合 -> 宣言されたエントリを使用 index.tsindex.js- それ以外の場合、1 レベルをスキャンして拡張機能エントリを検索:
- 直接の
*.ts/*.js - サブディレクトリの
index.ts/index.js - サブディレクトリの
package.jsonにxcsh.extensions/pi.extensions
- 直接の
ルールと制約:
- 1 つのサブディレクトリレベルを超える再帰的な検出は行われない
- 宣言された
extensionsマニフェストエントリは、そのパッケージディレクトリを基準に解決される - 宣言されたエントリは、ファイルが存在し/アクセスが許可されている場合のみ含まれる
*/index.{ts,js}のペアでは、TypeScript が JavaScript より優先される- シンボリックリンクは有効なファイル/ディレクトリとして扱われる
無視の動作はソースによって異なる
Section titled “無視の動作はソースによって異なる”- ネイティブの自動検出(検出ヘルパー内の
discoverExtensionModulePaths)は、gitignore: trueおよびhidden: falseでネイティブ glob を使用します。 loader.tsにおける明示的に設定されたディレクトリスキャンはreaddirルールを使用し、gitignore フィルタリングは適用しません。
読み込み順序と優先順位
Section titled “読み込み順序と優先順位”discoverAndLoadExtensions() は 1 つの順序付きリストを構築し、loadExtensions() を呼び出します。
順序:
- ネイティブで自動検出されたモジュール
- 明示的に設定されたパス(指定された順序で)
sdk.ts における設定順序:
- CLI の追加パス
- 設定の
extensions
重複排除:
- 絶対パスベース
- 最初に見つかったパスが優先
- 後の重複は無視される
含意:同じモジュールパスが自動検出と明示的な設定の両方に存在する場合、最初の位置(自動検出段階)で 1 回だけ読み込まれます。
モジュールのインポートとファクトリ契約
Section titled “モジュールのインポートとファクトリ契約”各候補パスは動的インポートで読み込まれます:
await import(resolvedPath)- ファクトリは
module.default ?? module - ファクトリは関数(
ExtensionFactory)でなければならない
エクスポートが関数でない場合、そのパスは構造化エラーで失敗し、読み込みは継続されます。
障害処理と分離
Section titled “障害処理と分離”拡張機能パスごとに、障害は { path, error } としてキャプチャされ、他のパスの読み込みを停止しません。
一般的なケース:
- インポート失敗 / ファイルが見つからない
- 無効なファクトリエクスポート(非関数)
- ファクトリ実行中にスローされた例外
ランタイム分離モデル
Section titled “ランタイム分離モデル”- 拡張機能はサンドボックス化されていません(同一プロセス/ランタイム)。
- 1 つの
EventBusと 1 つのExtensionRuntimeインスタンスを共有します。 - 読み込み中、ランタイムのアクションメソッドは意図的に
ExtensionRuntimeNotInitializedErrorをスローします。アクションの配線は後でExtensionRunner.initialize()で行われます。
ExtensionRunner を通じてイベントが実行される際、ハンドラーの例外はキャッチされ、ランナーループをクラッシュさせるのではなく拡張機能エラーとして発行されます。
最小限のユーザー/プロジェクトレイアウト例
Section titled “最小限のユーザー/プロジェクトレイアウト例”ユーザーレベル
Section titled “ユーザーレベル”~/.xcsh/agent/ config.yml extensions/ guardrails.ts audit/ index.tsプロジェクトレベル
Section titled “プロジェクトレベル”<repo>/ .xcsh/ settings.json extensions/ checks/ package.json lint-gates.tschecks/package.json:
{ "xcsh": { "extensions": ["./src/check-a.ts", "./src/check-b.js"] }}レガシーマニフェストキーも引き続き受け入れられます:
{ "pi": { "extensions": ["./index.ts"] }}