integrated-browser について
VS Code 統合ブラウザーの開発者向けアーキテクチャスキルです。Chromium ページのプロセス境界、状態管理、セキュリティ、および機能拡張の仕組みを説明します。
主な機能
- 01Electron WebContentsView による Chromium の埋め込み
- 02メイン・共有・レンダラープロセスの役割
- 03IPC を介したページ状態と操作
- 04セッション、グループ、CDP の分離
- 05エディターコントリビューションによる拡張
活用シーン
- 01コード変更前のブラウザー構造の把握
- 02ページ状態や操作の追加
- 03ページ共有と信頼境界の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ microsoft/ vscode --skill integrated-browserインストール後、Claude Code で/integrated-browserを入力して読み込まれたか確認します。
詳細
統合ブラウザーのアーキテクチャ
統合ブラウザー(「browserView」)は、Electron の WebContentsView を基盤として、VS Code に実際の Chromium ブラウザーを埋め込みます。ライブページを表示し、それぞれをエディタータブとして提示し、エージェントがツールを通じてページを操作できるようにします。製品内のブラウザータブと、エージェントの「browser」ツールを支えています。これは従来の extensions/simple-browser(webview 内の iframe)ではありません。デスクトップでは、現在はこちらに処理を委譲します。
これは重量級でセキュリティに慎重な配慮が必要な、マルチプロセスの基本機能であり、設計上のほぼすべての判断はここから導かれます。 このファイルでは、めったに変わらない重要な考え方について説明します。現在の機能/ツール/コマンド/設定は列挙しません。これらは頻繁に変わるため、最新情報は features/ と tools/ の各フォルダーを参照してください。ここで基本的な考え方を理解してから、変更するコードを確認してください。
すべての基本となる、唯一の考え方
ページとは、メインプロセスだけが作成、所有、配置できるネイティブの WebContentsView です。それ以外のものが直接触れることはできません。 メインプロセスが所有し、ワークベンチの DOM 内ではなく、OS のコンポジターによってその上に描画されます。それ以外のすべては、この前提に沿って動作します。
- レンダラー(エディター UI とエージェントツール)はページを保持できません。モデル/プロキシを保持し、IPC 経由でメインプロセスと通信します。
- Playwright は重量級で長時間稼働するため、共有プロセスで実行され、IPC 経由でページにアクセスします。
- ページは DOM の上に描画されるため、ワークベンチが位置合わせ、重なり順、フォーカス、スクリーンショットを手動で調整します。
3 つのプロセスと、その理由
| プロセス | 場所 | ここにあるもの |
|---|---|---|
| メイン | platform/browserView/electron-main | WebContentsView、セッション、信頼、権限、履歴、CDP、スクリーンショットなど、ページの正式な状態を管理します。ネイティブビューを作成できるのはメインプロセスだけです。 |
| 共有 | platform/browserView/node | Playwright とリモート/グループの自動化サービスがあります。重量級の依存関係をメインプロセス(安定性)およびレンダラー(ライフサイクル)から分離します。 |
| レンダラー | workbench/contrib/browserView + platform/browserView/electron-browser | エディターペイン、UI 機能のコントリビューション、エージェントツール、ページのプリロードスクリプトがあります。軽量なプロキシのみを保持します。 |
レイヤーのルール: platform から workbench をインポートしてはいけません。エージェントホストから workbench をインポートしてはいけません。共有型は platform/common に配置します。レンダラーは実装をインポートせず、ProxyChannel IPC 経由でメインプロセス/共有プロセスにアクセスします。ブラウザーイベントは、ホストウィンドウ単位でスコープされた、先行登録される単一の包括的なサブスクリプションを共有します。ワークベンチは、ライブの変更をモデルローカルイベントに振り分ける前に、初期スナップショットを適用します。バッファーは JSON オブジェクト内にネストせず、イベントメタデータと並ぶタプル/配列の要素として転送します。チャネルは electron-main/app.ts と electron-utility/sharedProcess/sharedProcessMain.ts に登録します。分担は次のとおりです。ページ操作/状態 → メイン、エージェントの自動化 → 共有、CDP の配線は独立したチャネルで、レンダラーと共有プロセスの両方がメインプロセスへのアクセスに使用します。
レンダラーは真実ではなく、鏡を映します
レンダラーモデルは、メインプロセスのビューが所有する状態の読み取りレプリカです。フローは一方向です。
renderer feature ──command──▶ model ──IPC──▶ main BrowserView ──▶ Chromium
▲ │
└──────────── event (state changed) ◀──────────┘
何かを実行するにはメソッドを呼び出し(メインプロセスとの往復が発生します)、何かに反応するにはモデルイベントをリッスンします。レンダラーでページの状態を計算しないでください。レンダラーはウェブコンテンツにアクセスできません。
- 新しい状態(url/title/loading/zoom/…):メインの
BrowserViewを信頼できる情報源として更新し、変更イベントを発行してから、レンダラーモデルにフィールドとイベントをミラーリングし、BrowserViewMainServiceの型付き転送マップに追加します。転送はナビゲーションの前に設定してください。ブラウザーごとのIPCサブスクリプションは追加しないでください。各ウィンドウのサブスクリプションは現在のスナップショットから始まり、別途初期化RPCを呼び出さずにワークベンチの準備完了を定義します。ワークベンチは各ブラウザーのエミッターマップを所有し、それをモデルに渡して、ブラウザーIDとイベント名で直接ディスパッチします。モデルはイベントを消費するだけです。 - 新しい操作(navigate/reload/focus/…):メインで定義し、チャネルとの往復を行う薄いプロキシメソッドをレンダラーモデルに公開します。
ページ上の何かをレンダラーから「読み取りたい」と思ったら、それはメインから新しいミラー状態とイベントが必要だという合図です。
ネイティブビューはDOMの上に浮かびます(オーバーレイの問題)
最もエラーが発生しやすい領域であり、「動かない/位置がずれる/メニュー越しに見える/フォーカスできない」というバグのほぼすべての原因です。ページはレンダラーの上に、メインプロセスによって画面座標で描画されるため、ワークベンチは通常のDOM要素を模倣します。ページの矩形、可視性、フォーカス、画像は、DOM上の事実ではなく、ワークベンチが調整するものとして扱ってください。
- 位置合わせ。 エディターは空のDOMスタブを描画し、その画面上の矩形を測定して、境界をメインプロセスに送信します。CSSのズーム率と画面ピクセルは一致しないため、境界はピクセル単位でスナップされます。ページを移動させる新しいレイアウトは、DOMボックスを動かすだけでなく、この境界計算にも反映してください。
- Z順序。 ネイティブビューはすべてのワークベンチUIの上に描画されるため、ページの上に表示するメニュー/ポップアップ/ホバー/ダイアログは隠れてしまいます。ワークベンチは重なりを検出し、ネイティブビューを隠してプレースホルダーに切り替えます。ページ上に新しいフローティングUIを表示する場合は、この仕組みで検出できるようにしてください。CSSのz-indexを高くしても解決しません。
- ちらつきのマスク。 非表示中または位置変更中は、定期的なスクリーンショットで代用します。スクリーンショットは、ページの画像をレンダラーやエージェントに渡す正当な唯一の方法でもあります。ネイティブのピクセルを読み取るものはありません。
- フォーカスとキーボード。 フォーカスは明示的に橋渡しされます。すべてのページに分離ワールドで挿入されるプリロードスクリプトが、ページ内にとどめるキー入力と、VS Codeのキーバインドに転送するキー入力を判断します。これは信頼境界として扱ってください。悪意のあるページを想定し、最小限かつ副作用のないものにしてください。
ブラウザータブは、コントリビューションで拡張された本物のエディターです
ページは通常のエディターです。標準レジストリに登録された読み取り専用かつシリアライズ可能なEditorInputとEditorPaneであり、ビュー・モデルへの解決は遅延されます(タブを閉じずにアンロードできます)。これにより、タブ、分割、永続化、フォーカス、キーバインドのスコープをそのまま利用できます。
ペインは薄く保たれます。動作は、ローカルコントリビューションモデル(ワークベンチのコントリビューションとは別)を使って追加します。これはエディターにアタッチされ、DIを受け取り、固定されたライフサイクル(モデルのアタッチ/デタッチ、レイアウトのオーバーライド、リサイズ/可視性、フォーカス、UIの挿入)にフックする小さなクラスです。それぞれのライフタイムはアタッチされたモデルにスコープされるため、ページごとの破棄可能オブジェクトはナビゲーション/終了時にクリーンアップされます。ネイティブビューのレンダリングも、単なる1つのコントリビューションです。
動作を追加するには、既存の同種のコントリビューションを手本に新しいコントリビューションを作成してください。エディターやメインビューを拡張しないでください。 ページの矩形に影響するコントリビューションは、優先度付きレイアウトオーバーライドを通じて組み合わされます(優先度の低いものから実行されます。たとえば、エミュレーションがビューポートのサイズを設定し、ピクセルスナップが最後に実行されます)。そのため、順序が重要です。ピクセル値をハードコードしないでください。
ID と分離:セッション、グループ、CDP
次の3つは明確に区別してください。
- セッション=ストレージ ID。 各 Electron セッションは1つの
BrowserSession(Cookie、キャッシュ、ストレージ)に1対1で対応し、その ID はCDP のブラウザーコンテキスト ID も兼ねます。グローバル、ワークスペースごと、または一時的なスコープで設定でき、複数のタブで共有できます。セキュリティはここで適用されます。file://、証明書の信頼、権限はすべてセッションで制御されます(たとえば、ローカルファイルにはワークスペースの信頼が必要です)。ページがアクセスできる範囲を広げる新機能は、機能側ではなくここに追加します。 - グループ=自動化の可視性。 グループは動的なビューの集合をまとめ、1つの論理的な CDP「ブラウザー」として公開します。グループはビューを参照しますが、所有はしません。1つのビューを複数のグループに含めることができます。これにより、異なるクライアント(チャットセッション、DevTools、拡張機能)が、それぞれ自分のサブセットだけを表示できます。
- CDP はプロキシ経由であり、直接公開されることはありません。 プロトコルを認識するプロキシが、ブラウザー/ターゲットレベルのドメイン(探索、自動アタッチ、フラット化セッション、コンテキスト)を実装し、残りをターゲットごとに転送します。これにより、ビューが動的に追加・削除される場合でも、複数のビューから1つの論理的なブラウザーを構成でき、Chromium に直接触れずに Playwright を接続できます。
Cookie/ログイン/ストレージ → セッション。「このクライアントに見えるページはどれか」→ グループ。プロトコルそのもの → プロキシ。
プライバシーゲートのもとで、エージェントはユーザーのページを共有します
- 同じページを協調して共有します。 Playwright は CDP を介して、ユーザーに表示されているのと同じ
WebContentsViewを操作します。接続はチャットセッションごとに1つです。人間とエージェントの操作が衝突することがありますが、競合はユーザー側に有利になるよう解決されます(人間によるプロンプトやダイアログが自動化を中断する場合があります)。デバイスエミュレーションを管理するのは Playwright ではなくワークベンチです。そのため、エージェントのアクション中を除き、Playwright の自動エミュレーションは抑制されます。同じページを人間が同時に操作する可能性があるものとして扱ってください。 - ページは共有されるまで非公開です。 コンテンツはデフォルトではエージェントに表示されません。ページの共有状態によってコンテンツへのアクセスが制御されます。別の利用可能性ゲート(チャットが有効か、エージェントモードか、設定)によって、ツール一式を登録するかどうかが決まります。登録されない場合、コンテンツにアクセスせずに URL を開く機能だけが縮小版として提供されます。URL はネットワークフィルターで検査され、ブロックされた場合はマスクされます。ページコンテンツは信頼できないモデル入力(プロンプトインジェクション)として扱ってください。新しいエージェント向けのサーフェスは、必ずこれらのゲートに従う必要があります。(ツールの名前は
platformに置きます。workbenchに依存できないエージェントホストから参照できるようにするためです。)
リモートページ
ブラウザーコンテキスト(そのストレージ)は、ネットワーク(ローカル、または権限によって決まるリモートネットワーク)に紐づきます。リモートネットワークには、ウィンドウのリモート(リモートワークスペースのウィンドウ)またはリモートエージェントホスト(Agents ウィンドウのセッション)があります。タブには要求されたセッション(ストレージスコープ、アフィニティ、ネットワーク)が保存されます。作成時には、その要求を上書きせずに、現在の信頼設定とプロキシ制限が適用されます。ポップアップと自動化コンテキストは、親のネットワークを引き継ぎます。リモートトラフィックには、ウィンドウ内のローカル拡張ホストにある HTTPS プロキシを使用します。プロキシの起動に失敗した場合、ローカル接続にフォールバックせず、ビューの作成が失敗します。プロキシに対応していないことが判明しているホストでは、新しいタブはローカルネットワークを使用し、警告を表示します。
ネットワークは、所有者、対象ユーザー、ポリシーではなく、ブラウザーコンテキストに属します。グローバルストレージは常にローカルです。ワークスペースストレージはウィンドウのネットワークを使用します。その他のネットワークでは、ストレージフォルダー内のパーティションを選択するために、ストレージのアフィニティ(エージェントホストとフォルダールート)が必要です。アフィニティがない場合は、ビューごとにメモリ内ストレージを使用します。ワークスペースストレージを消去すると、これらのパーティションも消去されます。
テスト戦略
すべてのテストレイヤーは簡潔に保ち、シナリオに焦点を当ててください。 失敗するとブラウザーの主要なシナリオに影響する重要な機能を保護し、実際のリスクを検証できる最も低コストのレイヤーを使用してください。複数のレイヤーで同じ動作を重複してテストしたり、付随的な実装の詳細を固定したりしないでください。
- ユニットテストでは、状態遷移、プロトコル変換、永続化ルール、セキュリティゲート、エラー処理など、重要な独立したロジックを対象にします。些細な分岐や非公開の構造を網羅的にテストするのではなく、代表的なケースを使用してください。
- ウィジェットテストでは、ネイティブページを必要としない、主要なレンダラーの操作、コマンド、コンテキストキーに応じた表示、中心的なレンダリング動作を対象にします。その構造自体が契約でない限り、ピクセル単位や DOM 構造のアサーションは避けてください。
extensions/vscode-api-tests/src/singlefolder-tests/browser*.test.tsにある 拡張機能 API テストは、ブラウザー API、CDP の動作、ブラウザーツール、拡張機能ホストとの接続、拡張機能に公開されるプロセス間の契約に適した統合テストレイヤーです。- その他の E2E 統合テストでは、実際のサービスを必要とするものの、ワークベンチを完全に通して操作する必要はない、重要なプロセス境界やランタイム統合を対象にします。
- スモークテストでは、実際の Electron ワークベンチ、レンダラー/メイン/共有プロセス間の接続、またはネイティブの
WebContentsViewが必要となる、重要なユーザージャーニーのみを対象にします。これには、プリロードでのキーボードルーティング、ネイティブビューのフォーカス/表示/ライフサイクル、Electron の権限、ポップアップエディター、ネイティブビュー上のワークベンチ UI、ページからチャットへのライブ添付に関する主要なリスクが含まれます。各テストはハッピーパスの要点に絞り、関連するアサーションは一貫性のある1つのジャーニーにまとめ、バリエーション、エッジケース、見た目の詳細は低コストのレイヤーに委ねてください。
適切なアサーションはユーザーとの契約を表し、動作を損なわない変更やリファクタリング後も安定しています。テストでは、失敗するとブラウザーの主要なシナリオに実質的な影響がある動作を保護し、その失敗モードを検証できる最も低コストのレイヤーに配置してください。スモークテストは、一貫性を保てる場合は既存のジャーニーを拡張し、主要なジャーニーについてはシナリオ数を少数に抑えてください。
実践的なガイダンス
- デスクトップ専用です。 Web では何も実行されません。
electron-*/nodeに追加し、browser/のスタブが「Web では利用できません」というエラーをスローするようにしてください。 - 既存のパターンに合わせてください。 新しい機能は、新しい機能コントリビューションやツールとして、類似のものを参考に実装します。プロセス間の状態は、ローカルなレンダラーの状態ではなく、メインからモデルメソッドとイベントで扱います。レイアウト変更は、ピクセル単位の指定ではなく、優先順位付きのオーバーライドで行います。
- 信頼境界に注意してください。 プリロード(悪意あるページ)、セッション(ストレージ/権限/ファイルアクセス)、エージェントのゲーティング(共有+利用可否+ネットワークフィルター)、チャットへの添付(プロンプトインジェクション)です。