Przeglądaj źródła

Focus the extension when receiving bridge commands (#7633)

Chris Estreich 4 miesięcy temu
rodzic
commit
280b75d2eb

+ 4 - 0
packages/cloud/src/__mocks__/vscode.ts

@@ -13,6 +13,10 @@ export const Uri = {
 	parse: vi.fn((uri: string) => ({ toString: () => uri })),
 }
 
+export const commands = {
+	executeCommand: vi.fn().mockResolvedValue(undefined),
+}
+
 export interface ExtensionContext {
 	secrets: {
 		get: (key: string) => Promise<string | undefined>

+ 34 - 4
packages/cloud/src/bridge/BaseChannel.ts

@@ -1,4 +1,13 @@
 import type { Socket } from "socket.io-client"
+import * as vscode from "vscode"
+
+import type { StaticAppProperties, GitProperties } from "@roo-code/types"
+
+export interface BaseChannelOptions {
+	instanceId: string
+	appProperties: StaticAppProperties
+	gitProperties?: GitProperties
+}
 
 /**
  * Abstract base class for communication channels in the bridge system.
@@ -11,9 +20,13 @@ import type { Socket } from "socket.io-client"
 export abstract class BaseChannel<TCommand = unknown, TEventName extends string = string, TEventData = unknown> {
 	protected socket: Socket | null = null
 	protected readonly instanceId: string
+	protected readonly appProperties: StaticAppProperties
+	protected readonly gitProperties?: GitProperties
 
-	constructor(instanceId: string) {
-		this.instanceId = instanceId
+	constructor(options: BaseChannelOptions) {
+		this.instanceId = options.instanceId
+		this.appProperties = options.appProperties
+		this.gitProperties = options.gitProperties
 	}
 
 	/**
@@ -81,9 +94,26 @@ export abstract class BaseChannel<TCommand = unknown, TEventName extends string
 	}
 
 	/**
-	 * Handle incoming commands - must be implemented by subclasses.
+	 * Handle incoming commands - template method that ensures common functionality
+	 * is executed before subclass-specific logic.
+	 *
+	 * This method should be called by subclasses to handle commands.
+	 * It will execute common functionality and then delegate to the abstract
+	 * handleCommandImplementation method.
+	 */
+	public async handleCommand(command: TCommand): Promise<void> {
+		// Common functionality: focus the sidebar.
+		await vscode.commands.executeCommand(`${this.appProperties.appName}.SidebarProvider.focus`)
+
+		// Delegate to subclass-specific implementation.
+		await this.handleCommandImplementation(command)
+	}
+
+	/**
+	 * Handle command-specific logic - must be implemented by subclasses.
+	 * This method is called after common functionality has been executed.
 	 */
-	public abstract handleCommand(command: TCommand): Promise<void>
+	protected abstract handleCommandImplementation(command: TCommand): Promise<void>
 
 	/**
 	 * Handle connection-specific logic.

+ 75 - 54
packages/cloud/src/bridge/BridgeOrchestrator.ts

@@ -1,4 +1,5 @@
 import crypto from "crypto"
+import os from "os"
 
 import {
 	type TaskProviderLike,
@@ -6,6 +7,8 @@ import {
 	type CloudUserInfo,
 	type ExtensionBridgeCommand,
 	type TaskBridgeCommand,
+	type StaticAppProperties,
+	type GitProperties,
 	ConnectionState,
 	ExtensionSocketEvents,
 	TaskSocketEvents,
@@ -39,6 +42,8 @@ export class BridgeOrchestrator {
 	private readonly token: string
 	private readonly provider: TaskProviderLike
 	private readonly instanceId: string
+	private readonly appProperties: StaticAppProperties
+	private readonly gitProperties?: GitProperties
 
 	// Components
 	private socketTransport: SocketTransport
@@ -61,66 +66,72 @@ export class BridgeOrchestrator {
 	public static async connectOrDisconnect(
 		userInfo: CloudUserInfo | null,
 		remoteControlEnabled: boolean | undefined,
-		options?: BridgeOrchestratorOptions,
+		options: BridgeOrchestratorOptions,
 	): Promise<void> {
-		const isEnabled = BridgeOrchestrator.isEnabled(userInfo, remoteControlEnabled)
+		if (BridgeOrchestrator.isEnabled(userInfo, remoteControlEnabled)) {
+			await BridgeOrchestrator.connect(options)
+		} else {
+			await BridgeOrchestrator.disconnect()
+		}
+	}
+
+	public static async connect(options: BridgeOrchestratorOptions) {
 		const instance = BridgeOrchestrator.instance
 
-		if (isEnabled) {
-			if (!instance) {
-				if (!options) {
-					console.error(
-						`[BridgeOrchestrator#connectOrDisconnect] Cannot connect: options are required for connection`,
-					)
-					return
-				}
-				try {
-					console.log(`[BridgeOrchestrator#connectOrDisconnect] Connecting...`)
-					BridgeOrchestrator.instance = new BridgeOrchestrator(options)
-					await BridgeOrchestrator.instance.connect()
-				} catch (error) {
-					console.error(
-						`[BridgeOrchestrator#connectOrDisconnect] connect() failed: ${error instanceof Error ? error.message : String(error)}`,
-					)
-				}
-			} else {
-				if (
-					instance.connectionState === ConnectionState.FAILED ||
-					instance.connectionState === ConnectionState.DISCONNECTED
-				) {
-					console.log(
-						`[BridgeOrchestrator#connectOrDisconnect] Re-connecting... (state: ${instance.connectionState})`,
-					)
+		if (!instance) {
+			try {
+				console.log(`[BridgeOrchestrator#connectOrDisconnect] Connecting...`)
+				// Populate telemetry properties before registering the instance.
+				await options.provider.getTelemetryProperties()
 
-					instance.reconnect().catch((error) => {
-						console.error(
-							`[BridgeOrchestrator#connectOrDisconnect] reconnect() failed: ${error instanceof Error ? error.message : String(error)}`,
-						)
-					})
-				} else {
-					console.log(
-						`[BridgeOrchestrator#connectOrDisconnect] Already connected or connecting (state: ${instance.connectionState})`,
-					)
-				}
+				BridgeOrchestrator.instance = new BridgeOrchestrator(options)
+				await BridgeOrchestrator.instance.connect()
+			} catch (error) {
+				console.error(
+					`[BridgeOrchestrator#connectOrDisconnect] connect() failed: ${error instanceof Error ? error.message : String(error)}`,
+				)
 			}
 		} else {
-			if (instance) {
-				try {
-					console.log(
-						`[BridgeOrchestrator#connectOrDisconnect] Disconnecting... (state: ${instance.connectionState})`,
-					)
+			if (
+				instance.connectionState === ConnectionState.FAILED ||
+				instance.connectionState === ConnectionState.DISCONNECTED
+			) {
+				console.log(
+					`[BridgeOrchestrator#connectOrDisconnect] Re-connecting... (state: ${instance.connectionState})`,
+				)
 
-					await instance.disconnect()
-				} catch (error) {
+				instance.reconnect().catch((error) => {
 					console.error(
-						`[BridgeOrchestrator#connectOrDisconnect] disconnect() failed: ${error instanceof Error ? error.message : String(error)}`,
+						`[BridgeOrchestrator#connectOrDisconnect] reconnect() failed: ${error instanceof Error ? error.message : String(error)}`,
 					)
-				} finally {
-					BridgeOrchestrator.instance = null
-				}
+				})
 			} else {
-				console.log(`[BridgeOrchestrator#connectOrDisconnect] Already disconnected`)
+				console.log(
+					`[BridgeOrchestrator#connectOrDisconnect] Already connected or connecting (state: ${instance.connectionState})`,
+				)
+			}
+		}
+	}
+
+	public static async disconnect() {
+		const instance = BridgeOrchestrator.instance
+
+		if (instance) {
+			try {
+				console.log(
+					`[BridgeOrchestrator#connectOrDisconnect] Disconnecting... (state: ${instance.connectionState})`,
+				)
+
+				await instance.disconnect()
+			} catch (error) {
+				console.error(
+					`[BridgeOrchestrator#connectOrDisconnect] disconnect() failed: ${error instanceof Error ? error.message : String(error)}`,
+				)
+			} finally {
+				BridgeOrchestrator.instance = null
 			}
+		} else {
+			console.log(`[BridgeOrchestrator#connectOrDisconnect] Already disconnected`)
 		}
 	}
 
@@ -146,6 +157,8 @@ export class BridgeOrchestrator {
 		this.token = options.token
 		this.provider = options.provider
 		this.instanceId = options.sessionId || crypto.randomUUID()
+		this.appProperties = { ...options.provider.appProperties, hostname: os.hostname() }
+		this.gitProperties = options.provider.gitProperties
 
 		this.socketTransport = new SocketTransport({
 			url: this.socketBridgeUrl,
@@ -166,8 +179,19 @@ export class BridgeOrchestrator {
 			onReconnect: () => this.handleReconnect(),
 		})
 
-		this.extensionChannel = new ExtensionChannel(this.instanceId, this.userId, this.provider)
-		this.taskChannel = new TaskChannel(this.instanceId)
+		this.extensionChannel = new ExtensionChannel({
+			instanceId: this.instanceId,
+			appProperties: this.appProperties,
+			gitProperties: this.gitProperties,
+			userId: this.userId,
+			provider: this.provider,
+		})
+
+		this.taskChannel = new TaskChannel({
+			instanceId: this.instanceId,
+			appProperties: this.appProperties,
+			gitProperties: this.gitProperties,
+		})
 	}
 
 	private setupSocketListeners() {
@@ -288,9 +312,6 @@ export class BridgeOrchestrator {
 	}
 
 	private async connect(): Promise<void> {
-		// Populate the app and git properties before registering the instance.
-		await this.provider.getTelemetryProperties()
-
 		await this.socketTransport.connect()
 		this.setupSocketListeners()
 	}

+ 20 - 14
packages/cloud/src/bridge/ExtensionChannel.ts

@@ -14,7 +14,12 @@ import {
 	HEARTBEAT_INTERVAL_MS,
 } from "@roo-code/types"
 
-import { BaseChannel } from "./BaseChannel.js"
+import { type BaseChannelOptions, BaseChannel } from "./BaseChannel.js"
+
+interface ExtensionChannelOptions extends BaseChannelOptions {
+	userId: string
+	provider: TaskProviderLike
+}
 
 /**
  * Manages the extension-level communication channel.
@@ -31,33 +36,36 @@ export class ExtensionChannel extends BaseChannel<
 	private heartbeatInterval: NodeJS.Timeout | null = null
 	private eventListeners: Map<RooCodeEventName, (...args: unknown[]) => void> = new Map()
 
-	constructor(instanceId: string, userId: string, provider: TaskProviderLike) {
-		super(instanceId)
-		this.userId = userId
-		this.provider = provider
+	constructor(options: ExtensionChannelOptions) {
+		super({
+			instanceId: options.instanceId,
+			appProperties: options.appProperties,
+			gitProperties: options.gitProperties,
+		})
+
+		this.userId = options.userId
+		this.provider = options.provider
 
 		this.extensionInstance = {
 			instanceId: this.instanceId,
 			userId: this.userId,
 			workspacePath: this.provider.cwd,
-			appProperties: this.provider.appProperties,
-			gitProperties: this.provider.gitProperties,
+			appProperties: this.appProperties,
+			gitProperties: this.gitProperties,
 			lastHeartbeat: Date.now(),
-			task: {
-				taskId: "",
-				taskStatus: TaskStatus.None,
-			},
+			task: { taskId: "", taskStatus: TaskStatus.None },
 			taskHistory: [],
 		}
 
 		this.setupListeners()
 	}
 
-	public async handleCommand(command: ExtensionBridgeCommand): Promise<void> {
+	protected async handleCommandImplementation(command: ExtensionBridgeCommand): Promise<void> {
 		if (command.instanceId !== this.instanceId) {
 			console.log(`[ExtensionChannel] command -> instance id mismatch | ${this.instanceId}`, {
 				messageInstanceId: command.instanceId,
 			})
+
 			return
 		}
 
@@ -217,8 +225,6 @@ export class ExtensionChannel extends BaseChannel<
 
 		this.extensionInstance = {
 			...this.extensionInstance,
-			appProperties: this.extensionInstance.appProperties ?? this.provider.appProperties,
-			gitProperties: this.extensionInstance.gitProperties ?? this.provider.gitProperties,
 			lastHeartbeat: Date.now(),
 			task: task
 				? {

+ 7 - 4
packages/cloud/src/bridge/TaskChannel.ts

@@ -14,7 +14,7 @@ import {
 	TaskSocketEvents,
 } from "@roo-code/types"
 
-import { BaseChannel } from "./BaseChannel.js"
+import { type BaseChannelOptions, BaseChannel } from "./BaseChannel.js"
 
 type TaskEventListener = {
 	[K in keyof TaskEvents]: (...args: TaskEvents[K]) => void | Promise<void>
@@ -26,6 +26,9 @@ type TaskEventMapping = {
 	createPayload: (task: TaskLike, ...args: any[]) => any // eslint-disable-line @typescript-eslint/no-explicit-any
 }
 
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+interface TaskChannelOptions extends BaseChannelOptions {}
+
 /**
  * Manages task-level communication channels.
  * Handles task subscriptions, messaging, and task-specific commands.
@@ -69,11 +72,11 @@ export class TaskChannel extends BaseChannel<
 		},
 	] as const
 
-	constructor(instanceId: string) {
-		super(instanceId)
+	constructor(options: TaskChannelOptions) {
+		super(options)
 	}
 
-	public async handleCommand(command: TaskBridgeCommand): Promise<void> {
+	protected async handleCommandImplementation(command: TaskBridgeCommand): Promise<void> {
 		const task = this.subscribedTasks.get(command.taskId)
 
 		if (!task) {

+ 22 - 2
packages/cloud/src/bridge/__tests__/ExtensionChannel.test.ts

@@ -5,6 +5,7 @@ import type { Socket } from "socket.io-client"
 import {
 	type TaskProviderLike,
 	type TaskProviderEvents,
+	type StaticAppProperties,
 	RooCodeEventName,
 	ExtensionBridgeEventName,
 	ExtensionSocketEvents,
@@ -19,6 +20,15 @@ describe("ExtensionChannel", () => {
 	const instanceId = "test-instance-123"
 	const userId = "test-user-456"
 
+	const appProperties: StaticAppProperties = {
+		appName: "roo-code",
+		appVersion: "1.0.0",
+		vscodeVersion: "1.0.0",
+		platform: "darwin",
+		editorName: "Roo Code",
+		hostname: "test-host",
+	}
+
 	// Track registered event listeners
 	const eventListeners = new Map<keyof TaskProviderEvents, Set<(...args: unknown[]) => unknown>>()
 
@@ -80,7 +90,12 @@ describe("ExtensionChannel", () => {
 		} as unknown as TaskProviderLike
 
 		// Create extension channel instance
-		extensionChannel = new ExtensionChannel(instanceId, userId, mockProvider)
+		extensionChannel = new ExtensionChannel({
+			instanceId,
+			appProperties,
+			userId,
+			provider: mockProvider,
+		})
 	})
 
 	afterEach(() => {
@@ -155,7 +170,12 @@ describe("ExtensionChannel", () => {
 
 		it("should not have duplicate listeners after multiple channel creations", () => {
 			// Create a second channel with the same provider
-			const secondChannel = new ExtensionChannel("instance-2", userId, mockProvider)
+			const secondChannel = new ExtensionChannel({
+				instanceId: "instance-2",
+				appProperties,
+				userId,
+				provider: mockProvider,
+			})
 
 			// Each event should have exactly 2 listeners (one from each channel)
 			eventListeners.forEach((listeners) => {

+ 22 - 9
packages/cloud/src/bridge/__tests__/TaskChannel.test.ts

@@ -6,6 +6,7 @@ import type { Socket } from "socket.io-client"
 import {
 	type TaskLike,
 	type ClineMessage,
+	type StaticAppProperties,
 	RooCodeEventName,
 	TaskBridgeEventName,
 	TaskBridgeCommandName,
@@ -22,6 +23,15 @@ describe("TaskChannel", () => {
 	const instanceId = "test-instance-123"
 	const taskId = "test-task-456"
 
+	const appProperties: StaticAppProperties = {
+		appName: "roo-code",
+		appVersion: "1.0.0",
+		vscodeVersion: "1.0.0",
+		platform: "darwin",
+		editorName: "Roo Code",
+		hostname: "test-host",
+	}
+
 	beforeEach(() => {
 		// Create mock socket
 		mockSocket = {
@@ -75,7 +85,10 @@ describe("TaskChannel", () => {
 		}
 
 		// Create task channel instance
-		taskChannel = new TaskChannel(instanceId)
+		taskChannel = new TaskChannel({
+			instanceId,
+			appProperties,
+		})
 	})
 
 	afterEach(() => {
@@ -320,7 +333,7 @@ describe("TaskChannel", () => {
 			channel.subscribedTasks.set(taskId, mockTask)
 		})
 
-		it("should handle Message command", () => {
+		it("should handle Message command", async () => {
 			const command = {
 				type: TaskBridgeCommandName.Message,
 				taskId,
@@ -331,7 +344,7 @@ describe("TaskChannel", () => {
 				},
 			}
 
-			taskChannel.handleCommand(command)
+			await taskChannel.handleCommand(command)
 
 			expect(mockTask.submitUserMessage).toHaveBeenCalledWith(
 				command.payload.text,
@@ -341,7 +354,7 @@ describe("TaskChannel", () => {
 			)
 		})
 
-		it("should handle ApproveAsk command", () => {
+		it("should handle ApproveAsk command", async () => {
 			const command = {
 				type: TaskBridgeCommandName.ApproveAsk,
 				taskId,
@@ -351,12 +364,12 @@ describe("TaskChannel", () => {
 				},
 			}
 
-			taskChannel.handleCommand(command)
+			await taskChannel.handleCommand(command)
 
 			expect(mockTask.approveAsk).toHaveBeenCalledWith(command.payload)
 		})
 
-		it("should handle DenyAsk command", () => {
+		it("should handle DenyAsk command", async () => {
 			const command = {
 				type: TaskBridgeCommandName.DenyAsk,
 				taskId,
@@ -366,12 +379,12 @@ describe("TaskChannel", () => {
 				},
 			}
 
-			taskChannel.handleCommand(command)
+			await taskChannel.handleCommand(command)
 
 			expect(mockTask.denyAsk).toHaveBeenCalledWith(command.payload)
 		})
 
-		it("should log error for unknown task", () => {
+		it("should log error for unknown task", async () => {
 			const errorSpy = vi.spyOn(console, "error")
 
 			const command = {
@@ -383,7 +396,7 @@ describe("TaskChannel", () => {
 				},
 			}
 
-			taskChannel.handleCommand(command)
+			await taskChannel.handleCommand(command)
 
 			expect(errorSpy).toHaveBeenCalledWith(`[TaskChannel] Unable to find task unknown-task`)
 

+ 1 - 1
packages/types/npm/package.metadata.json

@@ -1,6 +1,6 @@
 {
 	"name": "@roo-code/types",
-	"version": "1.69.0",
+	"version": "1.71.0",
 	"description": "TypeScript type definitions for Roo Code.",
 	"publishConfig": {
 		"access": "public",

+ 1 - 0
packages/types/src/telemetry.ts

@@ -78,6 +78,7 @@ export const staticAppPropertiesSchema = z.object({
 	vscodeVersion: z.string(),
 	platform: z.string(),
 	editorName: z.string(),
+	hostname: z.string().optional(),
 })
 
 export type StaticAppProperties = z.infer<typeof staticAppPropertiesSchema>

+ 0 - 1
src/core/webview/ClineProvider.ts

@@ -2095,7 +2095,6 @@ export class ClineProvider
 
 	public async remoteControlEnabled(enabled: boolean) {
 		const userInfo = CloudService.instance.getUserInfo()
-
 		const config = await CloudService.instance.cloudAPI?.bridgeConfig().catch(() => undefined)
 
 		if (!config) {

+ 13 - 5
src/core/webview/webviewMessageHandler.ts

@@ -956,13 +956,21 @@ export const webviewMessageHandler = async (
 			break
 		case "remoteControlEnabled":
 			try {
-				await CloudService.instance.updateUserSettings({
-					extensionBridgeEnabled: message.bool ?? false,
-				})
+				await CloudService.instance.updateUserSettings({ extensionBridgeEnabled: message.bool ?? false })
+			} catch (error) {
+				provider.log(
+					`CloudService#updateUserSettings failed: ${error instanceof Error ? error.message : String(error)}`,
+				)
+			}
+
+			try {
+				await provider.remoteControlEnabled(message.bool ?? false)
 			} catch (error) {
-				provider.log(`Failed to update cloud settings for remote control: ${error}`)
+				provider.log(
+					`ClineProvider#remoteControlEnabled failed: ${error instanceof Error ? error.message : String(error)}`,
+				)
 			}
-			await provider.remoteControlEnabled(message.bool ?? false)
+
 			await provider.postStateToWebview()
 			break
 		case "refreshAllMcpServers": {

+ 5 - 15
src/extension.ts

@@ -131,20 +131,13 @@ export async function activate(context: vscode.ExtensionContext) {
 	authStateChangedHandler = async (data: { state: AuthState; previousState: AuthState }) => {
 		postStateListener()
 
-		// Check if user has logged out
 		if (data.state === "logged-out") {
 			try {
-				// Disconnect the bridge when user logs out
-				// When userInfo is null and remoteControlEnabled is false, BridgeOrchestrator
-				// will disconnect. The options parameter is not needed for disconnection.
-				await BridgeOrchestrator.connectOrDisconnect(null, false)
-
+				await BridgeOrchestrator.disconnect()
 				cloudLogger("[CloudService] BridgeOrchestrator disconnected on logout")
 			} catch (error) {
 				cloudLogger(
-					`[CloudService] Failed to disconnect BridgeOrchestrator on logout: ${
-						error instanceof Error ? error.message : String(error)
-					}`,
+					`[CloudService] Failed to disconnect BridgeOrchestrator on logout: ${error instanceof Error ? error.message : String(error)}`,
 				)
 			}
 		}
@@ -152,6 +145,7 @@ export async function activate(context: vscode.ExtensionContext) {
 
 	settingsUpdatedHandler = async () => {
 		const userInfo = CloudService.instance.getUserInfo()
+
 		if (userInfo && CloudService.instance.cloudAPI) {
 			try {
 				const config = await CloudService.instance.cloudAPI.bridgeConfig()
@@ -163,8 +157,6 @@ export async function activate(context: vscode.ExtensionContext) {
 					? true
 					: (CloudService.instance.getUserSettings()?.settings?.extensionBridgeEnabled ?? false)
 
-				cloudLogger(`[CloudService] Settings updated - remoteControlEnabled = ${remoteControlEnabled}`)
-
 				await BridgeOrchestrator.connectOrDisconnect(userInfo, remoteControlEnabled, {
 					...config,
 					provider,
@@ -172,7 +164,7 @@ export async function activate(context: vscode.ExtensionContext) {
 				})
 			} catch (error) {
 				cloudLogger(
-					`[CloudService] Failed to update BridgeOrchestrator on settings change: ${error instanceof Error ? error.message : String(error)}`,
+					`[CloudService] BridgeOrchestrator#connectOrDisconnect failed on settings change: ${error instanceof Error ? error.message : String(error)}`,
 				)
 			}
 		}
@@ -194,8 +186,6 @@ export async function activate(context: vscode.ExtensionContext) {
 			const isCloudAgent =
 				typeof process.env.ROO_CODE_CLOUD_TOKEN === "string" && process.env.ROO_CODE_CLOUD_TOKEN.length > 0
 
-			cloudLogger(`[CloudService] isCloudAgent = ${isCloudAgent}, socketBridgeUrl = ${config.socketBridgeUrl}`)
-
 			const remoteControlEnabled = isCloudAgent
 				? true
 				: (CloudService.instance.getUserSettings()?.settings?.extensionBridgeEnabled ?? false)
@@ -207,7 +197,7 @@ export async function activate(context: vscode.ExtensionContext) {
 			})
 		} catch (error) {
 			cloudLogger(
-				`[CloudService] Failed to fetch bridgeConfig: ${error instanceof Error ? error.message : String(error)}`,
+				`[CloudService] BridgeOrchestrator#connectOrDisconnect failed on user change: ${error instanceof Error ? error.message : String(error)}`,
 			)
 		}
 	}

+ 2 - 1
src/extension/api.ts

@@ -1,9 +1,10 @@
 import { EventEmitter } from "events"
-import * as vscode from "vscode"
 import fs from "fs/promises"
 import * as path from "path"
 import * as os from "os"
 
+import * as vscode from "vscode"
+
 import {
 	type RooCodeAPI,
 	type RooCodeSettings,

+ 0 - 4
src/shared/package.ts

@@ -1,7 +1,3 @@
-/**
- * Package
- */
-
 import { publisher, name, version } from "../package.json"
 
 // These ENV variables can be defined by ESBuild when building the extension