mirror of
https://github.com/cline/cline.git
synced 2026-09-16 06:32:31 +08:00
* chore: add CLI type checking and caching to ci workflow - Added a new cache step for CLI dependencies in the GitHub Actions test workflow to improve build performance. - Included a step to install CLI dependencies using `npm ci`. - Updated the `ci:check-all` script in `package.json` to include CLI type checking. - Added a `cli:typecheck` script to handle type checking within the CLI directory. * Fix type and import issues for cli * Includes CI tests in test workflow * use npx npm-run-all * update ci:check-all * ci: skip npm ci steps on cache hit in test workflow Update the test workflow to conditionally run npm installation steps only when a cache hit is not found. This optimization reduces CI execution time by avoiding redundant dependency installations when the node_modules are already restored from cache. * ci: update cache keys and add dependency verification in test workflow Updated the cache keys for root, webview-ui, cli, and testing-platform dependencies by adding a version prefix (v1). This ensures a clean cache state and helps avoid potential corruption or mismatch issues. Additionally, added a verification step in the test job to log cache hit status and check for the presence of key dependencies like biome and globby. This helps diagnose issues where the cache might be restored but dependencies are not correctly available for subsequent steps. * update Verify and fix root dependencies * fix type check script * add isSettingsKey check * update settingskey set * apply feedback * npx * feat: flashing dot for streaming chat messages in CI (#9054) Introduce an ink-spinner to the DotRow component to provide visual feedback when messages are being streamed. This improves the CLI user experience by clearly indicating that a tool call or message is currently in progress. - Add `flashing` prop to `DotRow` component - Replace static dot with `toggle8` spinner when `flashing` is true - Update `ChatMessage` to pass `flashing` state based on `isStreaming` and `partial` message properties Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> * ci: simplify dependency caching using built-in npm cache Replace manual actions/cache steps with setup-node's built-in npm caching feature across all workflow jobs. This change: - Removes redundant cache action steps for root, webview-ui, cli, and testing-platform dependencies - Uses setup-node's native `cache: 'npm'` option with `cache-dependency-path` to handle multiple package-lock.json files - Eliminates conditional installation steps based on cache hits - Reduces workflow complexity and maintenance overhead while maintaining caching functionality The built-in caching provides the same performance benefits with less configuration and better integration with the Node.js setup action. --------- Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
215 lines
7.5 KiB
JavaScript
Executable File
215 lines
7.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import path from "path"
|
|
import { fileURLToPath } from "url"
|
|
import { writeFileWithMkdirs } from "./file-utils.mjs"
|
|
import { getFqn, loadServicesFromProtoDescriptor } from "./proto-utils.mjs"
|
|
|
|
const WEBVIEW_CLIENTS_FILE = path.resolve("webview-ui/src/services/grpc-client.ts")
|
|
const VSCODE_SERVICES_FILE = path.resolve("src/generated/hosts/vscode/protobus-services.ts")
|
|
const VSCODE_SERVICE_TYPES_FILE = path.resolve("src/generated/hosts/vscode/protobus-service-types.ts")
|
|
const STANDALONE_SERVER_SETUP_FILE = path.resolve("src/generated/hosts/standalone/protobus-server-setup.ts")
|
|
|
|
const SCRIPT_NAME = path.relative(process.cwd(), fileURLToPath(import.meta.url))
|
|
|
|
export async function main() {
|
|
const { protobusServices } = await loadServicesFromProtoDescriptor()
|
|
await generateWebviewProtobusClients(protobusServices)
|
|
await generateVscodeServiceTypes(protobusServices)
|
|
await generateVscodeProtobusServers(protobusServices)
|
|
await generateStandaloneProtobusServiceSetup(protobusServices)
|
|
|
|
console.log(`Generated ProtoBus files at:`)
|
|
console.log(`- ${WEBVIEW_CLIENTS_FILE}`)
|
|
console.log(`- ${VSCODE_SERVICE_TYPES_FILE}`)
|
|
console.log(`- ${VSCODE_SERVICES_FILE}`)
|
|
console.log(`- ${STANDALONE_SERVER_SETUP_FILE}`)
|
|
}
|
|
|
|
async function generateWebviewProtobusClients(protobusServices) {
|
|
const clients = []
|
|
|
|
for (const [serviceName, def] of Object.entries(protobusServices)) {
|
|
const rpcs = []
|
|
for (const [rpcName, rpc] of Object.entries(def.service)) {
|
|
const requestType = getFqn(rpc.requestType.type.name)
|
|
const responseType = getFqn(rpc.responseType.type.name)
|
|
|
|
if (rpc.requestStream) {
|
|
throw new Error("Request streaming is not supported")
|
|
}
|
|
if (!rpc.responseStream) {
|
|
rpcs.push(` static async ${rpcName}(request: ${requestType}): Promise<${responseType}> {
|
|
return this.makeUnaryRequest("${rpcName}", request, ${requestType}.toJSON, ${responseType}.fromJSON)
|
|
}`)
|
|
} else {
|
|
rpcs.push(` static ${rpcName}(request: ${requestType}, callbacks: Callbacks<${responseType}>): ()=>void {
|
|
return this.makeStreamingRequest("${rpcName}", request, ${requestType}.toJSON, ${responseType}.fromJSON, callbacks)
|
|
}`)
|
|
}
|
|
}
|
|
clients.push(`export class ${serviceName}Client extends ProtoBusClient {
|
|
static override serviceName: string = "cline.${serviceName}"
|
|
${rpcs.join("\n")}
|
|
}`)
|
|
}
|
|
|
|
// Create output file
|
|
const output = `// GENERATED CODE -- DO NOT EDIT!
|
|
// Generated by ${SCRIPT_NAME}
|
|
import * as proto from "@shared/proto/index"
|
|
import { ProtoBusClient, Callbacks } from "./grpc-client-base"
|
|
|
|
${clients.join("\n")}
|
|
`
|
|
// Write output file
|
|
await writeFileWithMkdirs(WEBVIEW_CLIENTS_FILE, output)
|
|
}
|
|
|
|
/**
|
|
* Generate imports and function to add all the handlers to the server for all services defined in the proto files.
|
|
*/
|
|
async function generateVscodeServiceTypes(protobusServices) {
|
|
const servers = []
|
|
|
|
for (const [serviceName, def] of Object.entries(protobusServices)) {
|
|
const domain = getDomainName(serviceName)
|
|
servers.push(`// ${domain} Service Handler Types`)
|
|
servers.push(`export type ${serviceName}Handlers = {`)
|
|
for (const [rpcName, rpc] of Object.entries(def.service)) {
|
|
const requestType = getFqn(rpc.requestType.type.name)
|
|
const responseType = getFqn(rpc.responseType.type.name)
|
|
if (rpc.requestStream) {
|
|
throw new Error("Request streaming is not supported")
|
|
}
|
|
if (!rpc.responseStream) {
|
|
servers.push(` ${rpcName}:(controller: Controller, request: ${requestType}) => Promise<${responseType}>`)
|
|
} else {
|
|
servers.push(
|
|
` ${rpcName}:(controller: Controller, request: ${requestType}, responseStream: StreamingResponseHandler<${responseType}>, requestId?: string) => Promise<void>`,
|
|
)
|
|
}
|
|
}
|
|
servers.push(`}\n`)
|
|
}
|
|
|
|
// Create output file
|
|
const output = `// GENERATED CODE -- DO NOT EDIT!
|
|
// Generated by ${SCRIPT_NAME}
|
|
import * as proto from "@shared/proto/index"
|
|
import { Controller } from "@core/controller"
|
|
import { StreamingResponseHandler } from "@/core/controller/grpc-handler"
|
|
|
|
${servers.join("\n")}
|
|
`
|
|
// Write output file
|
|
await writeFileWithMkdirs(VSCODE_SERVICE_TYPES_FILE, output)
|
|
}
|
|
|
|
/**
|
|
* Generate imports and function to add all the handlers to the server for all services defined in the proto files.
|
|
*/
|
|
async function generateVscodeProtobusServers(protobusServices) {
|
|
const imports = []
|
|
const servers = []
|
|
const serviceMap = []
|
|
for (const [serviceName, def] of Object.entries(protobusServices)) {
|
|
const domain = getDomainName(serviceName)
|
|
const dir = getDirName(serviceName)
|
|
imports.push(`// ${domain} Service`)
|
|
servers.push(`const ${serviceName}Handlers: serviceTypes.${serviceName}Handlers = {`)
|
|
for (const [rpcName, _rpc] of Object.entries(def.service)) {
|
|
imports.push(`import { ${rpcName} } from "@core/controller/${dir}/${rpcName}"`)
|
|
servers.push(` ${rpcName}: ${rpcName},`)
|
|
}
|
|
servers.push(`} \n`)
|
|
serviceMap.push(` "cline.${serviceName}": ${serviceName}Handlers,`)
|
|
imports.push("")
|
|
}
|
|
|
|
// Create output file
|
|
const output = `// GENERATED CODE -- DO NOT EDIT!
|
|
// Generated by ${SCRIPT_NAME}
|
|
import * as serviceTypes from "@generated/hosts/vscode/protobus-service-types"
|
|
|
|
${imports.join("\n")}
|
|
${servers.join("\n")}
|
|
export const serviceHandlers: Record<string, any> = {
|
|
${serviceMap.join("\n")}
|
|
}
|
|
`
|
|
// Write output file
|
|
await writeFileWithMkdirs(VSCODE_SERVICES_FILE, output)
|
|
}
|
|
|
|
/**
|
|
* Generate imports and function to add all the handlers to the server for all services defined in the proto files.
|
|
*/
|
|
async function generateStandaloneProtobusServiceSetup(protobusServices) {
|
|
const imports = []
|
|
const handlerSetup = []
|
|
|
|
for (const [name, def] of Object.entries(protobusServices)) {
|
|
const domain = getDomainName(name)
|
|
const dir = getDirName(name)
|
|
imports.push(`// ${domain} Service`)
|
|
handlerSetup.push(` // ${domain} Service`)
|
|
handlerSetup.push(` server.addService(cline.${name}Service, {`)
|
|
for (const [rpcName, rpc] of Object.entries(def.service)) {
|
|
imports.push(`import { ${rpcName} } from "@core/controller/${dir}/${rpcName}"`)
|
|
const requestType = "cline." + rpc.requestType.type.name
|
|
const responseType = "cline." + rpc.responseType.type.name
|
|
if (rpc.requestStream) {
|
|
throw new Error("Request streaming is not supported")
|
|
}
|
|
if (rpc.responseStream) {
|
|
handlerSetup.push(
|
|
` ${rpcName}: wrapStreamingResponse<${requestType},${responseType}>(${rpcName}, controller),`,
|
|
)
|
|
} else {
|
|
handlerSetup.push(` ${rpcName}: wrapper<${requestType},${responseType}>(${rpcName}, controller),`)
|
|
}
|
|
}
|
|
handlerSetup.push(` });`)
|
|
imports.push("")
|
|
handlerSetup.push("")
|
|
}
|
|
|
|
// Create output file
|
|
const output = `// GENERATED CODE -- DO NOT EDIT!
|
|
// Generated by ${SCRIPT_NAME}
|
|
import * as grpc from "@grpc/grpc-js"
|
|
import { cline } from "@generated/grpc-js"
|
|
import { Controller } from "@core/controller"
|
|
import { GrpcHandlerWrapper, GrpcStreamingResponseHandlerWrapper } from "@hosts/external/grpc-types"
|
|
|
|
${imports.join("\n")}
|
|
export function addProtobusServices(
|
|
server: grpc.Server,
|
|
controller: Controller,
|
|
wrapper: GrpcHandlerWrapper,
|
|
wrapStreamingResponse: GrpcStreamingResponseHandlerWrapper,
|
|
): void {
|
|
${handlerSetup.join("\n")}
|
|
}
|
|
`
|
|
// Write output file
|
|
await writeFileWithMkdirs(STANDALONE_SERVER_SETUP_FILE, output)
|
|
}
|
|
|
|
function getDomainName(serviceName) {
|
|
return serviceName.replace(/Service$/, "")
|
|
}
|
|
function getDirName(serviceName) {
|
|
const domain = getDomainName(serviceName)
|
|
return domain.charAt(0).toLowerCase() + domain.slice(1)
|
|
}
|
|
|
|
// Only run main if this script is executed directly
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
main().catch((error) => {
|
|
console.error(chalk.red("Error:"), error)
|
|
process.exit(1)
|
|
})
|
|
}
|