mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #7070 from Kilo-Org/mark/add-skill-removal
feat: add ability to remove discovered skills
This commit is contained in:
@@ -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<void> {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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<SubtabId>("agents")
|
||||
const [selectedAgent, setSelectedAgent] = createSignal<string>("")
|
||||
const [newSkillPath, setNewSkillPath] = createSignal("")
|
||||
const [newSkillUrl, setNewSkillUrl] = createSignal("")
|
||||
const [newInstruction, setNewInstruction] = createSignal("")
|
||||
const [discoveredSkills, setDiscoveredSkills] = createSignal<SkillInfo[]>([])
|
||||
|
||||
// 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(() => (
|
||||
<Dialog title={language.t("settings.agentBehaviour.removeSkill.title")} fit>
|
||||
<div class="dialog-confirm-body">
|
||||
<span>{language.t("settings.agentBehaviour.removeSkill.confirm", { name: skill.name })}</span>
|
||||
<div class="dialog-confirm-actions">
|
||||
<Button variant="ghost" size="large" onClick={() => dialog.close()}>
|
||||
{language.t("common.cancel")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="large"
|
||||
onClick={() => {
|
||||
session.removeSkill(skill.location)
|
||||
dialog.close()
|
||||
}}
|
||||
>
|
||||
{language.t("settings.agentBehaviour.removeSkill.button")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
))
|
||||
}
|
||||
|
||||
const renderAgentsSubtab = () => (
|
||||
<div>
|
||||
{/* Default agent */}
|
||||
@@ -398,7 +414,7 @@ const AgentBehaviourTab: Component = () => {
|
||||
{language.t("settings.agentBehaviour.discoveredSkills")}
|
||||
</h4>
|
||||
<Show
|
||||
when={discoveredSkills().length > 0}
|
||||
when={session.skills().length > 0}
|
||||
fallback={
|
||||
<Card style={{ "margin-bottom": "16px" }}>
|
||||
<div data-slot="settings-row-label-subtitle">{language.t("settings.agentBehaviour.noSkillsFound")}</div>
|
||||
@@ -406,28 +422,33 @@ const AgentBehaviourTab: Component = () => {
|
||||
}
|
||||
>
|
||||
<Card style={{ "margin-bottom": "16px" }}>
|
||||
<For each={discoveredSkills()}>
|
||||
<For each={session.skills()}>
|
||||
{(skill, index) => (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
"align-items": "center",
|
||||
"justify-content": "space-between",
|
||||
padding: "8px 0",
|
||||
"border-bottom":
|
||||
index() < discoveredSkills().length - 1 ? "1px solid var(--border-weak-base)" : "none",
|
||||
"border-bottom": index() < session.skills().length - 1 ? "1px solid var(--border-weak-base)" : "none",
|
||||
}}
|
||||
>
|
||||
<div data-slot="settings-row-label-title" style={{ "margin-bottom": "0" }}>
|
||||
{skill.name}
|
||||
</div>
|
||||
<div
|
||||
data-slot="settings-row-label-subtitle"
|
||||
style={{
|
||||
"margin-top": "4px",
|
||||
"font-family": "var(--vscode-editor-font-family, monospace)",
|
||||
}}
|
||||
>
|
||||
<div>{skill.description}</div>
|
||||
<div>{skill.location}</div>
|
||||
<div style={{ flex: 1, "min-width": 0 }}>
|
||||
<div data-slot="settings-row-label-title" style={{ "margin-bottom": "0" }}>
|
||||
{skill.name}
|
||||
</div>
|
||||
<div
|
||||
data-slot="settings-row-label-subtitle"
|
||||
style={{
|
||||
"margin-top": "4px",
|
||||
"font-family": "var(--vscode-editor-font-family, monospace)",
|
||||
}}
|
||||
>
|
||||
<div>{skill.description}</div>
|
||||
<div>{skill.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
<IconButton size="small" variant="ghost" icon="close" onClick={() => confirmRemoveSkill(skill)} />
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
|
||||
@@ -36,6 +36,7 @@ import type {
|
||||
ModelSelection,
|
||||
ContextUsage,
|
||||
AgentInfo,
|
||||
SkillInfo,
|
||||
ExtensionMessage,
|
||||
FileAttachment,
|
||||
SendMessageFailedMessage,
|
||||
@@ -114,6 +115,11 @@ interface SessionContextValue {
|
||||
totalCost: Accessor<number>
|
||||
contextUsage: Accessor<ContextUsage | undefined>
|
||||
|
||||
// Skills loaded from the CLI backend
|
||||
skills: Accessor<SkillInfo[]>
|
||||
refreshSkills: () => void
|
||||
removeSkill: (location: string) => void
|
||||
|
||||
// Agent/mode selection (per-session)
|
||||
agents: Accessor<AgentInfo[]>
|
||||
selectedAgent: Accessor<string>
|
||||
@@ -204,6 +210,9 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
const [agents, setAgents] = createSignal<AgentInfo[]>([])
|
||||
const [defaultAgent, setDefaultAgent] = createSignal("code")
|
||||
|
||||
// Skills loaded from the CLI backend
|
||||
const [skills, setSkills] = createSignal<SkillInfo[]>([])
|
||||
|
||||
// Pending agent selection for before a session exists
|
||||
const [pendingAgentSelection, setPendingAgentSelection] = createSignal<string | null>(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(),
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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 服务器。",
|
||||
|
||||
@@ -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 伺服器。",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<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: "body", key: "location" },
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
return (options?.client ?? this.client).post<KilocodeRemoveSkillResponses, KilocodeRemoveSkillErrors, ThrowOnError>(
|
||||
{
|
||||
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 }))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user