Skip to content

Entrée d'extension : flux de démarrage activate

源码版本v4.0.10

Responsabilités

activate() est le point d'entrée (entry point) appelé par VSCode lorsque l'utilisateur déclenche pour la première fois une fonctionnalité de l'extension. Il est défini dans apps/vscode/src/extension.ts. Cline y découpe tout le processus de démarrage en cinq étapes : d'abord mettre en place le HostProvider lié à la plateforme, puis nettoyer les formats de stockage hérités de la version précédente, ensuite exporter le stockage natif de VSCode vers un stockage de fichiers partagé, puis exécuter une initialisation multi-plateforme (initialize), et seulement alors enregistrer les commandes, vues, URI handler et CodeAction Provider propres à VSCode. Toute la fonction se termine par createClineAPI, qui renvoie un objet API minimal que les consommateurs externes peuvent appeler directement.

Son intérêt est de séparer « comment l'extension est levée par VSCode » — un sujet lié à la plateforme — de « comment Cline lui-même s'initialise » — un sujet multi-plateforme. Le initialize() de common.ts est partagé par les trois hôtes VSCode, CLI et JetBrains (initialize:34). extension.ts se borne à brancher le context, les commandes et les URI propres à VSCode. C'est pourquoi, en lisant extension.ts, vous ne voyez quasiment que des appels du genre vscode.commands.registerCommand(...) : l'assemblage réel des services se trouve dans initialize() et le constructeur de Controller.

Motivation de conception

  • L'abstraction plateforme avant tout : setupHostProvider doit s'exécuter en premier (setupHostProvider:73), car tous les services suivants obtiennent webview, terminal et callback URL via HostProvider.get(). Les implémentations propres à VSCode (VscodeWebviewProvider, VscodeTerminalManager, etc.) y sont injectées.
  • Migration avant export : cleanupLegacyVSCodeStorage s'exécute avant exportVSCodeStorageToSharedFiles (cleanupLegacyVSCodeStorage:78). Il nettoie d'abord les données historiques (workspace→global, task history→fichier, custom instructions→rules), puis exporte un state propre vers ~/.cline/data/, afin que les autres plateformes lisent un état cohérent.
  • Initialisation partagée dans common.ts : les services multi-plateformes (StateManager, ErrorService, PostHog, ClineTempManager, FileContextTracker, etc.) sont levés dans initialize() (external services:56), VSCode ne les réinvente pas. Ainsi CLI et JetBrains réutilisent le même démarrage.
  • Webview en retainContextWhenHidden : registerWebviewViewProvider reçoit retainContextWhenHidden: true (webview retain:124), pour que l'état React ne se perde pas quand la sidebar se ferme et que la réouverture n'entraîne pas de re-render. Le coût est une mémoire résidente, mais le contexte de conversation Cline mérite cette dépense.
  • Enregistrement des commandes en deux couches : les commandes VSCode tirent d'abord leurs ID constants de ExtensionRegistryInfo.commands (ExtensionRegistryInfo:130), pour garantir la cohérence des command ID entre package.json et le code. En mode dev, des commandes de debug sont également chargées depuis dev/commands/tasks (dev commands:193).
  • URI handler avec repli et retry : quand handleUri traite un deep link et que la sidebar n'est pas encore initialisée, il appelle openClineSidebarForTaskUri puis retente (task uri retry:178), afin d'éviter la race condition entre l'initialisation de la sidebar et l'arrivée du deep link à la première installation.

