Files
cline/scripts/test-hostbridge-server.ts
T
Bee 26b6c7bdb6 refactor: move vscode config access to hostbridge layer (#7843)
- Add error_level field to telemetry proto messages
- Move getConfiguration usage from core services to vscode hostbridge provider
- Remove migrateDisableBrowserToolSetting and migrateChromeExecutablePathSetting methods
- Remove direct vscode imports from core/task and services/browser
- Update getTelemetrySettings to retrieve and return telemetryLevel from vscode config

This refactoring centralizes vscode-specific configuration access in the hostbridge provider layer, improving separation of concerns and making core services less coupled to the vscode API. Plus the cline configurations has already been set to be empty in the package.json for vs code extension.
2025-12-18 19:43:50 -08:00

152 lines
4.6 KiB
TypeScript
Executable File

#!/usr/bin/env npx tsx
import * as grpc from "@grpc/grpc-js"
import { ReflectionService } from "@grpc/reflection"
import * as health from "grpc-health-check"
import * as os from "os"
import { type DiffServiceServer, DiffServiceService } from "../src/generated/grpc-js/host/diff"
import { type EnvServiceServer, EnvServiceService } from "../src/generated/grpc-js/host/env"
import { type TestingServiceServer, TestingServiceService } from "../src/generated/grpc-js/host/testing"
import { type WindowServiceServer, WindowServiceService } from "../src/generated/grpc-js/host/window"
import { type WorkspaceServiceServer, WorkspaceServiceService } from "../src/generated/grpc-js/host/workspace"
import { getPackageDefinition } from "./proto-utils.mjs"
export async function startTestHostBridgeServer() {
const server = new grpc.Server()
// Set up health check
const healthImpl = new health.HealthImplementation({ "": "SERVING" })
healthImpl.addToServer(server)
// Add host bridge services using the mock implementations
server.addService(WorkspaceServiceService, createMockService<WorkspaceServiceServer>("WorkspaceService"))
server.addService(WindowServiceService, createMockService<WindowServiceServer>("WindowService"))
server.addService(EnvServiceService, createMockService<EnvServiceServer>("EnvService"))
server.addService(DiffServiceService, createMockService<DiffServiceServer>("DiffService"))
server.addService(TestingServiceService, createMockService<TestingServiceServer>("TestingService"))
// Load package definition for reflection service
const packageDefinition = await getPackageDefinition()
// Filter service names to only include host services
const hostBridgeServiceNames = Object.keys(packageDefinition).filter(
(name) => name.startsWith("host.") || name.startsWith("grpc.health"),
)
const reflection = new ReflectionService(packageDefinition, {
services: hostBridgeServiceNames,
})
reflection.addToServer(server)
const bindAddress = process.env.HOST_BRIDGE_ADDRESS || `127.0.0.1:26041`
server.bindAsync(bindAddress, grpc.ServerCredentials.createInsecure(), (err) => {
if (err) {
console.error(`Failed to bind test host bridge server to ${bindAddress}:`, err)
process.exit(1)
}
server.start()
console.log(`Test HostBridge gRPC server listening on ${bindAddress}`)
})
}
/**
* Creates a mock gRPC service implementation using Proxy
* @param serviceName Name of the service for logging
* @returns A proxy that implements the service interface
*/
function createMockService<T extends grpc.UntypedServiceImplementation>(serviceName: string): T {
const handler: ProxyHandler<T> = {
get(_target, prop) {
// Return a function that handles the gRPC call
return (call: any, callback: any) => {
console.log(`Hostbridge: ${serviceName}.${String(prop)} called with:`, call.request)
// Special cases that need specific return values
switch (prop) {
case "getWorkspacePaths":
const workspaceDir = process.env.TEST_HOSTBRIDGE_WORKSPACE_DIR || "/test-workspace"
callback(null, {
paths: [workspaceDir],
})
return
case "getMachineId":
callback(null, {
value: "fake-machine-id-" + os.hostname(),
})
return
case "getTelemetrySettings":
callback(null, {
isEnabled: 2, // Setting.DISABLED
errorLevel: "all",
})
return
case "clipboardReadText":
callback(null, {
value: "",
})
return
case "getWebviewHtml":
callback(null, {
html: "<html><body>Fake Webview</body></html>",
})
return
case "showTextDocument":
callback(null, {
document_path: call.request?.path || "",
view_column: 1,
is_active: true,
})
return
case "openDiff":
callback(null, {
diff_id: "fake-diff-" + Date.now(),
})
return
case "getDocumentText":
callback(null, {
content: "",
})
return
case "getOpenTabs":
case "getVisibleTabs":
case "showOpenDialogue":
callback(null, {
paths: [],
})
return
case "getDiagnostics":
callback(null, {
file_diagnostics: [],
})
return
// For streaming methods (like subscribeToTelemetrySettings)
case "subscribeToTelemetrySettings":
// Just end the stream immediately
call.end()
return
}
// Default: return empty object for all other methods
callback(null, {})
}
},
}
return new Proxy({} as T, handler)
}
if (require.main === module) {
startTestHostBridgeServer().catch((err) => {
console.error("Failed to start test host bridge server:", err)
process.exit(1)
})
}