Compare commits

...
2 Commits
Author SHA1 Message Date
Sarah Fortune a4b80448da Comments and logging 2025-08-08 16:40:15 +01:00
Sarah Fortune 5488e3e34a Don't use activate() in cline-core
Have separate code paths to set up the extension and cline-core.

This means the cline-core is not running all the vscode setup and is
only using one `Controller` (the one from the WebviewProvider).

Move the shared logic into common.ts.
2025-08-08 16:32:04 +01:00
4 changed files with 120 additions and 95 deletions
+92
View File
@@ -0,0 +1,92 @@
import * as vscode from "vscode"
import {
migrateCustomInstructionsToGlobalRules,
migrateWelcomeViewCompleted,
migrateWorkspaceToGlobalStorage,
} from "./core/storage/state-migrations"
import { WebviewProvider } from "./core/webview"
import { Logger } from "./services/logging/Logger"
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
import { WebviewProviderType } from "./shared/webview/types"
import "./utils/path" // necessary to have access to String.prototype.toPosix
import { HostProvider } from "@/hosts/host-provider"
import { FileContextTracker } from "./core/context/context-tracking/FileContextTracker"
import { telemetryService } from "./services/posthog/PostHogClientProvider"
import { ShowMessageType } from "./shared/proto/host/window"
import { getLatestAnnouncementId } from "./utils/announcements"
/**
* Performs intialization for Cline that is common to all platforms.
*
* @param context
* @returns The webview provider
*/
export async function initialize(context: vscode.ExtensionContext): Promise<WebviewProvider> {
// Initialize PostHog client provider
const distinctId = context.globalState.get<string>("cline.distinctId")
PostHogClientProvider.getInstance(distinctId)
// Migrate custom instructions to global Cline rules (one-time cleanup)
await migrateCustomInstructionsToGlobalRules(context)
// Migrate welcomeViewCompleted setting based on existing API keys (one-time cleanup)
await migrateWelcomeViewCompleted(context)
// Migrate workspace storage values back to global storage (reverting previous migration)
await migrateWorkspaceToGlobalStorage(context)
// Clean up orphaned file context warnings (startup cleanup)
await FileContextTracker.cleanupOrphanedWarnings(context)
const sidebarWebview = HostProvider.get().createWebviewProvider(WebviewProviderType.SIDEBAR)
await showVersionUpdateAnnouncement(context)
telemetryService.captureExtensionActivated()
return sidebarWebview
}
async function showVersionUpdateAnnouncement(context: vscode.ExtensionContext) {
// Version checking for autoupdate notification
const currentVersion = context.extension.packageJSON.version
const previousVersion = context.globalState.get<string>("clineVersion")
// Perform post-update actions if necessary
try {
if (!previousVersion || currentVersion !== previousVersion) {
Logger.log(`Cline version changed: ${previousVersion} -> ${currentVersion}. First run or update detected.`)
// Use the same condition as announcements: focus when there's a new announcement to show
const lastShownAnnouncementId = context.globalState.get<string>("lastShownAnnouncementId")
const latestAnnouncementId = getLatestAnnouncementId(context)
if (lastShownAnnouncementId !== latestAnnouncementId) {
// Focus Cline when there's a new announcement to show (major/minor updates or fresh installs)
const message = previousVersion
? `Cline has been updated to v${currentVersion}`
: `Welcome to Cline v${currentVersion}`
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
await new Promise((resolve) => setTimeout(resolve, 200))
HostProvider.window.showMessage({
type: ShowMessageType.INFORMATION,
message,
})
}
// Always update the main version tracker for the next launch.
await context.globalState.update("clineVersion", currentVersion)
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
console.error(`Error during post-update actions: ${errorMessage}, Stack trace: ${error.stack}`)
}
}
/**
* Performs cleanup when Cline is deactivated that is common to all platforms.
*/
export async function tearDown(): Promise<void> {
PostHogClientProvider.getInstance().dispose()
// Dispose all webview instances
await WebviewProvider.disposeAllInstances()
}
@@ -3,6 +3,7 @@ import { Controller } from "../index"
import { EmptyRequest } from "@shared/proto/cline/common"
import { StreamingResponseHandler, getRequestRegistry } from "../grpc-handler"
import { State } from "@shared/proto/cline/state"
import { ExtensionState } from "@/shared/ExtensionMessage"
// Keep track of active state subscriptions by controller ID
const activeStateSubscriptions = new Map<string, StreamingResponseHandler<State>>()
@@ -52,7 +53,7 @@ export async function subscribeToState(
* @param controllerId The ID of the controller to send the state to
* @param state The state to send
*/
export async function sendStateUpdate(controllerId: string, state: any): Promise<void> {
export async function sendStateUpdate(controllerId: string, state: ExtensionState): Promise<void> {
// Get the subscription for this specific controller
const responseStream = activeStateSubscriptions.get(controllerId)
+16 -78
View File
@@ -1,10 +1,10 @@
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import assert from "node:assert"
import { setTimeout as setTimeoutPromise } from "node:timers/promises"
import { DIFF_VIEW_URI_SCHEME } from "@hosts/vscode/VscodeDiffViewProvider"
import { WebviewProviderType as WebviewProviderTypeEnum } from "@shared/proto/cline/ui"
import assert from "node:assert"
import { setTimeout as setTimeoutPromise } from "node:timers/promises"
import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
import { sendAccountButtonClickedEvent } from "./core/controller/ui/subscribeToAccountButtonClicked"
@@ -12,33 +12,26 @@ import { sendChatButtonClickedEvent } from "./core/controller/ui/subscribeToChat
import { sendHistoryButtonClickedEvent } from "./core/controller/ui/subscribeToHistoryButtonClicked"
import { sendMcpButtonClickedEvent } from "./core/controller/ui/subscribeToMcpButtonClicked"
import { sendSettingsButtonClickedEvent } from "./core/controller/ui/subscribeToSettingsButtonClicked"
import {
migrateCustomInstructionsToGlobalRules,
migrateWelcomeViewCompleted,
migrateWorkspaceToGlobalStorage,
} from "./core/storage/state-migrations"
import { WebviewProvider } from "./core/webview"
import { createClineAPI } from "./exports"
import { Logger } from "./services/logging/Logger"
import { PostHogClientProvider } from "./services/posthog/PostHogClientProvider"
import { cleanupTestMode, initializeTestMode } from "./services/test/TestMode"
import { WebviewProviderType } from "./shared/webview/types"
import "./utils/path" // necessary to have access to String.prototype.toPosix
import type { ExtensionContext } from "vscode"
import { HostProvider } from "@/hosts/host-provider"
import { vscodeHostBridgeClient } from "@/hosts/vscode/hostbridge/client/host-grpc-client"
import { readTextFromClipboard, writeTextToClipboard } from "@/utils/env"
import { FileContextTracker } from "./core/context/context-tracking/FileContextTracker"
import type { ExtensionContext } from "vscode"
import { initialize, tearDown } from "./common"
import { sendFocusChatInputEvent } from "./core/controller/ui/subscribeToFocusChatInput"
import { VscodeDiffViewProvider } from "./hosts/vscode/VscodeDiffViewProvider"
import { VscodeWebviewProvider } from "./hosts/vscode/VscodeWebviewProvider"
import { GitCommitGenerator } from "./integrations/git/commit-message-generator"
import { AuthService } from "./services/auth/AuthService"
import { telemetryService } from "./services/posthog/PostHogClientProvider"
import { ShowMessageType } from "./shared/proto/host/window"
import { SharedUriHandler } from "./services/uri/SharedUriHandler"
import { getLatestAnnouncementId } from "./utils/announcements"
import { ShowMessageType } from "./shared/proto/host/window"
/*
Built using https://github.com/microsoft/vscode-webview-ui-toolkit
@@ -51,31 +44,12 @@ https://github.com/microsoft/vscode-webview-ui-toolkit-samples/tree/main/framewo
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export async function activate(context: vscode.ExtensionContext) {
maybeSetupHostProviders(context)
setupHostProvider(context)
// Initialize PostHog client provider
const distinctId = context.globalState.get<string>("cline.distinctId")
PostHogClientProvider.getInstance(distinctId)
const sidebarWebview = (await initialize(context)) as VscodeWebviewProvider
Logger.log("Cline extension activated")
// Migrate custom instructions to global Cline rules (one-time cleanup)
await migrateCustomInstructionsToGlobalRules(context)
// Migrate welcomeViewCompleted setting based on existing API keys (one-time cleanup)
await migrateWelcomeViewCompleted(context)
// Migrate workspace storage values back to global storage (reverting previous migration)
await migrateWorkspaceToGlobalStorage(context)
// Clean up orphaned file context warnings (startup cleanup)
await FileContextTracker.cleanupOrphanedWarnings(context)
// Version checking for autoupdate notification
const currentVersion = context.extension.packageJSON.version
const previousVersion = context.globalState.get<string>("clineVersion")
const sidebarWebview = HostProvider.get().createWebviewProvider(WebviewProviderType.SIDEBAR)
const testModeWatchers = await initializeTestMode(sidebarWebview)
// Initialize test mode and add disposables to context
context.subscriptions.push(...testModeWatchers)
@@ -88,37 +62,6 @@ export async function activate(context: vscode.ExtensionContext) {
}),
)
// Perform post-update actions if necessary
try {
if (!previousVersion || currentVersion !== previousVersion) {
Logger.log(`Cline version changed: ${previousVersion} -> ${currentVersion}. First run or update detected.`)
// Use the same condition as announcements: focus when there's a new announcement to show
const lastShownAnnouncementId = context.globalState.get<string>("lastShownAnnouncementId")
const latestAnnouncementId = getLatestAnnouncementId(context)
if (lastShownAnnouncementId !== latestAnnouncementId) {
// Focus Cline when there's a new announcement to show (major/minor updates or fresh installs)
const message = previousVersion
? `Cline has been updated to v${currentVersion}`
: `Welcome to Cline v${currentVersion}`
await vscode.commands.executeCommand("claude-dev.SidebarProvider.focus")
await new Promise((resolve) => setTimeout(resolve, 200))
HostProvider.window.showMessage({
type: ShowMessageType.INFORMATION,
message,
})
}
// Always update the main version tracker for the next launch.
await context.globalState.update("clineVersion", currentVersion)
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
console.error(`Error during post-update actions: ${errorMessage}, Stack trace: ${error.stack}`)
}
telemetryService.captureExtensionActivated()
context.subscriptions.push(
vscode.commands.registerCommand("cline.plusButtonClicked", async (webview: any) => {
console.log("[DEBUG] plusButtonClicked", webview)
@@ -640,26 +583,21 @@ export async function activate(context: vscode.ExtensionContext) {
return createClineAPI(sidebarWebview.controller)
}
function maybeSetupHostProviders(context: ExtensionContext) {
if (!HostProvider.isInitialized()) {
console.log("Setting up vscode host providers...")
function setupHostProvider(context: ExtensionContext) {
console.log("Setting up vscode host providers...")
const createWebview = (type: WebviewProviderType) => new VscodeWebviewProvider(context, type)
const createDiffView = () => new VscodeDiffViewProvider()
const outputChannel = vscode.window.createOutputChannel("Cline")
context.subscriptions.push(outputChannel)
const createWebview = (type: WebviewProviderType) => new VscodeWebviewProvider(context, type)
const createDiffView = () => new VscodeDiffViewProvider()
const outputChannel = vscode.window.createOutputChannel("Cline")
context.subscriptions.push(outputChannel)
const getCallbackUri = async () => `${vscode.env.uriScheme || "vscode"}://saoudrizwan.claude-dev`
HostProvider.initialize(createWebview, createDiffView, vscodeHostBridgeClient, outputChannel.appendLine, getCallbackUri)
}
const getCallbackUri = async () => `${vscode.env.uriScheme || "vscode"}://saoudrizwan.claude-dev`
HostProvider.initialize(createWebview, createDiffView, vscodeHostBridgeClient, outputChannel.appendLine, getCallbackUri)
}
// This method is called when your extension is deactivated
export async function deactivate() {
PostHogClientProvider.getInstance().dispose()
// Dispose all webview instances
await WebviewProvider.disposeAllInstances()
tearDown()
// Clean up test mode
cleanupTestMode()
+10 -16
View File
@@ -1,35 +1,29 @@
import { activate } from "@/extension"
import { Controller } from "@core/controller"
import { CacheService } from "@core/storage/CacheService"
import { initialize } from "@/common"
import { WebviewProvider } from "@/core/webview"
import { AuthHandler } from "@/hosts/external/AuthHandler"
import { HostProvider } from "@/hosts/host-provider"
import { DiffViewProvider } from "@/integrations/editor/DiffViewProvider"
import { ExternalDiffViewProvider } from "@hosts/external/ExternalDiffviewProvider"
import { ExternalWebviewProvider } from "@hosts/external/ExternalWebviewProvider"
import { ExternalHostBridgeClientManager } from "@hosts/external/host-bridge-client-manager"
import { HostProvider } from "@/hosts/host-provider"
import { WebviewProviderType } from "@shared/webview/types"
import { v4 as uuidv4 } from "uuid"
import { startProtobusService } from "./protobus-service"
import { log } from "./utils"
import { extensionContext } from "./vscode-context"
import { startProtobusService } from "./protobus-service"
import { AuthHandler } from "@/hosts/external/AuthHandler"
import { WebviewProvider } from "@/core/webview"
import { DiffViewProvider } from "@/integrations/editor/DiffViewProvider"
async function main() {
log("\n\n\nStarting cline-core service...\n\n\n")
AuthHandler.getInstance().setEnabled(true)
setupHostProvider()
// Set up global error handlers to prevent process crashes
setupGlobalErrorHandlers()
activate(extensionContext)
// Create and initialize cache service
const webviewProvider = await initialize(extensionContext)
// Create controller with cache service
const controller = new Controller(extensionContext, uuidv4())
startProtobusService(controller)
AuthHandler.getInstance().setEnabled(true)
startProtobusService(webviewProvider.controller)
}
function setupHostProvider() {