[PROTOBUS] Move deleteRuleFile to protobus 🚌💨 (#3124)

* createRuleFile protobus migration

* deleteRuleFile protobus

* mend

* mend

* mend

* ellipsis changes

* Generic response for delete request

* refactored deleteRuleFile for consolidation

* rename ruleFileResult to ruleFile
This commit is contained in:
canvrno 2025-05-01 16:06:54 -07:00 committed by GitHub
parent f6d50ead3f
commit 4650ffa86b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 393 additions and 26 deletions

View File

@ -0,0 +1,5 @@
---
"claude-dev": patch
---
deleteRuleFile protobus migration

View File

@ -49,3 +49,9 @@ message BooleanRequest {
message Boolean {
bool value = 1;
}
// Generic response for operations that return success status and a message
message OperationResponse {
bool success = 1; // Whether the operation was successful
string message = 2; // Success or error message
}

View File

@ -13,4 +13,20 @@ service FileService {
// Opens an image in the system viewer
rpc openImage(StringRequest) returns (Empty);
// Deletes a rule file from either global or workspace rules directory
rpc deleteRuleFile(DeleteRuleFileRequest) returns (RuleFile);
}
// Request for deleteRuleFile
message DeleteRuleFileRequest {
Metadata metadata = 1;
string rule_path = 2;
bool is_global = 3;
}
// Result for rule file operations with meaningful data only
message RuleFile {
string file_path = 1; // Path to the rule file
string display_name = 2; // Filename for display purposes
}

View File

@ -0,0 +1,47 @@
import { Controller } from ".."
import { DeleteRuleFileRequest, RuleFile } from "@shared/proto/file"
import { FileMethodHandler } from "./index"
import {
deleteRuleFile as deleteRuleFileImpl,
refreshClineRulesToggles,
} from "@core/context/instructions/user-instructions/cline-rules"
import * as vscode from "vscode"
import * as path from "path"
import { cwd } from "@core/task"
/**
* Deletes a rule file from either global or workspace rules directory
* @param controller The controller instance
* @param request The request containing rule path and isGlobal flag
* @returns Result with file path and display name
* @throws Error if operation fails
*/
export const deleteRuleFile: FileMethodHandler = async (
controller: Controller,
request: DeleteRuleFileRequest,
): Promise<RuleFile> => {
if (typeof request.isGlobal !== "boolean" || typeof request.rulePath !== "string" || !request.rulePath) {
console.error("deleteRuleFile: Missing or invalid parameters", {
isGlobal: typeof request.isGlobal === "boolean" ? request.isGlobal : `Invalid: ${typeof request.isGlobal}`,
rulePath: typeof request.rulePath === "string" ? request.rulePath : `Invalid: ${typeof request.rulePath}`,
})
throw new Error("Missing or invalid parameters")
}
const result = await deleteRuleFileImpl(controller.context, request.rulePath, request.isGlobal)
if (!result.success) {
throw new Error(result.message || "Failed to delete rule file")
}
await refreshClineRulesToggles(controller.context, cwd)
await controller.postStateToWebview()
const fileName = path.basename(request.rulePath)
vscode.window.showInformationMessage(`Rule file "${fileName}" deleted successfully`)
return RuleFile.create({
filePath: request.rulePath,
displayName: fileName,
})
}

View File

@ -3,12 +3,14 @@
// Import all method implementations
import { registerMethod } from "./index"
import { deleteRuleFile } from "./deleteRuleFile"
import { openFile } from "./openFile"
import { openImage } from "./openImage"
// Register all file service methods
export function registerAllMethods(): void {
// Register each method with the registry
registerMethod("deleteRuleFile", deleteRuleFile)
registerMethod("openFile", openFile)
registerMethod("openImage", openImage)
}

View File

@ -48,7 +48,7 @@ import {
} from "../storage/state"
import { Task, cwd } from "../task"
import { ClineRulesToggles } from "@shared/cline-rules"
import { createRuleFile, deleteRuleFile, refreshClineRulesToggles } from "../context/instructions/user-instructions/cline-rules"
import { createRuleFile, refreshClineRulesToggles } from "../context/instructions/user-instructions/cline-rules"
/*
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
@ -549,24 +549,6 @@ export class Controller {
}
break
}
case "deleteClineRule": {
const { isGlobal, rulePath } = message
if (rulePath && typeof isGlobal === "boolean") {
const result = await deleteRuleFile(this.context, rulePath, isGlobal)
if (result.success) {
await refreshClineRulesToggles(this.context, cwd)
await this.postStateToWebview()
} else {
console.error("Failed to delete rule file:", result.message)
}
} else {
console.error("deleteClineRule: Missing or invalid parameters", {
rulePath,
isGlobal: typeof isGlobal === "boolean" ? isGlobal : `Invalid: ${typeof isGlobal}`,
})
}
break
}
case "requestTotalTasksSize": {
this.refreshTotalTasksSize()
break

View File

@ -53,6 +53,14 @@ export interface Boolean {
value: boolean
}
/** Generic response for operations that return success status and a message */
export interface OperationResponse {
/** Whether the operation was successful */
success: boolean
/** Success or error message */
message: string
}
function createBaseMetadata(): Metadata {
return {}
}
@ -738,6 +746,82 @@ export const Boolean: MessageFns<Boolean> = {
},
}
function createBaseOperationResponse(): OperationResponse {
return { success: false, message: "" }
}
export const OperationResponse: MessageFns<OperationResponse> = {
encode(message: OperationResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.success !== false) {
writer.uint32(8).bool(message.success)
}
if (message.message !== "") {
writer.uint32(18).string(message.message)
}
return writer
},
decode(input: BinaryReader | Uint8Array, length?: number): OperationResponse {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = createBaseOperationResponse()
while (reader.pos < end) {
const tag = reader.uint32()
switch (tag >>> 3) {
case 1: {
if (tag !== 8) {
break
}
message.success = reader.bool()
continue
}
case 2: {
if (tag !== 18) {
break
}
message.message = reader.string()
continue
}
}
if ((tag & 7) === 4 || tag === 0) {
break
}
reader.skip(tag & 7)
}
return message
},
fromJSON(object: any): OperationResponse {
return {
success: isSet(object.success) ? globalThis.Boolean(object.success) : false,
message: isSet(object.message) ? globalThis.String(object.message) : "",
}
},
toJSON(message: OperationResponse): unknown {
const obj: any = {}
if (message.success !== false) {
obj.success = message.success
}
if (message.message !== "") {
obj.message = message.message
}
return obj
},
create<I extends Exact<DeepPartial<OperationResponse>, I>>(base?: I): OperationResponse {
return OperationResponse.fromPartial(base ?? ({} as any))
},
fromPartial<I extends Exact<DeepPartial<OperationResponse>, I>>(object: I): OperationResponse {
const message = createBaseOperationResponse()
message.success = object.success ?? false
message.message = object.message ?? ""
return message
},
}
function bytesFromBase64(b64: string): Uint8Array {
return Uint8Array.from(globalThis.Buffer.from(b64, "base64"))
}

