diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 5f5d6f3aeaf..99c9e4143ef 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -429,6 +429,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper case "requestSkills": this.fetchAndSendSkills().catch((e) => console.error("[Kilo New] fetchAndSendSkills failed:", e)) break + case "removeSkill": + this.handleRemoveSkill(message.location).catch((e) => + console.error("[Kilo New] handleRemoveSkill failed:", e), + ) + break case "questionReply": await this.handleQuestionReply(message.requestID, message.answers) break @@ -1127,6 +1132,32 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } + /** + * 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. + * On failure, re-fetches skills so the webview reverts to the authoritative state. + */ + private async handleRemoveSkill(location: string): Promise { + if (!this.client) return + try { + const dir = this.getWorkspaceDirectory() + const result = await this.client.kilocode.removeSkill({ location, directory: dir }) + if (result.error) { + console.error("[Kilo New] KiloProvider: removeSkill returned error:", result.error) + this.cachedSkillsMessage = null + await this.fetchAndSendSkills() + return + } + } catch (error) { + console.error("[Kilo New] KiloProvider: Failed to remove skill:", error) + this.cachedSkillsMessage = null + await this.fetchAndSendSkills() + return + } + // Invalidate cache so next requestSkills fetches fresh data + this.cachedSkillsMessage = null + } + /** * Fetch backend config and send to webview. */ diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 2ce51e38c23..1d4236d87a1 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -1,15 +1,16 @@ -import { Component, createSignal, createMemo, createEffect, For, Show, onCleanup } from "solid-js" +import { Component, createSignal, createMemo, createEffect, For, Show } from "solid-js" import { Select } from "@kilocode/kilo-ui/select" import { TextField } from "@kilocode/kilo-ui/text-field" import { Card } from "@kilocode/kilo-ui/card" import { Button } from "@kilocode/kilo-ui/button" import { IconButton } from "@kilocode/kilo-ui/icon-button" +import { Dialog } from "@kilocode/kilo-ui/dialog" +import { useDialog } from "@kilocode/kilo-ui/context/dialog" import { useConfig } from "../../context/config" import { useSession } from "../../context/session" import { useLanguage } from "../../context/language" -import { useVSCode } from "../../context/vscode" -import type { AgentConfig, SkillInfo, ExtensionMessage } from "../../types/messages" +import type { AgentConfig, SkillInfo } from "../../types/messages" type SubtabId = "agents" | "mcpServers" | "rules" | "workflows" | "skills" @@ -52,30 +53,20 @@ const AgentBehaviourTab: Component = () => { const language = useLanguage() const { config, updateConfig } = useConfig() const session = useSession() - const vscode = useVSCode() + const dialog = useDialog() const [activeSubtab, setActiveSubtab] = createSignal("agents") const [selectedAgent, setSelectedAgent] = createSignal("") const [newSkillPath, setNewSkillPath] = createSignal("") const [newSkillUrl, setNewSkillUrl] = createSignal("") const [newInstruction, setNewInstruction] = createSignal("") - const [discoveredSkills, setDiscoveredSkills] = createSignal([]) - - // Subscribe to skillsLoaded messages from the extension - const unsub = vscode.onMessage((message: ExtensionMessage) => { - if (message.type === "skillsLoaded") { - setDiscoveredSkills(message.skills) - } - }) // Fetch skills whenever the skills subtab becomes active createEffect(() => { if (activeSubtab() === "skills") { - vscode.postMessage({ type: "requestSkills" }) + session.refreshSkills() } }) - onCleanup(() => unsub()) - const agentNames = createMemo(() => { const names = session.agents().map((a) => a.name) // Also include any agents from config that might not be in the agent list @@ -179,6 +170,31 @@ const AgentBehaviourTab: Component = () => { updateConfig({ skills: { ...config().skills, urls: current } }) } + const confirmRemoveSkill = (skill: SkillInfo) => { + dialog.show(() => ( + +
+ {language.t("settings.agentBehaviour.removeSkill.confirm", { name: skill.name })} +
+ + +
+
+
+ )) + } + const renderAgentsSubtab = () => (
{/* Default agent */} @@ -398,7 +414,7 @@ const AgentBehaviourTab: Component = () => { {language.t("settings.agentBehaviour.discoveredSkills")} 0} + when={session.skills().length > 0} fallback={
{language.t("settings.agentBehaviour.noSkillsFound")}
@@ -406,28 +422,33 @@ const AgentBehaviourTab: Component = () => { } > - + {(skill, index) => (
-
- {skill.name} -
-
-
{skill.description}
-
{skill.location}
+
+
+ {skill.name} +
+
+
{skill.description}
+
{skill.location}
+
+ confirmRemoveSkill(skill)} />
)} diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index 24219c433a8..9bec4955fd9 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -36,6 +36,7 @@ import type { ModelSelection, ContextUsage, AgentInfo, + SkillInfo, ExtensionMessage, FileAttachment, SendMessageFailedMessage, @@ -114,6 +115,11 @@ interface SessionContextValue { totalCost: Accessor contextUsage: Accessor + // Skills loaded from the CLI backend + skills: Accessor + refreshSkills: () => void + removeSkill: (location: string) => void + // Agent/mode selection (per-session) agents: Accessor selectedAgent: Accessor @@ -204,6 +210,9 @@ export const SessionProvider: ParentComponent = (props) => { const [agents, setAgents] = createSignal([]) const [defaultAgent, setDefaultAgent] = createSignal("code") + // Skills loaded from the CLI backend + const [skills, setSkills] = createSignal([]) + // Pending agent selection for before a session exists const [pendingAgentSelection, setPendingAgentSelection] = createSignal(null) @@ -341,8 +350,25 @@ export const SessionProvider: ParentComponent = (props) => { vscode.postMessage({ type: "requestAgents" }) }, agentRetryMs) + // Skills loaded from the CLI backend + const unsubSkills = vscode.onMessage((message: ExtensionMessage) => { + if (message.type === "skillsLoaded") { + setSkills(message.skills) + } + }) + + const refreshSkills = () => { + vscode.postMessage({ type: "requestSkills" }) + } + + const removeSkill = (location: string) => { + setSkills((prev) => prev.filter((s) => s.location !== location)) + vscode.postMessage({ type: "removeSkill", location }) + } + onCleanup(() => { unsubAgents() + unsubSkills() clearInterval(agentRetryTimer) }) @@ -1285,6 +1311,9 @@ export const SessionProvider: ParentComponent = (props) => { totalCost, contextUsage, agents, + skills, + refreshSkills, + removeSkill, selectedAgent: selectedAgentName, selectAgent, getSessionAgent: (sessionID: string) => store.agentSelections[sessionID] ?? defaultAgent(), diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 2f56d1df2af..3cb7863ceff 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -951,6 +951,10 @@ export const dict = { "لم يتم العثور على مهارات. أضف مسارات مجلدات أو عناوين URL أدناه لإتاحة المهارات.", "settings.agentBehaviour.skillPaths": "مسارات مجلدات المهارات", "settings.agentBehaviour.skillUrls": "عناوين URL للمهارات", + "settings.agentBehaviour.removeSkill.title": "إزالة المهارة", + "settings.agentBehaviour.removeSkill.confirm": + 'هل تريد إزالة المهارة "{{name}}"؟ سيؤدي هذا إلى حذف ملفات المهارة من القرص.', + "settings.agentBehaviour.removeSkill.button": "إزالة", "settings.agentBehaviour.instructionFiles": "ملفات تعليمات إضافية", "settings.agentBehaviour.instructionFiles.description": "مسارات ملفات التعليمات الإضافية في موجه النظام", "settings.agentBehaviour.mcpEmpty": "لم يتم تهيئة خوادم MCP. قم بتحرير ملف تهيئة opencode لإضافة خوادم MCP.", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 7af43d62fe7..36d2f565aa7 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -963,6 +963,10 @@ export const dict = { "Nenhuma habilidade encontrada. Adicione caminhos de pastas ou URLs abaixo para disponibilizar habilidades.", "settings.agentBehaviour.skillPaths": "Caminhos de pastas de habilidades", "settings.agentBehaviour.skillUrls": "URLs de habilidades", + "settings.agentBehaviour.removeSkill.title": "Remover habilidade", + "settings.agentBehaviour.removeSkill.confirm": + 'Remover a habilidade "{{name}}"? Isso excluirá os arquivos da habilidade do disco.', + "settings.agentBehaviour.removeSkill.button": "Remover", "settings.agentBehaviour.instructionFiles": "Arquivos de instruções adicionais", "settings.agentBehaviour.instructionFiles.description": "Caminhos para arquivos de instruções adicionais no prompt do sistema", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index f5741c147fe..d7b78449e6b 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -963,6 +963,10 @@ export const dict = { "Nisu pronađene vještine. Dodajte putanje mapa ili URL-ove ispod kako biste učinili vještine dostupnim.", "settings.agentBehaviour.skillPaths": "Putanje mapa vještina", "settings.agentBehaviour.skillUrls": "URL-ovi vještina", + "settings.agentBehaviour.removeSkill.title": "Ukloni vještinu", + "settings.agentBehaviour.removeSkill.confirm": + 'Ukloniti vještinu "{{name}}"? Ovo će obrisati datoteke vještine sa diska.', + "settings.agentBehaviour.removeSkill.button": "Ukloni", "settings.agentBehaviour.instructionFiles": "Dodatne datoteke uputa", "settings.agentBehaviour.instructionFiles.description": "Putanje do dodatnih datoteka uputa u sistemskom promptu", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index ee236fceef0..e8039761794 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -959,6 +959,10 @@ export const dict = { "Ingen skills fundet. Tilføj skill-mappestier eller URL'er nedenfor for at gøre skills tilgængelige.", "settings.agentBehaviour.skillPaths": "Skill-mappestier", "settings.agentBehaviour.skillUrls": "Skill-URL'er", + "settings.agentBehaviour.removeSkill.title": "Fjern færdighed", + "settings.agentBehaviour.removeSkill.confirm": + 'Vil du fjerne færdigheden "{{name}}"? Dette vil slette færdighedsfilerne fra disken.', + "settings.agentBehaviour.removeSkill.button": "Fjern", "settings.agentBehaviour.instructionFiles": "Yderligere instruktionsfiler", "settings.agentBehaviour.instructionFiles.description": "Stier til yderligere instruktionsfiler i systemprompten", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index f7e20e15c31..3b877fe0057 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -974,6 +974,10 @@ export const dict = { "Keine Skills gefunden. Fügen Sie unten Skill-Ordnerpfade oder URLs hinzu, um Skills verfügbar zu machen.", "settings.agentBehaviour.skillPaths": "Skill-Ordnerpfade", "settings.agentBehaviour.skillUrls": "Skill-URLs", + "settings.agentBehaviour.removeSkill.title": "Skill entfernen", + "settings.agentBehaviour.removeSkill.confirm": + 'Skill "{{name}}" entfernen? Dadurch werden die Skill-Dateien vom Datenträger gelöscht.', + "settings.agentBehaviour.removeSkill.button": "Entfernen", "settings.agentBehaviour.instructionFiles": "Zusätzliche Anweisungsdateien", "settings.agentBehaviour.instructionFiles.description": "Pfade zu zusätzlichen Anweisungsdateien im System-Prompt", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index cffafc12273..1582971d356 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -971,6 +971,9 @@ export const dict = { "No skills discovered. Add skill folder paths or URLs below to make skills available.", "settings.agentBehaviour.skillPaths": "Skill Folder Paths", "settings.agentBehaviour.skillUrls": "Skill URLs", + "settings.agentBehaviour.removeSkill.title": "Remove skill", + "settings.agentBehaviour.removeSkill.confirm": 'Remove skill "{{name}}"? This will delete the skill files from disk.', + "settings.agentBehaviour.removeSkill.button": "Remove", "settings.agentBehaviour.instructionFiles": "Additional Instruction Files", "settings.agentBehaviour.instructionFiles.description": "Paths to additional instruction files that are included in the system prompt", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 1a9b99a0303..3787b776cf1 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -966,6 +966,10 @@ export const dict = { "No se encontraron habilidades. Agregue rutas de carpetas o URLs abajo para hacer disponibles las habilidades.", "settings.agentBehaviour.skillPaths": "Rutas de carpetas de habilidades", "settings.agentBehaviour.skillUrls": "URLs de habilidades", + "settings.agentBehaviour.removeSkill.title": "Eliminar habilidad", + "settings.agentBehaviour.removeSkill.confirm": + '¿Eliminar la habilidad "{{name}}"? Esto borrará los archivos de la habilidad del disco.', + "settings.agentBehaviour.removeSkill.button": "Eliminar", "settings.agentBehaviour.instructionFiles": "Archivos de instrucciones adicionales", "settings.agentBehaviour.instructionFiles.description": "Rutas a archivos de instrucciones adicionales incluidos en el prompt del sistema", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 8d0755d572a..3f10e46bd65 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -976,6 +976,10 @@ export const dict = { "Aucune compétence découverte. Ajoutez des chemins de dossiers ou des URLs ci-dessous pour rendre les compétences disponibles.", "settings.agentBehaviour.skillPaths": "Chemins des dossiers de compétences", "settings.agentBehaviour.skillUrls": "URLs de compétences", + "settings.agentBehaviour.removeSkill.title": "Supprimer la compétence", + "settings.agentBehaviour.removeSkill.confirm": + 'Supprimer la compétence "{{name}}" ? Cela supprimera les fichiers de la compétence du disque.', + "settings.agentBehaviour.removeSkill.button": "Supprimer", "settings.agentBehaviour.instructionFiles": "Fichiers d'instructions supplémentaires", "settings.agentBehaviour.instructionFiles.description": "Chemins vers des fichiers d'instructions supplémentaires", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index 0500017fe6f..0319039a1eb 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -959,6 +959,10 @@ export const dict = { "スキルが見つかりません。スキルを利用可能にするには、以下にスキルフォルダパスまたはURLを追加してください。", "settings.agentBehaviour.skillPaths": "スキルフォルダパス", "settings.agentBehaviour.skillUrls": "スキルURL", + "settings.agentBehaviour.removeSkill.title": "スキルを削除", + "settings.agentBehaviour.removeSkill.confirm": + 'スキル "{{name}}" を削除しますか?これにより、ディスクからスキルファイルが削除されます。', + "settings.agentBehaviour.removeSkill.button": "削除", "settings.agentBehaviour.instructionFiles": "追加の指示ファイル", "settings.agentBehaviour.instructionFiles.description": "システムプロンプトに含まれる追加の指示ファイルへのパス", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 618e280fdc3..9c29adae7e0 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -956,6 +956,10 @@ export const dict = { "스킬을 찾을 수 없습니다. 스킬을 사용하려면 아래에 스킬 폴더 경로 또는 URL을 추가하세요.", "settings.agentBehaviour.skillPaths": "스킬 폴더 경로", "settings.agentBehaviour.skillUrls": "스킬 URL", + "settings.agentBehaviour.removeSkill.title": "스킬 제거", + "settings.agentBehaviour.removeSkill.confirm": + '스킬 "{{name}}"을(를) 제거하시겠습니까? 디스크에서 스킬 파일이 삭제됩니다.', + "settings.agentBehaviour.removeSkill.button": "제거", "settings.agentBehaviour.instructionFiles": "추가 지시 파일", "settings.agentBehaviour.instructionFiles.description": "시스템 프롬프트에 포함되는 추가 지시 파일 경로", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 740f463b0e3..bc81bcde276 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -961,6 +961,10 @@ export const dict = { "Ingen ferdigheter funnet. Legg til ferdighetsmappestier eller URLer nedenfor for å gjøre ferdigheter tilgjengelige.", "settings.agentBehaviour.skillPaths": "Ferdighetsmappe-stier", "settings.agentBehaviour.skillUrls": "Ferdighets-URLer", + "settings.agentBehaviour.removeSkill.title": "Fjern ferdighet", + "settings.agentBehaviour.removeSkill.confirm": + 'Vil du fjerne ferdigheten "{{name}}"? Dette vil slette ferdighetsfilene fra disken.', + "settings.agentBehaviour.removeSkill.button": "Fjern", "settings.agentBehaviour.instructionFiles": "Ekstra instruksjonsfiler", "settings.agentBehaviour.instructionFiles.description": "Stier til ekstra instruksjonsfiler i systemprompten", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 508a496b792..098b89b72c3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -961,6 +961,10 @@ export const dict = { "Nie znaleziono umiejętności. Dodaj ścieżki folderów lub adresy URL poniżej, aby udostępnić umiejętności.", "settings.agentBehaviour.skillPaths": "Ścieżki folderów umiejętności", "settings.agentBehaviour.skillUrls": "Adresy URL umiejętności", + "settings.agentBehaviour.removeSkill.title": "Usuń umiejętność", + "settings.agentBehaviour.removeSkill.confirm": + 'Usunąć umiejętność "{{name}}"? Spowoduje to usunięcie plików umiejętności z dysku.', + "settings.agentBehaviour.removeSkill.button": "Usuń", "settings.agentBehaviour.instructionFiles": "Dodatkowe pliki instrukcji", "settings.agentBehaviour.instructionFiles.description": "Ścieżki do dodatkowych plików instrukcji w prompcie systemowym", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index db6d9ad9686..af44e040a58 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -964,6 +964,10 @@ export const dict = { "Навыки не обнаружены. Добавьте пути к папкам навыков или URL-адреса ниже, чтобы сделать навыки доступными.", "settings.agentBehaviour.skillPaths": "Пути папок навыков", "settings.agentBehaviour.skillUrls": "URL навыков", + "settings.agentBehaviour.removeSkill.title": "Удалить навык", + "settings.agentBehaviour.removeSkill.confirm": + 'Удалить навык "{{name}}"? Это приведет к удалению файлов навыка с диска.', + "settings.agentBehaviour.removeSkill.button": "Удалить", "settings.agentBehaviour.instructionFiles": "Дополнительные файлы инструкций", "settings.agentBehaviour.instructionFiles.description": "Пути к дополнительным файлам инструкций в системном промпте", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index 528c8eff8d7..647b93b1ee4 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -951,6 +951,10 @@ export const dict = { "settings.agentBehaviour.noSkillsFound": "ไม่พบทักษะ เพิ่มเส้นทางโฟลเดอร์หรือ URL ด้านล่างเพื่อทำให้ทักษะพร้อมใช้งาน", "settings.agentBehaviour.skillPaths": "เส้นทางโฟลเดอร์ทักษะ", "settings.agentBehaviour.skillUrls": "URL ทักษะ", + "settings.agentBehaviour.removeSkill.title": "ลบทักษะ", + "settings.agentBehaviour.removeSkill.confirm": + 'ต้องการลบทักษะ "{{name}}" หรือไม่? การดำเนินการนี้จะลบไฟล์ทักษะออกจากดิสก์', + "settings.agentBehaviour.removeSkill.button": "ลบ", "settings.agentBehaviour.instructionFiles": "ไฟล์คำสั่งเพิ่มเติม", "settings.agentBehaviour.instructionFiles.description": "เส้นทางไฟล์คำสั่งเพิ่มเติมในพรอมต์ระบบ", "settings.agentBehaviour.mcpEmpty": diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 78544fae708..694b4333c9a 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -945,6 +945,9 @@ export const dict = { "settings.agentBehaviour.noSkillsFound": "未发现任何技能。请在下方添加技能文件夹路径或 URL 以使技能可用。", "settings.agentBehaviour.skillPaths": "技能文件夹路径", "settings.agentBehaviour.skillUrls": "技能 URL", + "settings.agentBehaviour.removeSkill.title": "移除技能", + "settings.agentBehaviour.removeSkill.confirm": '移除技能 "{{name}}" 吗?这会从磁盘中删除该技能文件。', + "settings.agentBehaviour.removeSkill.button": "移除", "settings.agentBehaviour.instructionFiles": "附加指令文件", "settings.agentBehaviour.instructionFiles.description": "包含在系统提示词中的附加指令文件路径", "settings.agentBehaviour.mcpEmpty": "未配置 MCP 服务器。编辑 opencode 配置文件以添加 MCP 服务器。", diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index b8e91245c06..4e3a720f433 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -946,6 +946,9 @@ export const dict = { "settings.agentBehaviour.noSkillsFound": "未發現任何 Skill。請在下方新增 Skill 資料夾路徑或 URL 以使 Skill 可用。", "settings.agentBehaviour.skillPaths": "Skill 資料夾路徑", "settings.agentBehaviour.skillUrls": "Skill URL", + "settings.agentBehaviour.removeSkill.title": "移除技能", + "settings.agentBehaviour.removeSkill.confirm": '要移除技能 "{{name}}" 嗎?這將從磁碟中刪除該技能檔案。', + "settings.agentBehaviour.removeSkill.button": "移除", "settings.agentBehaviour.instructionFiles": "附加指令檔案", "settings.agentBehaviour.instructionFiles.description": "包含在系統提示詞中的附加指令檔案路徑", "settings.agentBehaviour.mcpEmpty": "未設定 MCP 伺服器。編輯 opencode 設定檔以新增 MCP 伺服器。", diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index e9fa87dedad..e0da4d52ec2 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -1248,6 +1248,11 @@ export interface RequestSkillsMessage { type: "requestSkills" } +export interface RemoveSkillMessage { + type: "removeSkill" + location: string +} + export interface SetLanguageRequest { type: "setLanguage" locale: string @@ -1628,6 +1633,7 @@ export type WebviewMessage = | CompactRequest | RequestAgentsMessage | RequestSkillsMessage + | RemoveSkillMessage | SetLanguageRequest | QuestionReplyRequest | QuestionRejectRequest diff --git a/packages/opencode/src/server/routes/kilocode.ts b/packages/opencode/src/server/routes/kilocode.ts new file mode 100644 index 00000000000..3edb468fbc2 --- /dev/null +++ b/packages/opencode/src/server/routes/kilocode.ts @@ -0,0 +1,42 @@ +// kilocode_change - new file +// Kilo-specific routes that live in the CLI package (direct access to internals). +// All future kilo-specific endpoints should be added here. +import { Hono } from "hono" +import { describeRoute, validator, resolver } from "hono-openapi" +import z from "zod" +import { Skill } from "../../skill/skill" +import { lazy } from "../../util/lazy" +import { errors } from "../error" + +export const KilocodeRoutes = lazy(() => + new Hono().post( + "/skill/remove", + describeRoute({ + summary: "Remove a skill", + description: "Remove a skill by deleting its directory from disk and clearing it from cache.", + operationId: "kilocode.removeSkill", + responses: { + 200: { + description: "Skill removed", + content: { + "application/json": { + schema: resolver(z.boolean()), + }, + }, + }, + ...errors(400), + }, + }), + validator( + "json", + z.object({ + location: z.string(), + }), + ), + async (c) => { + const { location } = c.req.valid("json") + await Skill.remove(location) + return c.json(true) + }, + ), +) diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index d37112823a1..9d7026dc9d4 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -47,6 +47,7 @@ import { HTTPException } from "hono/http-exception" import { errors } from "./error" import { CommitMessageRoutes } from "./routes/commit-message" import { EnhancePromptRoutes } from "./routes/enhance-prompt" // kilocode_change +import { KilocodeRoutes } from "./routes/kilocode" // kilocode_change import { QuestionRoutes } from "./routes/question" import { PermissionRoutes } from "./routes/permission" import { GlobalRoutes } from "./routes/global" @@ -268,6 +269,7 @@ export namespace Server { .route("/telemetry", TelemetryRoutes()) // kilocode_change .route("/commit-message", CommitMessageRoutes()) // kilocode_change .route("/enhance-prompt", EnhancePromptRoutes()) // kilocode_change + .route("/kilocode", KilocodeRoutes()) // kilocode_change // kilocode_change start - Kilo Gateway routes .route( "/kilo", diff --git a/packages/opencode/src/skill/skill.ts b/packages/opencode/src/skill/skill.ts index d0b4eddeb87..d4c1d97144b 100644 --- a/packages/opencode/src/skill/skill.ts +++ b/packages/opencode/src/skill/skill.ts @@ -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,27 @@ export namespace Skill { export async function dirs() { return state().then((x) => x.dirs) } + + // kilocode_change start + export const RemoveError = NamedError.create( + "SkillRemoveError", + z.object({ + location: z.string(), + message: z.string(), + }), + ) + + export async function remove(location: string) { + const resolved = path.resolve(location) + const s = await state() + const name = Object.keys(s.skills).find((k) => path.resolve(s.skills[k].location) === resolved) + if (!name) { + throw new RemoveError({ location: resolved, message: "skill not found in registry" }) + } + const dir = path.dirname(resolved) + await rm(dir, { recursive: true, force: true }) + delete s.skills[name] + s.dirs = s.dirs.filter((d) => path.resolve(d) !== dir) + } + // kilocode_change end } diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index 9104c813c2e..9fbc4210568 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -57,6 +57,8 @@ import type { KiloCloudSessionImportResponses, KiloCloudSessionsErrors, KiloCloudSessionsResponses, + KilocodeRemoveSkillErrors, + KilocodeRemoveSkillResponses, KiloFimErrors, KiloFimResponses, KiloNotificationsErrors, @@ -2928,6 +2930,47 @@ export class EnhancePrompt extends HeyApiClient { } } +export class Kilocode extends HeyApiClient { + /** + * Remove a skill + * + * Remove a skill by deleting its directory from disk and clearing it from cache. + */ + public removeSkill( + parameters?: { + directory?: string + workspace?: string + location?: string + }, + options?: Options, + ) { + const params = buildClientParams( + [parameters], + [ + { + args: [ + { in: "query", key: "directory" }, + { in: "query", key: "workspace" }, + { in: "body", key: "location" }, + ], + }, + ], + ) + return (options?.client ?? this.client).post( + { + url: "/kilocode/skill/remove", + ...options, + ...params, + headers: { + "Content-Type": "application/json", + ...options?.headers, + ...params.headers, + }, + }, + ) + } +} + export class Organization extends HeyApiClient { /** * Update Kilo Gateway organization @@ -4545,6 +4588,11 @@ export class KiloClient extends HeyApiClient { return (this._enhancePrompt ??= new EnhancePrompt({ client: this.client })) } + private _kilocode?: Kilocode + get kilocode(): Kilocode { + return (this._kilocode ??= new Kilocode({ client: this.client })) + } + private _kilo?: Kilo get kilo(): Kilo { return (this._kilo ??= new Kilo({ client: this.client })) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 5c724d3621f..fea79d1ecfa 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -4402,6 +4402,36 @@ export type EnhancePromptEnhanceResponses = { export type EnhancePromptEnhanceResponse = EnhancePromptEnhanceResponses[keyof EnhancePromptEnhanceResponses] +export type KilocodeRemoveSkillData = { + body?: { + location: string + } + path?: never + query?: { + directory?: string + workspace?: string + } + url: "/kilocode/skill/remove" +} + +export type KilocodeRemoveSkillErrors = { + /** + * Bad request + */ + 400: BadRequestError +} + +export type KilocodeRemoveSkillError = KilocodeRemoveSkillErrors[keyof KilocodeRemoveSkillErrors] + +export type KilocodeRemoveSkillResponses = { + /** + * Skill removed + */ + 200: boolean +} + +export type KilocodeRemoveSkillResponse = KilocodeRemoveSkillResponses[keyof KilocodeRemoveSkillResponses] + export type KiloProfileData = { body?: never path?: never diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 45dd0752210..5c04569c5f1 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -5372,6 +5372,72 @@ ] } }, + "/kilocode/skill/remove": { + "post": { + "operationId": "kilocode.removeSkill", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "workspace", + "schema": { + "type": "string" + } + } + ], + "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" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "location": { + "type": "string" + } + }, + "required": ["location"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createKiloClient } from \"@kilocode/sdk\n\nconst client = createKiloClient()\nawait client.kilocode.removeSkill({\n ...\n})" + } + ] + } + }, "/kilo/profile": { "get": { "operationId": "kilo.profile",