From 455283221d3f9fd73295411760c2e14f79cbf305 Mon Sep 17 00:00:00 2001 From: cte Date: Tue, 12 Aug 2025 01:43:26 -0700 Subject: [PATCH 1/2] Switch to the UnifiedBridgeService --- scripts/link-packages.js | 53 +++++++++++++++++++++++++++++++ src/core/task/Task.ts | 50 ++++++++++++++--------------- src/core/webview/ClineProvider.ts | 45 ++++++++------------------ src/extension.ts | 11 +++---- 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/scripts/link-packages.js b/scripts/link-packages.js index 60ef3be865..6d8b33f6de 100755 --- a/scripts/link-packages.js +++ b/scripts/link-packages.js @@ -58,6 +58,54 @@ if (!unlink && watch) { } } +function generateNpmPackageJson(sourcePath, npmPath) { + const npmDir = path.join(sourcePath, npmPath) + const npmPackagePath = path.join(npmDir, "package.json") + const npmMetadataPath = path.join(npmDir, "package.metadata.json") + const monorepoPackagePath = path.join(sourcePath, "package.json") + + if (fs.existsSync(npmPackagePath)) { + console.log(` ✓ npm/package.json already exists`) + return + } + + if (!fs.existsSync(npmMetadataPath)) { + console.log(` ⚠ No package.metadata.json found, skipping npm package.json generation`) + return + } + + try { + console.log(` 📦 Generating npm/package.json...`) + const monorepoPackage = JSON.parse(fs.readFileSync(monorepoPackagePath, "utf8")) + const npmMetadata = JSON.parse(fs.readFileSync(npmMetadataPath, "utf8")) + + const npmPackage = { + ...npmMetadata, + type: "module", + dependencies: monorepoPackage.dependencies || {}, + main: "./dist/index.cjs", + module: "./dist/index.js", + types: "./dist/index.d.ts", + exports: { + ".": { + types: "./dist/index.d.ts", + import: "./dist/index.js", + require: { + types: "./dist/index.d.cts", + default: "./dist/index.cjs", + }, + }, + }, + files: ["dist"], + } + + fs.writeFileSync(npmPackagePath, JSON.stringify(npmPackage, null, 2) + "\n") + console.log(` ✓ Generated npm/package.json for ${npmPackage.name}`) + } catch (error) { + console.error(` ✗ Failed to generate npm/package.json: ${error.message}`) + } +} + function linkPackage(pkg) { const sourcePath = path.resolve(__dirname, "..", pkg.sourcePath) const targetPath = path.resolve(__dirname, "..", pkg.targetPath) @@ -78,6 +126,11 @@ function linkPackage(pkg) { } } + // If npmPath is specified, check if we need to generate package.json. + if (pkg.npmPath) { + generateNpmPackageJson(sourcePath, pkg.npmPath) + } + // Create symlink. fs.rmSync(targetPath, { recursive: true, force: true }) fs.mkdirSync(path.dirname(targetPath), { recursive: true }) diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index cd9ee06453..cb6694b7f0 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -33,7 +33,7 @@ import { isBlockingAsk, } from "@roo-code/types" import { TelemetryService } from "@roo-code/telemetry" -import { CloudService, TaskBridgeService } from "@roo-code/cloud" +import { CloudService, UnifiedBridgeService } from "@roo-code/cloud" // api import { ApiHandler, ApiHandlerCreateMessageMetadata, buildApiHandler } from "../../api" @@ -241,7 +241,7 @@ export class Task extends EventEmitter implements TaskLike { // Task Bridge enableTaskBridge: boolean - taskBridgeService: TaskBridgeService | null = null + bridgeService: UnifiedBridgeService | null = null // Streaming isWaitingForFirstChunk = false @@ -980,19 +980,17 @@ export class Task extends EventEmitter implements TaskLike { // Start / Abort / Resume private async startTask(task?: string, images?: string[]): Promise { - if (this.enableTaskBridge && CloudService.hasInstance()) { - if (!this.taskBridgeService) { - const bridgeConfig = await CloudService.instance.cloudAPI?.bridgeConfig().catch(() => undefined) + if (this.enableTaskBridge) { + try { + this.bridgeService = this.bridgeService || UnifiedBridgeService.getInstance() - if (bridgeConfig) { - this.taskBridgeService = await TaskBridgeService.createInstance({ - ...bridgeConfig, - }) + if (this.bridgeService) { + await this.bridgeService.subscribeToTask(this) } - } - - if (this.taskBridgeService) { - await this.taskBridgeService.subscribeToTask(this) + } catch (error) { + console.error( + `[Task#startTask] subscribeToTask failed - ${error instanceof Error ? error.message : String(error)}`, + ) } } @@ -1047,19 +1045,17 @@ export class Task extends EventEmitter implements TaskLike { } private async resumeTaskFromHistory() { - if (this.enableTaskBridge && CloudService.hasInstance()) { - if (!this.taskBridgeService) { - const bridgeConfig = await CloudService.instance.cloudAPI?.bridgeConfig().catch(() => undefined) + if (this.enableTaskBridge) { + try { + this.bridgeService = this.bridgeService || UnifiedBridgeService.getInstance() - if (bridgeConfig) { - this.taskBridgeService = await TaskBridgeService.createInstance({ - ...bridgeConfig, - }) + if (this.bridgeService) { + await this.bridgeService.subscribeToTask(this) } - } - - if (this.taskBridgeService) { - await this.taskBridgeService.subscribeToTask(this) + } catch (error) { + console.error( + `[Task#resumeTaskFromHistory] subscribeToTask failed - ${error instanceof Error ? error.message : String(error)}`, + ) } } @@ -1309,11 +1305,11 @@ export class Task extends EventEmitter implements TaskLike { } // Unsubscribe from TaskBridge service. - if (this.taskBridgeService) { - this.taskBridgeService + if (this.bridgeService) { + this.bridgeService .unsubscribeFromTask(this.taskId) .catch((error) => console.error("Error unsubscribing from task bridge:", error)) - this.taskBridgeService = null + this.bridgeService = null } // Release any terminals associated with this task. diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index f3de56268c..e6817e1825 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2134,25 +2134,21 @@ export class ClineProvider /** * Handle remote control enabled/disabled state changes - * Manages ExtensionBridgeService and TaskBridgeService lifecycle + * Manages UnifiedBridgeService lifecycle */ public async handleRemoteControlToggle(enabled: boolean) { - const { - CloudService: CloudServiceImport, - ExtensionBridgeService, - TaskBridgeService, - } = await import("@roo-code/cloud") + const { CloudService: CloudServiceImport, UnifiedBridgeService } = await import("@roo-code/cloud") const userInfo = CloudServiceImport.instance.getUserInfo() const bridgeConfig = await CloudServiceImport.instance.cloudAPI?.bridgeConfig().catch(() => undefined) if (!bridgeConfig) { - this.log("[CloudService] Failed to get bridge config") + this.log("[ClineProvider#handleRemoteControlToggle] Failed to get bridge config") return } - ExtensionBridgeService.handleRemoteControlState( + await UnifiedBridgeService.handleRemoteControlState( userInfo, enabled, { ...bridgeConfig, provider: this }, @@ -2160,49 +2156,36 @@ export class ClineProvider ) if (isRemoteControlEnabled(userInfo, enabled)) { - // Set up TaskBridgeService for the currently active task if one exists. const currentTask = this.getCurrentCline() - if (currentTask && !currentTask.taskBridgeService && CloudService.hasInstance()) { + if (currentTask && !currentTask.bridgeService) { try { - if (!currentTask.taskBridgeService) { - const bridgeConfig = await CloudService.instance.cloudAPI?.bridgeConfig().catch(() => undefined) - - if (bridgeConfig) { - currentTask.taskBridgeService = await TaskBridgeService.createInstance({ - ...bridgeConfig, - }) - } - } + currentTask.bridgeService = UnifiedBridgeService.getInstance() - if (currentTask.taskBridgeService) { - await currentTask.taskBridgeService.subscribeToTask(currentTask) + if (currentTask.bridgeService) { + await currentTask.bridgeService.subscribeToTask(currentTask) } - - this.log(`[TaskBridgeService] Subscribed current task ${currentTask.taskId} to TaskBridge`) } catch (error) { - const message = `[TaskBridgeService#subscribeToTask] ${error instanceof Error ? error.message : String(error)}` + const message = `[ClineProvider#handleRemoteControlToggle] subscribeToTask failed - ${error instanceof Error ? error.message : String(error)}` this.log(message) console.error(message) } } } else { - // Disconnect TaskBridgeService for all tasks in the stack. for (const task of this.clineStack) { - if (task.taskBridgeService) { + if (task.bridgeService) { try { - await task.taskBridgeService.unsubscribeFromTask(task.taskId) - task.taskBridgeService = null - this.log(`[TaskBridgeService] Unsubscribed task ${task.taskId} from TaskBridge`) + await task.bridgeService.unsubscribeFromTask(task.taskId) + task.bridgeService = null } catch (error) { - const message = `[TaskBridgeService#unsubscribeFromTask] for task ${task.taskId}: ${error instanceof Error ? error.message : String(error)}` + const message = `[ClineProvider#handleRemoteControlToggle] unsubscribeFromTask failed - ${error instanceof Error ? error.message : String(error)}` this.log(message) console.error(message) } } } - TaskBridgeService.resetInstance() + UnifiedBridgeService.resetInstance() } } diff --git a/src/extension.ts b/src/extension.ts index 741f7b9f86..767e83c42d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -12,7 +12,7 @@ try { console.warn("Failed to load environment variables:", e) } -import { CloudService, ExtensionBridgeService } from "@roo-code/cloud" +import { CloudService, UnifiedBridgeService } from "@roo-code/cloud" import { TelemetryService, PostHogTelemetryClient } from "@roo-code/telemetry" import "./utils/path" // Necessary to have access to String.prototype.toPosix. @@ -141,7 +141,7 @@ export async function activate(context: vscode.ExtensionContext) { return } - ExtensionBridgeService.handleRemoteControlState( + UnifiedBridgeService.handleRemoteControlState( userInfo, contextProxy.getValue("remoteControlEnabled"), { ...bridgeConfig, provider }, @@ -280,11 +280,10 @@ export async function activate(context: vscode.ExtensionContext) { export async function deactivate() { outputChannel.appendLine(`${Package.name} extension deactivated`) - // Cleanup Extension Bridge service. - const extensionBridgeService = ExtensionBridgeService.getInstance() + const bridgeService = UnifiedBridgeService.getInstance() - if (extensionBridgeService) { - await extensionBridgeService.disconnect() + if (bridgeService) { + await bridgeService.disconnect() } await McpServerManager.cleanup(extensionContext) From 15d6f88bac983bb0c0566db88c1f4f89204e5d3f Mon Sep 17 00:00:00 2001 From: cte Date: Tue, 12 Aug 2025 03:28:58 -0700 Subject: [PATCH 2/2] Bump @roo-code/cloud to v0.11.0 --- pnpm-lock.yaml | 10 +++++----- src/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19c5f3ec96..0bc3f93bcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -563,8 +563,8 @@ importers: specifier: ^1.14.0 version: 1.14.0(typescript@5.8.3) '@roo-code/cloud': - specifier: ^0.10.0 - version: 0.10.0 + specifier: ^0.11.0 + version: 0.11.0 '@roo-code/ipc': specifier: workspace:^ version: link:../packages/ipc @@ -3065,8 +3065,8 @@ packages: cpu: [x64] os: [win32] - '@roo-code/cloud@0.10.0': - resolution: {integrity: sha512-nP5XD9JVaFFmz+XN9za9XMombCjw7LrS4pFEbBU52raZbobvUAExKuMJw8U+vyXFW+mcVAexM0i39XB6SJvhWA==} + '@roo-code/cloud@0.11.0': + resolution: {integrity: sha512-ZT3gBRNHI0HGmn5bMxdyhMxJVrp/7l7jcx/lDRl+xjeCP3KmJshzFKlfjdSGDtOoztnNj65hSbs/WiTS2wUodQ==} '@roo-code/types@1.45.0': resolution: {integrity: sha512-+rFJ9HcukDl59X9pI6lgZDtJHtKqHg6BIdS4LG759X+5MV7wvlNb4S+bQ3qKqIlBsQhH17bzIJCfsWZwjwxecw==} @@ -12234,7 +12234,7 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true - '@roo-code/cloud@0.10.0': + '@roo-code/cloud@0.11.0': dependencies: '@roo-code/types': 1.45.0 ioredis: 5.6.1 diff --git a/src/package.json b/src/package.json index 29effb2f3a..64ccc99b7c 100644 --- a/src/package.json +++ b/src/package.json @@ -420,7 +420,7 @@ "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.9.0", "@qdrant/js-client-rest": "^1.14.0", - "@roo-code/cloud": "^0.10.0", + "@roo-code/cloud": "^0.11.0", "@roo-code/ipc": "workspace:^", "@roo-code/telemetry": "workspace:^", "@roo-code/types": "workspace:^",