拡張エントリ: activate 起動フロー
役割
activate() は VSCode 拡張がユーザーに初めて拡張機能をトリガーされた時に呼ばれるエントリで、apps/vscode/src/extension.ts に書かれている。Cline は起動全体をここで五つのステップに分ける。まずプラットフォーム依存の HostProvider を組み、次に前バージョンが残したストレージ形式を整理し、VSCode 自身のストレージを共有ファイルストレージにエクスポートし、クロスプラットフォーム初期化 (initialize) を走らせ、最後に VSCode 専用のコマンド、ビュー、URI handler、CodeAction Provider を登録する。関数全体は createClineAPI で締めくくり、外部利用者が直接呼べるミニマムな API オブジェクトを返す。
これが存在する意義は、「拡張がどう VSCode に立ち上げられるか」というプラットフォーム依存の事柄と、「Cline 自身がどう初期化されるか」というクロスプラットフォームの事柄を分離することにある。common.ts の initialize() は VSCode、CLI、JetBrains の三つの host で共通利用され (initialize:34)、extension.ts は VSCode 固有の context、コマンド、URI などを接ぐことだけを担う。そのため extension.ts を読むと vscode.commands.registerCommand(...) といった登録動作がほとんどで、本当のサービス組み立ては initialize() と Controller のコンストラクタにある。
設計動機
- プラットフォーム抽象を最優先:
setupHostProviderが先に走る必要がある (setupHostProvider:73)。後続のすべてのサービスはHostProvider.get()で webview、ターミナル、コールバック URL を取得するから。VSCode 固有の実装 (VscodeWebviewProvider、VscodeTerminalManager 等) はここで注入される。 - マイグレーションをエクスポートより先に:
cleanupLegacyVSCodeStorageはexportVSCodeStorageToSharedFilesの前に走る (cleanupLegacyVSCodeStorage:78)。workspace→global、task history→ファイル、custom instructions→rules といった過去の汚れたデータを先に掃除してから、きれいな state を~/.cline/data/にエクスポートし、他プラットフォームが一貫した状態を読めるようにする。 - 共通初期化を common.ts に切り出し:クロスプラットフォームサービス (StateManager、ErrorService、PostHog、ClineTempManager、FileContextTracker 等) はすべて
initialize()の中で立ち上がる (external services:56)。VSCode はこれを再実装しない。これにより CLI と JetBrains が同じ起動ロジックを再利用できる。 - webview は retainContextWhenHidden を使用:
registerWebviewViewProviderにretainContextWhenHidden: trueを渡す (webview retain:124)。サイドバーが閉じても React の状態が失われず、次回オープン時に再レンダリング不要となる。代償はメモリ常駐だが、Cline の会話コンテキストはこのオーバーヘッドに見合う価値がある。 - コマンドを二段階で登録:VSCode コマンドはまず
ExtensionRegistryInfo.commandsから ID 定数を取得し (ExtensionRegistryInfo:130)、package.json とコード上の command ID の一致を保証する。Dev モードでは追加でdev/commands/tasksのデバッグコマンドを読み込む (dev commands:193)。 - URI handler のリトライで競合を吸収:
handleUriがディープリンクを処理する際、サイドバーがまだ初期化されていなければopenClineSidebarForTaskUriを呼んでから再度処理する (task uri retry:178)。初回インストール時にサイドバー初期化とディープリンク到着が竞合するのを防ぐためである。
主要ファイル
activate:68— 拡張のエントリ全体。五段階の起動フローがここに集まる。setupHostProvider call:73— 第一ステップ。VSCode 版 HostProvider (webview、diff、comment review、terminal、callback URL) を組み立てる。cleanupLegacyVSCodeStorage:78— 第二ステップ。workspace→global、task history→file、custom instructions→rules などの過去形式を整理する。exportVSCodeStorageToSharedFiles:84— 第三ステップ。VSCode ネイティブストレージを~/.cline/data/の共有ファイルストレージにエクスポートし、他プラットフォームが読めるようにする。initialize call:88— 第四ステップ。common.tsのクロスプラットフォーム初期化を走らせ、VscodeWebviewProviderを返す。registerWebviewViewProvider:124— サイドバー webview を VSCode に登録し、retainContextWhenHiddenを有効化する。registerUriHandler:187— URI handler を登録し、vscode://extension.id/cline/task/...といったディープリンクを処理する。registerCodeActionsProvider:248— CodeAction Provider を登録し、エディタのエラーランプに「Add to Cline / Explain / Improve / Fix with Cline」の四つのアクションを取り付ける。setupHostProvider:602— HostProvider を組み立てる実際の関数。VscodeWebviewProvider、VscodeDiffViewProvider、VscodeTerminalManager などのファクトリ関数を渡す。createClineAPI:553— 外部 API を返す。startNewTask、sendMessage、pressPrimaryButton、pressSecondaryButtonの四つのメソッドを提供する。initialize:34— クロスプラットフォーム初期化の本体。StateManager、PostHog、ErrorService、syncWorker をここで立ち上げる。deactivate:699— 非アクティブ化時にtearDown()を呼び、comment review controller を dispose する。
データフロー
起動順序は activate の先頭で一目で分かる。核心は「マイグレーションを先に、初期化を後に。共有を先に、プラットフォームを後に」である:
// apps/vscode/src/extension.ts
// 1. Set up HostProvider for VSCode
setupHostProvider(context)
// 2. Clean up legacy data patterns within VSCode's native storage.
await cleanupLegacyVSCodeStorage(context)
// 3. One-time export of VSCode's native storage to shared file-backed stores.
const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath
const storageContext = createStorageContext({ workspacePath })
await exportVSCodeStorageToSharedFiles(context, storageContext)
// 4. Register services and perform common initialization
const webview = (await initialize(storageContext)) as VscodeWebviewProviderこの部分は activation sequence:73 の付近にある。initialize() の内部 (createWebviewProvider:63) で HostProvider.get().createWebviewProvider() を呼ぶと、ファクトリメソッドが VscodeWebviewProvider インスタンスを返す。このインスタンスは構築時に同期的に new Controller(context) を呼び、Controller のコンストラクタで StateManager、AuthService、McpHub、BannerService などの一連の依存が立ち上がる。したがって initialize() が返る時点で Controller は既に webview メッセージを受け取る準備が整っている。activate() の後半に戻ってからコマンド、URI handler、CodeAction Provider を登録するが、これらの登録动作は最終的にリクエストを webview.controller か WebviewProvider.getInstance() に転送する。
境界と失敗
- StateManager 初期化失敗は致命的ではない:
initialize()はStateManager.initializeを try/catch で囲み、失敗すると ERROR メッセージを出すが処理は続行する (stateManager try:45)。ストレージはメモリ上でも使えるため、永続化できないだけですむ。 - task URI とサイドバー初期化の競合:URI handler は最初に task ディープリンクの処理を試み、失敗したら
openClineSidebarForTaskUriでサイドバーが可視になるのを待って再試行する (task uri retry:178)。最大 3 秒待つ。 - dev モードの追加コマンドは非同期読み込み:
IS_DEV分岐では動的import("./dev/commands/tasks")でデバッグコマンドを読み込む (dev import:193)。失敗はログに記録するだけでメインフローには影響しない。 - secrets のウィンドウ間同期:
storageContext.secrets.onDidChangeを監視し、cline:clineAccountIdが変化した時、新値は別ウィンドウでのログインを、空値は別ウィンドウでのログアウトを意味する (secrets listener:533)。これにより複数ウィンドウ間でログイン状態を一貫させる。 - ripgrep のパスプローブ:VSCode 1.122 で ripgrep が
@vscode/ripgrepから@vscode/ripgrep-universalに移行した。getBinaryLocationは新しい配置を先に探し、失敗したら古いパスにフォールバックする (ripgrep path probe:685)。 - deactivate は tearDown を呼ぶ:
deactivate()はcommon.tsのtearDown()を呼び (tearDown:153)、PostHog、telemetry、ErrorService、featureFlags、WebviewProvider、syncWorker、HookProcessRegistry、ClineTempManager の順に dispose しゾンビプロセスを残さない。
まとめ
activate() は VSCode 固有の機能と Cline のビジネスロジックをきれいに分けている。VSCode 側はコマンド、ビュー、URI handler、CodeAction の登録だけを担い、本当のサービス組み立ては common.ts の initialize() と Controller のコンストラクタに委ねられる。このレイヤ分けにより CLI と JetBrains は同じ初期化コードを再利用できる。初期化後に Controller がどう依存を組み立て、webview と Task をどう繋ぐかは /startup/controller に、webview と拡張の間で gRPC-over-postMessage でどう通信するかは /startup/webview-bridge に続く。
公式資料: Cline ドキュメント · README