Fichiers clés

  • activate:68 — entrée de toute l'extension, le démarrage en cinq étapes se trouve ici.
  • setupHostProvider call:73 — première étape, assemble le HostProvider VSCode (webview, diff, comment review, terminal, callback URL).
  • cleanupLegacyVSCodeStorage:78 — deuxième étape, nettoie les formats historiques workspace→global, task history→file, custom instructions→rules.
  • exportVSCodeStorageToSharedFiles:84 — troisième étape, exporte le stockage natif VSCode vers ~/.cline/data/, le stockage de fichiers partagé lisible par les autres plateformes.
  • initialize call:88 — quatrième étape, exécute l'initialisation multi-plateforme de common.ts, renvoie VscodeWebviewProvider.
  • registerWebviewViewProvider:124 — enregistre la webview sidebar auprès de VSCode, active retainContextWhenHidden.
  • registerUriHandler:187 — enregistre l'URI handler, traite les deep links vscode://extension.id/cline/task/....
  • registerCodeActionsProvider:248 — enregistre le CodeAction Provider, expose quatre actions « Add to Cline / Explain / Improve / Fix with Cline » sur l'ampoule d'erreur de l'éditeur.
  • setupHostProvider:602 — fonction effectuant l'assemblage du HostProvider, transmet les factory VscodeWebviewProvider, VscodeDiffViewProvider, VscodeTerminalManager, etc.
  • createClineAPI:553 — renvoie l'API externe, expose startNewTask, sendMessage, pressPrimaryButton, pressSecondaryButton.
  • initialize:34 — corps de l'initialisation multi-plateforme, StateManager, PostHog, ErrorService, syncWorker sont levés ici.
  • deactivate:699 — à la désactivation, appelle tearDown() + dispose du comment review controller.

Flux de données

La séquence de démarrage est visible en haut de activate. Le cœur est « migration avant initialisation, partagé avant plateforme » :

typescript
// 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

Ce bloc se trouve près de activation sequence:73. À l'intérieur de initialize() (createWebviewProvider:63), on appelle HostProvider.get().createWebviewProvider(). Cette factory renvoie une instance VscodeWebviewProvider qui, dans son constructeur, new synchro new Controller(context), lequel lève à son tour StateManager, AuthService, McpHub, BannerService et toute une chaîne de dépendances. À la fin de initialize(), Controller est donc déjà prêt à recevoir les messages de la webview. De retour dans activate(), la suite enregistre les commandes, l'URI handler et le CodeAction Provider ; ces enregistrements font tous transiter les requêtes vers webview.controller ou WebviewProvider.getInstance().

Limites et échecs

  • Échec d'initialisation du StateManager non fatal : initialize() enveloppe StateManager.initialize dans un try/catch. En cas d'échec, il affiche un message ERROR mais poursuit (stateManager try:45), car le stockage reste utilisable en mémoire, seule la persistance est perdue.
  • Race entre task URI et initialisation de la sidebar : l'URI handler tente d'abord de traiter le deep link task ; en cas d'échec, il appelle openClineSidebarForTaskUri puis attend que la sidebar soit visible pour réessayer (task uri retry:178), avec un délai maximal de 3 secondes.
  • Commandes dev chargées en asynchrone : dans la branche IS_DEV, les commandes de debug sont chargées via import("./dev/commands/tasks") dynamique (dev import:193). En cas d'échec, on se contente de loguer, sans impacter le flux principal.
  • Synchronisation cross-fenêtre des secrets : écoute storageContext.secrets.onDidChange. Quand cline:clineAccountId change, la nouvelle valeur signifie qu'une autre fenêtre s'est connectée, une valeur vide qu'une autre fenêtre s'est déconnectée (secrets listener:533), ce qui maintient la cohérence de l'état de login entre fenêtres.
  • Détection du chemin ripgrep : VSCode 1.122 migre ripgrep de @vscode/ripgrep vers @vscode/ripgrep-universal. getBinaryLocation tente d'abord la nouvelle disposition, et repli sur l'ancien chemin en cas d'échec (ripgrep path probe:685).
  • deactivate appelle tearDown : deactivate() appelle le tearDown() de common.ts (tearDown:153), qui dispose dans l'ordre PostHog, telemetry, ErrorService, featureFlags, WebviewProvider, syncWorker, HookProcessRegistry, ClineTempManager, pour éviter de laisser des zombies.

Résumé

activate() sépare proprement la spécificité plateforme VSCode de la logique métier de Cline : côté VSCode, on ne fait qu'enregistrer commandes, vues, URI handler et CodeAction ; l'assemblage réel des services est délégué à initialize() de common.ts et au constructeur de Controller. Cette séparation permet à CLI et JetBrains de réutiliser la même initialisation. Pour voir comment Controller assemble les dépendances et relie webview et Task, voir /startup/controller ; pour voir comment webview et extension communiquent via gRPC-over-postMessage, voir /startup/webview-bridge.

Voir la documentation officielle : documentation Cline · README.