From 9507b01c4c2a18a29a42c598086c3cda9ece7394 Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Mon, 16 Mar 2026 12:24:07 +0100 Subject: [PATCH] fix: rely on optimistic removal instead of stale backend response The DELETE endpoint was returning data that somehow rendered as empty rows in the webview. Simplify the approach: - Webview optimistically removes the skill from its signal immediately - Extension fires DELETE to the backend (deletes from disk + cache) - Extension invalidates cachedSkillsMessage so next tab visit fetches fresh data - No second skillsLoaded message is sent after removal, avoiding the stale data overwrite that caused the UI corruption --- packages/kilo-vscode/src/KiloProvider.ts | 14 ++++------- .../opencode/src/server/routes/kilocode.ts | 10 ++++---- packages/sdk/js/src/v2/gen/sdk.gen.ts | 2 +- packages/sdk/js/src/v2/gen/types.gen.ts | 9 ++----- packages/sdk/openapi.json | 24 +++---------------- 5 files changed, 15 insertions(+), 44 deletions(-) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 9db1031fd6f..b8ce386a0ad 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1133,23 +1133,19 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } /** - * Remove a skill via the CLI backend (deletes from disk + clears cache). - * The DELETE endpoint returns the updated skills list, which we send directly to the webview. + * Remove a skill via the CLI backend (deletes from disk + clears cache), then refresh. + * The webview optimistically removes the skill from its list before this runs. */ private async handleRemoveSkill(location: string): Promise { if (!this.client) return try { const dir = this.getWorkspaceDirectory() - const { data: skills } = await this.client.kilocode.removeSkill( - { location, directory: dir }, - { throwOnError: true }, - ) - const message = { type: "skillsLoaded", skills } - this.cachedSkillsMessage = message - this.postMessage(message) + await this.client.kilocode.removeSkill({ location, directory: dir }) } catch (error) { console.error("[Kilo New] KiloProvider: Failed to remove skill:", error) } + // Invalidate cache so next requestSkills fetches fresh data + this.cachedSkillsMessage = null } /** diff --git a/packages/opencode/src/server/routes/kilocode.ts b/packages/opencode/src/server/routes/kilocode.ts index 3e120d7d2e8..60d077fe1b5 100644 --- a/packages/opencode/src/server/routes/kilocode.ts +++ b/packages/opencode/src/server/routes/kilocode.ts @@ -13,15 +13,14 @@ export const KilocodeRoutes = lazy(() => "/skill", describeRoute({ summary: "Remove a skill", - description: - "Remove a skill by deleting its directory from disk and clearing it from cache. Returns the updated skills list.", + description: "Remove a skill by deleting its directory from disk and clearing it from cache.", operationId: "kilocode.removeSkill", responses: { 200: { - description: "Updated list of skills after removal", + description: "Skill removed", content: { "application/json": { - schema: resolver(Skill.Info.array()), + schema: resolver(z.boolean()), }, }, }, @@ -37,8 +36,7 @@ export const KilocodeRoutes = lazy(() => async (c) => { const { location } = c.req.valid("query") await Skill.remove(location) - const skills = await Skill.all() - return c.json(skills) + return c.json(true) }, ), ) diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 7328e0d95af..b88b95c24a7 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -2934,7 +2934,7 @@ export class Kilocode extends HeyApiClient { /** * Remove a skill * - * Remove a skill by deleting its directory from disk and clearing it from cache. Returns the updated skills list. + * Remove a skill by deleting its directory from disk and clearing it from cache. */ public removeSkill( parameters: { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 4c9a0741520..47c1300d35f 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -4424,14 +4424,9 @@ export type KilocodeRemoveSkillError = KilocodeRemoveSkillErrors[keyof KilocodeR export type KilocodeRemoveSkillResponses = { /** - * Updated list of skills after removal + * Skill removed */ - 200: Array<{ - name: string - description: string - location: string - content: string - }> + 200: boolean } export type KilocodeRemoveSkillResponse = KilocodeRemoveSkillResponses[keyof KilocodeRemoveSkillResponses] diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 686994f0d9d..5e09dbd374e 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -5400,32 +5400,14 @@ } ], "summary": "Remove a skill", - "description": "Remove a skill by deleting its directory from disk and clearing it from cache. Returns the updated skills list.", + "description": "Remove a skill by deleting its directory from disk and clearing it from cache.", "responses": { "200": { - "description": "Updated list of skills after removal", + "description": "Skill removed", "content": { "application/json": { "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "location": { - "type": "string" - }, - "content": { - "type": "string" - } - }, - "required": ["name", "description", "location", "content"] - } + "type": "boolean" } } }