From 3da18dee40605d954d8ad63a50090f6002cd7b0c Mon Sep 17 00:00:00 2001 From: Mark IJbema Date: Mon, 16 Mar 2026 10:50:28 +0100 Subject: [PATCH] refactor: move skills state to session context with refreshSkills/removeSkill Move discoveredSkills signal from AgentBehaviourTab into the session context so any component can access session.skills(), session.refreshSkills(), and session.removeSkill(location). removeSkill optimistically removes the skill from the UI signal before sending the message to the extension, so the screen updates immediately. --- .../components/settings/AgentBehaviourTab.tsx | 31 +++++-------------- .../webview-ui/src/context/session.tsx | 29 +++++++++++++++++ 2 files changed, 36 insertions(+), 24 deletions(-) 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 3b0d278b92e..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,4 +1,4 @@ -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" @@ -10,8 +10,7 @@ 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" @@ -54,31 +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 @@ -182,10 +170,6 @@ const AgentBehaviourTab: Component = () => { updateConfig({ skills: { ...config().skills, urls: current } }) } - const removeSkill = (skill: SkillInfo) => { - vscode.postMessage({ type: "removeSkill", location: skill.location }) - } - const confirmRemoveSkill = (skill: SkillInfo) => { dialog.show(() => ( @@ -199,7 +183,7 @@ const AgentBehaviourTab: Component = () => { variant="primary" size="large" onClick={() => { - removeSkill(skill) + session.removeSkill(skill.location) dialog.close() }} > @@ -430,7 +414,7 @@ const AgentBehaviourTab: Component = () => { {language.t("settings.agentBehaviour.discoveredSkills")} 0} + when={session.skills().length > 0} fallback={
{language.t("settings.agentBehaviour.noSkillsFound")}
@@ -438,7 +422,7 @@ const AgentBehaviourTab: Component = () => { } > - + {(skill, index) => (
{ "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", }} >
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(),