View File

@ -5,10 +5,195 @@
// source: file.proto
/* eslint-disable */
import { Empty, StringRequest } from "./common"
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"
import { Empty, Metadata, StringRequest } from "./common"
export const protobufPackage = "cline"
/** Request for deleteRuleFile */
export interface DeleteRuleFileRequest {
metadata?: Metadata | undefined
rulePath: string
isGlobal: boolean
}
/** Result for rule file operations with meaningful data only */
export interface RuleFile {
/** Path to the rule file */
filePath: string
/** Filename for display purposes */
displayName: string
}
function createBaseDeleteRuleFileRequest(): DeleteRuleFileRequest {
return { metadata: undefined, rulePath: "", isGlobal: false }
}
export const DeleteRuleFileRequest: MessageFns<DeleteRuleFileRequest> = {
encode(message: DeleteRuleFileRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.metadata !== undefined) {
Metadata.encode(message.metadata, writer.uint32(10).fork()).join()
}
if (message.rulePath !== "") {
writer.uint32(18).string(message.rulePath)
}
if (message.isGlobal !== false) {
writer.uint32(24).bool(message.isGlobal)
}
return writer
},
decode(input: BinaryReader | Uint8Array, length?: number): DeleteRuleFileRequest {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = createBaseDeleteRuleFileRequest()
while (reader.pos < end) {
const tag = reader.uint32()
switch (tag >>> 3) {
case 1: {
if (tag !== 10) {
break
}
message.metadata = Metadata.decode(reader, reader.uint32())
continue
}
case 2: {
if (tag !== 18) {
break
}
message.rulePath = reader.string()
continue
}
case 3: {
if (tag !== 24) {
break
}
message.isGlobal = reader.bool()
continue
}
}
if ((tag & 7) === 4 || tag === 0) {
break
}
reader.skip(tag & 7)
}
return message
},
fromJSON(object: any): DeleteRuleFileRequest {
return {
metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined,
rulePath: isSet(object.rulePath) ? globalThis.String(object.rulePath) : "",
isGlobal: isSet(object.isGlobal) ? globalThis.Boolean(object.isGlobal) : false,
}
},
toJSON(message: DeleteRuleFileRequest): unknown {
const obj: any = {}
if (message.metadata !== undefined) {
obj.metadata = Metadata.toJSON(message.metadata)
}
if (message.rulePath !== "") {
obj.rulePath = message.rulePath
}
if (message.isGlobal !== false) {
obj.isGlobal = message.isGlobal
}
return obj
},
create<I extends Exact<DeepPartial<DeleteRuleFileRequest>, I>>(base?: I): DeleteRuleFileRequest {
return DeleteRuleFileRequest.fromPartial(base ?? ({} as any))
},
fromPartial<I extends Exact<DeepPartial<DeleteRuleFileRequest>, I>>(object: I): DeleteRuleFileRequest {
const message = createBaseDeleteRuleFileRequest()
message.metadata =
object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined
message.rulePath = object.rulePath ?? ""
message.isGlobal = object.isGlobal ?? false
return message
},
}
function createBaseRuleFile(): RuleFile {
return { filePath: "", displayName: "" }
}
export const RuleFile: MessageFns<RuleFile> = {
encode(message: RuleFile, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
if (message.filePath !== "") {
writer.uint32(10).string(message.filePath)
}
if (message.displayName !== "") {
writer.uint32(18).string(message.displayName)
}
return writer
},
decode(input: BinaryReader | Uint8Array, length?: number): RuleFile {
const reader = input instanceof BinaryReader ? input : new BinaryReader(input)
let end = length === undefined ? reader.len : reader.pos + length
const message = createBaseRuleFile()
while (reader.pos < end) {
const tag = reader.uint32()
switch (tag >>> 3) {
case 1: {
if (tag !== 10) {
break
}
message.filePath = reader.string()
continue
}
case 2: {
if (tag !== 18) {
break
}
message.displayName = reader.string()
continue
}
}
if ((tag & 7) === 4 || tag === 0) {
break
}
reader.skip(tag & 7)
}
return message
},
fromJSON(object: any): RuleFile {
return {
filePath: isSet(object.filePath) ? globalThis.String(object.filePath) : "",
displayName: isSet(object.displayName) ? globalThis.String(object.displayName) : "",
}
},
toJSON(message: RuleFile): unknown {
const obj: any = {}
if (message.filePath !== "") {
obj.filePath = message.filePath
}
if (message.displayName !== "") {
obj.displayName = message.displayName
}
return obj
},
create<I extends Exact<DeepPartial<RuleFile>, I>>(base?: I): RuleFile {
return RuleFile.fromPartial(base ?? ({} as any))
},
fromPartial<I extends Exact<DeepPartial<RuleFile>, I>>(object: I): RuleFile {
const message = createBaseRuleFile()
message.filePath = object.filePath ?? ""
message.displayName = object.displayName ?? ""
return message
},
}
/** Service for file-related operations */
export type FileServiceDefinition = typeof FileServiceDefinition
export const FileServiceDefinition = {
@ -33,5 +218,44 @@ export const FileServiceDefinition = {
responseStream: false,
options: {},
},
/** Deletes a rule file from either global or workspace rules directory */
deleteRuleFile: {
name: "deleteRuleFile",
requestType: DeleteRuleFileRequest,
requestStream: false,
responseType: RuleFile,
responseStream: false,
options: {},
},
},
} as const
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined
export type DeepPartial<T> = T extends Builtin
? T
: T extends globalThis.Array<infer U>
? globalThis.Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>
type KeysOfUnion<T> = T extends T ? keyof T : never
export type Exact<P, I extends P> = P extends Builtin
? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never }
function isSet(value: any): boolean {
return value !== null && value !== undefined
}
export interface MessageFns<T> {
encode(message: T, writer?: BinaryWriter): BinaryWriter
decode(input: BinaryReader | Uint8Array, length?: number): T
fromJSON(object: any): T
toJSON(message: T): unknown
create<I extends Exact<DeepPartial<T>, I>>(base?: I): T
fromPartial<I extends Exact<DeepPartial<T>, I>>(object: I): T
}

View File

@ -1,6 +1,6 @@
import { vscode } from "@/utils/vscode"
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
import { FileServiceClient } from "@/services/grpc-client"
import { DeleteRuleFileRequest } from "@shared/proto/file"
const RuleRow: React.FC<{
rulePath: string
@ -16,11 +16,12 @@ const RuleRow: React.FC<{
}
const handleDeleteClick = () => {
vscode.postMessage({
type: "deleteClineRule",
rulePath: rulePath,
isGlobal: isGlobal,
})
FileServiceClient.deleteRuleFile(
DeleteRuleFileRequest.create({
rulePath: rulePath,
isGlobal: isGlobal,
}),
).catch((err) => console.error("Failed to delete rule file:", err))
}
return (