mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
feat: add DELETE /skill endpoint and use CLI backend for skill removal
Add Skill.remove() that deletes the skill directory from disk and mutates the cached Instance.state in-place so subsequent GET /skill calls return the updated list. Add DELETE /skill?location=... server endpoint, regenerate the SDK, and update KiloProvider to call the SDK method instead of deleting files directly from the extension.
This commit is contained in:
@@ -1133,15 +1133,15 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a skill by deleting its directory from disk, then refresh the skills list.
|
||||
* The location is the path to the SKILL.md file; the skill directory is its parent.
|
||||
* Remove a skill via the CLI backend (deletes from disk + clears cache), then refresh.
|
||||
*/
|
||||
private async handleRemoveSkill(location: string): Promise<void> {
|
||||
const dir = path.dirname(location)
|
||||
if (!this.client) return
|
||||
try {
|
||||
await vscode.workspace.fs.delete(vscode.Uri.file(dir), { recursive: true })
|
||||
const dir = this.getWorkspaceDirectory()
|
||||
await this.client.app.removeSkill({ location, directory: dir }, { throwOnError: true })
|
||||
} catch (error) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to delete skill directory:", dir, error)
|
||||
console.error("[Kilo New] KiloProvider: Failed to remove skill:", error)
|
||||
}
|
||||
this.cachedSkillsMessage = null
|
||||
await this.fetchAndSendSkills()
|
||||
|
||||
@@ -500,6 +500,38 @@ export namespace Server {
|
||||
return c.json(skills)
|
||||
},
|
||||
)
|
||||
// kilocode_change start
|
||||
.delete(
|
||||
"/skill",
|
||||
describeRoute({
|
||||
summary: "Remove a skill",
|
||||
description: "Remove a skill by deleting its directory from disk and clearing it from cache.",
|
||||
operationId: "app.removeSkill",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Skill removed",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.boolean()),
|
||||
},
|
||||
},
|
||||
},
|
||||
...errors(400),
|
||||
},
|
||||
}),
|
||||
validator(
|
||||
"query",
|
||||
z.object({
|
||||
location: z.string(),
|
||||
}),
|
||||
),
|
||||
async (c) => {
|
||||
const { location } = c.req.valid("query")
|
||||
await Skill.remove(location)
|
||||
return c.json(true)
|
||||
},
|
||||
)
|
||||
// kilocode_change end
|
||||
.get(
|
||||
"/lsp",
|
||||
describeRoute({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import z from "zod"
|
||||
import path from "path"
|
||||
import os from "os"
|
||||
import { rm } from "fs/promises"
|
||||
import { Config } from "../config/config"
|
||||
import { Instance } from "../project/instance"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
@@ -213,4 +214,17 @@ export namespace Skill {
|
||||
export async function dirs() {
|
||||
return state().then((x) => x.dirs)
|
||||
}
|
||||
|
||||
// kilocode_change start
|
||||
export async function remove(location: string) {
|
||||
const dir = path.dirname(location)
|
||||
await rm(dir, { recursive: true, force: true })
|
||||
const s = await state()
|
||||
const name = Object.keys(s.skills).find((k) => s.skills[k].location === location)
|
||||
if (name) {
|
||||
delete s.skills[name]
|
||||
s.dirs = s.dirs.filter((d) => d !== dir)
|
||||
}
|
||||
}
|
||||
// kilocode_change end
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import type {
|
||||
AppAgentsResponses,
|
||||
AppLogErrors,
|
||||
AppLogResponses,
|
||||
AppRemoveSkillErrors,
|
||||
AppRemoveSkillResponses,
|
||||
AppSkillsResponses,
|
||||
Auth as Auth3,
|
||||
AuthRemoveErrors,
|
||||
@@ -4330,6 +4332,38 @@ export class App extends HeyApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a skill
|
||||
*
|
||||
* Remove a skill by deleting its directory from disk and clearing it from cache.
|
||||
*/
|
||||
public removeSkill<ThrowOnError extends boolean = false>(
|
||||
parameters: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
location: string
|
||||
},
|
||||
options?: Options<never, ThrowOnError>,
|
||||
) {
|
||||
const params = buildClientParams(
|
||||
[parameters],
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{ in: "query", key: "directory" },
|
||||
{ in: "query", key: "workspace" },
|
||||
{ in: "query", key: "location" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).delete<AppRemoveSkillResponses, AppRemoveSkillErrors, ThrowOnError>({
|
||||
url: "/skill",
|
||||
...options,
|
||||
...params,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* List skills
|
||||
*
|
||||
|
||||
@@ -5483,6 +5483,35 @@ export type AppAgentsResponses = {
|
||||
|
||||
export type AppAgentsResponse = AppAgentsResponses[keyof AppAgentsResponses]
|
||||
|
||||
export type AppRemoveSkillData = {
|
||||
body?: never
|
||||
path?: never
|
||||
query: {
|
||||
directory?: string
|
||||
workspace?: string
|
||||
location: string
|
||||
}
|
||||
url: "/skill"
|
||||
}
|
||||
|
||||
export type AppRemoveSkillErrors = {
|
||||
/**
|
||||
* Bad request
|
||||
*/
|
||||
400: BadRequestError
|
||||
}
|
||||
|
||||
export type AppRemoveSkillError = AppRemoveSkillErrors[keyof AppRemoveSkillErrors]
|
||||
|
||||
export type AppRemoveSkillResponses = {
|
||||
/**
|
||||
* Skill removed
|
||||
*/
|
||||
200: boolean
|
||||
}
|
||||
|
||||
export type AppRemoveSkillResponse = AppRemoveSkillResponses[keyof AppRemoveSkillResponses]
|
||||
|
||||
export type AppSkillsData = {
|
||||
body?: never
|
||||
path?: never
|
||||
|
||||
@@ -7935,6 +7935,63 @@
|
||||
"source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.app.skills({\n ...\n})"
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "app.removeSkill",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "directory",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "workspace",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "location",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"summary": "Remove a skill",
|
||||
"description": "Remove a skill by deleting its directory from disk and clearing it from cache.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Skill removed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/BadRequestError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-codeSamples": [
|
||||
{
|
||||
"lang": "js",
|
||||
"source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.app.removeSkill({\n ...\n})"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/lsp": {
|
||||
|
||||
Reference in New Issue
Block a user