mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #7133 from Kilo-Org/mark/marketplace-full-implementation
feat(marketplace): add MCP servers and modes tabs
This commit is contained in:
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "المهارات",
|
||||
"marketplace.tab.mcpServers": "خوادم MCP",
|
||||
"marketplace.tab.modes": "الأوضاع",
|
||||
"marketplace.search.skills": "البحث في المهارات...",
|
||||
"marketplace.category.all": "الكل",
|
||||
"marketplace.empty.skills": "لم يتم العثور على مهارات",
|
||||
"marketplace.placeholder": "سيتم تنفيذه لاحقاً",
|
||||
"marketplace.card.installed": "مثبت",
|
||||
"marketplace.card.install": "تثبيت",
|
||||
"marketplace.card.remove": "إزالة",
|
||||
"marketplace.card.removeScope": "إزالة ({{scope}})",
|
||||
"marketplace.card.showMore": "عرض المزيد",
|
||||
"marketplace.card.showLess": "عرض أقل",
|
||||
"marketplace.install.title": "تثبيت {{name}}",
|
||||
"marketplace.install.scope": "النطاق",
|
||||
"marketplace.install.scope.project": "المشروع",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"هل أنت متأكد أنك تريد إزالة هذا الـ {{type}}؟ سيؤدي هذا إلى إزالته من تكوين {{scope}} الخاص بك.",
|
||||
"marketplace.remove.cancel": "إلغاء",
|
||||
"marketplace.remove.confirm.button": "إزالة",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "بحث...",
|
||||
"marketplace.filter.all": "جميع العناصر",
|
||||
"marketplace.filter.notInstalled": "غير مثبت",
|
||||
"marketplace.empty": "لم يتم العثور على عناصر",
|
||||
"marketplace.badge.mcpServer": "خادم MCP",
|
||||
"marketplace.badge.mode": "وضع",
|
||||
"marketplace.card.by": "بواسطة {{author}}",
|
||||
"marketplace.install.method": "طريقة التثبيت",
|
||||
"marketplace.install.parameters": "المعلمات",
|
||||
"marketplace.install.optional": "(اختياري)",
|
||||
"marketplace.install.required": "{{name}} مطلوب",
|
||||
"marketplace.scope.project": "مشروع",
|
||||
"marketplace.scope.global": "عام",
|
||||
"marketplace.remove.type.mcp": "خادم MCP",
|
||||
"marketplace.remove.type.skill": "مهارة",
|
||||
"marketplace.remove.type.mode": "وضع",
|
||||
"marketplace.remove.failed": "فشلت إزالة {{name}}",
|
||||
"marketplace.install": "تثبيت",
|
||||
"marketplace.filter.installed": "مثبت",
|
||||
"marketplace.error.dismiss": "تجاهل",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "Servidores MCP",
|
||||
"marketplace.tab.modes": "Modos",
|
||||
"marketplace.search.skills": "Buscar skills...",
|
||||
"marketplace.category.all": "Todos",
|
||||
"marketplace.empty.skills": "Nenhuma skill encontrada",
|
||||
"marketplace.placeholder": "A ser implementado",
|
||||
"marketplace.card.installed": "Instalado",
|
||||
"marketplace.card.install": "Instalar",
|
||||
"marketplace.card.remove": "Remover",
|
||||
"marketplace.card.removeScope": "Remover ({{scope}})",
|
||||
"marketplace.card.showMore": "Mostrar mais",
|
||||
"marketplace.card.showLess": "Mostrar menos",
|
||||
"marketplace.install.title": "Instalar {{name}}",
|
||||
"marketplace.install.scope": "Escopo",
|
||||
"marketplace.install.scope.project": "Projeto",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Tem certeza que deseja remover este {{type}}? Isso o removerá da sua configuração {{scope}}.",
|
||||
"marketplace.remove.cancel": "Cancelar",
|
||||
"marketplace.remove.confirm.button": "Remover",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Pesquisar...",
|
||||
"marketplace.filter.all": "Todos os Itens",
|
||||
"marketplace.filter.notInstalled": "Não Instalado",
|
||||
"marketplace.empty": "Nenhum item encontrado",
|
||||
"marketplace.badge.mcpServer": "Servidor MCP",
|
||||
"marketplace.badge.mode": "Modo",
|
||||
"marketplace.card.by": "por {{author}}",
|
||||
"marketplace.install.method": "Método de Instalação",
|
||||
"marketplace.install.parameters": "Parâmetros",
|
||||
"marketplace.install.optional": "(opcional)",
|
||||
"marketplace.install.required": "{{name}} é obrigatório",
|
||||
"marketplace.scope.project": "projeto",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "servidor MCP",
|
||||
"marketplace.remove.type.skill": "habilidade",
|
||||
"marketplace.remove.type.mode": "modo",
|
||||
"marketplace.remove.failed": "Falha ao remover {{name}}",
|
||||
"marketplace.install": "Instalar",
|
||||
"marketplace.filter.installed": "Instalado",
|
||||
"marketplace.error.dismiss": "Dispensar",
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Vještine",
|
||||
"marketplace.tab.mcpServers": "MCP Serveri",
|
||||
"marketplace.tab.modes": "Modovi",
|
||||
"marketplace.search.skills": "Pretraži vještine...",
|
||||
"marketplace.category.all": "Sve",
|
||||
"marketplace.empty.skills": "Nema pronađenih vještina",
|
||||
"marketplace.placeholder": "Biće implementirano",
|
||||
"marketplace.card.installed": "Instalirano",
|
||||
"marketplace.card.install": "Instaliraj",
|
||||
"marketplace.card.remove": "Ukloni",
|
||||
"marketplace.card.removeScope": "Ukloni ({{scope}})",
|
||||
"marketplace.card.showMore": "Prikaži više",
|
||||
"marketplace.card.showLess": "Prikaži manje",
|
||||
"marketplace.install.title": "Instaliraj {{name}}",
|
||||
"marketplace.install.scope": "Opseg",
|
||||
"marketplace.install.scope.project": "Projekat",
|
||||
@@ -48,4 +48,25 @@ export const dict = {
|
||||
"Jeste li sigurni da želite ukloniti ovaj {{type}}? Ovo će ga ukloniti iz vaše {{scope}} konfiguracije.",
|
||||
"marketplace.remove.cancel": "Otkaži",
|
||||
"marketplace.remove.confirm.button": "Ukloni",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Pretraži...",
|
||||
"marketplace.filter.all": "Sve stavke",
|
||||
"marketplace.filter.notInstalled": "Nije instalirano",
|
||||
"marketplace.empty": "Nema pronađenih stavki",
|
||||
"marketplace.badge.mcpServer": "MCP Server",
|
||||
"marketplace.badge.mode": "Režim",
|
||||
"marketplace.card.by": "od {{author}}",
|
||||
"marketplace.install.method": "Metoda instalacije",
|
||||
"marketplace.install.parameters": "Parametri",
|
||||
"marketplace.install.optional": "(opciono)",
|
||||
"marketplace.install.required": "{{name}} je obavezno",
|
||||
"marketplace.scope.project": "projekat",
|
||||
"marketplace.scope.global": "globalno",
|
||||
"marketplace.remove.type.mcp": "MCP server",
|
||||
"marketplace.remove.type.skill": "vještina",
|
||||
"marketplace.remove.type.mode": "režim",
|
||||
"marketplace.remove.failed": "Uklanjanje {{name}} nije uspjelo",
|
||||
"marketplace.install": "Instaliraj",
|
||||
"marketplace.filter.installed": "Instalirano",
|
||||
"marketplace.error.dismiss": "Odbaci",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "MCP-servere",
|
||||
"marketplace.tab.modes": "Tilstande",
|
||||
"marketplace.search.skills": "Søg efter skills...",
|
||||
"marketplace.category.all": "Alle",
|
||||
"marketplace.empty.skills": "Ingen skills fundet",
|
||||
"marketplace.placeholder": "Skal implementeres",
|
||||
"marketplace.card.installed": "Installeret",
|
||||
"marketplace.card.install": "Installer",
|
||||
"marketplace.card.remove": "Fjern",
|
||||
"marketplace.card.removeScope": "Fjern ({{scope}})",
|
||||
"marketplace.card.showMore": "Vis mere",
|
||||
"marketplace.card.showLess": "Vis mindre",
|
||||
"marketplace.install.title": "Installer {{name}}",
|
||||
"marketplace.install.scope": "Omfang",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Er du sikker på, at du vil fjerne denne {{type}}? Dette vil fjerne den fra din {{scope}} konfiguration.",
|
||||
"marketplace.remove.cancel": "Annuller",
|
||||
"marketplace.remove.confirm.button": "Fjern",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Søg...",
|
||||
"marketplace.filter.all": "Alle elementer",
|
||||
"marketplace.filter.notInstalled": "Ikke installeret",
|
||||
"marketplace.empty": "Ingen elementer fundet",
|
||||
"marketplace.badge.mcpServer": "MCP-server",
|
||||
"marketplace.badge.mode": "Tilstand",
|
||||
"marketplace.card.by": "af {{author}}",
|
||||
"marketplace.install.method": "Installationsmetode",
|
||||
"marketplace.install.parameters": "Parametre",
|
||||
"marketplace.install.optional": "(valgfrit)",
|
||||
"marketplace.install.required": "{{name}} er påkrævet",
|
||||
"marketplace.scope.project": "projekt",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "MCP-server",
|
||||
"marketplace.remove.type.skill": "færdighed",
|
||||
"marketplace.remove.type.mode": "tilstand",
|
||||
"marketplace.remove.failed": "Kunne ikke fjerne {{name}}",
|
||||
"marketplace.install": "Installer",
|
||||
"marketplace.filter.installed": "Installeret",
|
||||
"marketplace.error.dismiss": "Afvis",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "MCP-Server",
|
||||
"marketplace.tab.modes": "Modi",
|
||||
"marketplace.search.skills": "Skills suchen...",
|
||||
"marketplace.category.all": "Alle",
|
||||
"marketplace.empty.skills": "Keine Skills gefunden",
|
||||
"marketplace.placeholder": "Noch nicht implementiert",
|
||||
"marketplace.card.installed": "Installiert",
|
||||
"marketplace.card.install": "Installieren",
|
||||
"marketplace.card.remove": "Entfernen",
|
||||
"marketplace.card.removeScope": "Entfernen ({{scope}})",
|
||||
"marketplace.card.showMore": "Mehr anzeigen",
|
||||
"marketplace.card.showLess": "Weniger anzeigen",
|
||||
"marketplace.install.title": "{{name}} installieren",
|
||||
"marketplace.install.scope": "Bereich",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Sind Sie sicher, dass Sie diese {{type}} entfernen möchten? Dadurch wird sie aus Ihrer {{scope}}-Konfiguration entfernt.",
|
||||
"marketplace.remove.cancel": "Abbrechen",
|
||||
"marketplace.remove.confirm.button": "Entfernen",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Suchen...",
|
||||
"marketplace.filter.all": "Alle Elemente",
|
||||
"marketplace.filter.notInstalled": "Nicht installiert",
|
||||
"marketplace.empty": "Keine Elemente gefunden",
|
||||
"marketplace.badge.mcpServer": "MCP-Server",
|
||||
"marketplace.badge.mode": "Modus",
|
||||
"marketplace.card.by": "von {{author}}",
|
||||
"marketplace.install.method": "Installationsmethode",
|
||||
"marketplace.install.parameters": "Parameter",
|
||||
"marketplace.install.optional": "(optional)",
|
||||
"marketplace.install.required": "{{name}} ist erforderlich",
|
||||
"marketplace.scope.project": "Projekt",
|
||||
"marketplace.scope.global": "Global",
|
||||
"marketplace.remove.type.mcp": "MCP-Server",
|
||||
"marketplace.remove.type.skill": "Skill",
|
||||
"marketplace.remove.type.mode": "Modus",
|
||||
"marketplace.remove.failed": "Fehler beim Entfernen von {{name}}",
|
||||
"marketplace.install": "Installieren",
|
||||
"marketplace.filter.installed": "Installiert",
|
||||
"marketplace.error.dismiss": "Verwerfen",
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "MCP Servers",
|
||||
"marketplace.tab.modes": "Modes",
|
||||
"marketplace.search.skills": "Search skills...",
|
||||
"marketplace.category.all": "All",
|
||||
"marketplace.empty.skills": "No skills found",
|
||||
"marketplace.placeholder": "To be implemented",
|
||||
"marketplace.card.installed": "Installed",
|
||||
"marketplace.card.install": "Install",
|
||||
"marketplace.card.remove": "Remove",
|
||||
"marketplace.card.removeScope": "Remove ({{scope}})",
|
||||
"marketplace.card.showMore": "Show more",
|
||||
"marketplace.card.showLess": "Show less",
|
||||
"marketplace.install.title": "Install {{name}}",
|
||||
"marketplace.install.scope": "Scope",
|
||||
"marketplace.install.scope.project": "Project",
|
||||
@@ -45,4 +45,25 @@ export const dict = {
|
||||
"Are you sure you want to remove this {{type}}? This will remove it from your {{scope}} configuration.",
|
||||
"marketplace.remove.cancel": "Cancel",
|
||||
"marketplace.remove.confirm.button": "Remove",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Search...",
|
||||
"marketplace.filter.all": "All Items",
|
||||
"marketplace.filter.notInstalled": "Not Installed",
|
||||
"marketplace.empty": "No items found",
|
||||
"marketplace.badge.mcpServer": "MCP Server",
|
||||
"marketplace.badge.mode": "Mode",
|
||||
"marketplace.card.by": "by {{author}}",
|
||||
"marketplace.install.method": "Installation Method",
|
||||
"marketplace.install.parameters": "Parameters",
|
||||
"marketplace.install.optional": "(optional)",
|
||||
"marketplace.install.required": "{{name}} is required",
|
||||
"marketplace.scope.project": "project",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "MCP server",
|
||||
"marketplace.remove.type.skill": "skill",
|
||||
"marketplace.remove.type.mode": "mode",
|
||||
"marketplace.remove.failed": "Failed to remove {{name}}",
|
||||
"marketplace.install": "Install",
|
||||
"marketplace.filter.installed": "Installed",
|
||||
"marketplace.error.dismiss": "Dismiss",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "Servidores MCP",
|
||||
"marketplace.tab.modes": "Modos",
|
||||
"marketplace.search.skills": "Buscar skills...",
|
||||
"marketplace.category.all": "Todos",
|
||||
"marketplace.empty.skills": "No se encontraron skills",
|
||||
"marketplace.placeholder": "Por implementar",
|
||||
"marketplace.card.installed": "Instalado",
|
||||
"marketplace.card.install": "Instalar",
|
||||
"marketplace.card.remove": "Eliminar",
|
||||
"marketplace.card.removeScope": "Eliminar ({{scope}})",
|
||||
"marketplace.card.showMore": "Mostrar más",
|
||||
"marketplace.card.showLess": "Mostrar menos",
|
||||
"marketplace.install.title": "Instalar {{name}}",
|
||||
"marketplace.install.scope": "Alcance",
|
||||
"marketplace.install.scope.project": "Proyecto",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"¿Estás seguro de que deseas eliminar este {{type}}? Esto lo eliminará de tu configuración {{scope}}.",
|
||||
"marketplace.remove.cancel": "Cancelar",
|
||||
"marketplace.remove.confirm.button": "Eliminar",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Buscar...",
|
||||
"marketplace.filter.all": "Todos los elementos",
|
||||
"marketplace.filter.notInstalled": "No instalado",
|
||||
"marketplace.empty": "No se encontraron elementos",
|
||||
"marketplace.badge.mcpServer": "Servidor MCP",
|
||||
"marketplace.badge.mode": "Modo",
|
||||
"marketplace.card.by": "por {{author}}",
|
||||
"marketplace.install.method": "Método de instalación",
|
||||
"marketplace.install.parameters": "Parámetros",
|
||||
"marketplace.install.optional": "(opcional)",
|
||||
"marketplace.install.required": "{{name}} es obligatorio",
|
||||
"marketplace.scope.project": "proyecto",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "servidor MCP",
|
||||
"marketplace.remove.type.skill": "habilidad",
|
||||
"marketplace.remove.type.mode": "modo",
|
||||
"marketplace.remove.failed": "Error al eliminar {{name}}",
|
||||
"marketplace.install": "Instalar",
|
||||
"marketplace.filter.installed": "Instalado",
|
||||
"marketplace.error.dismiss": "Descartar",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "Serveurs MCP",
|
||||
"marketplace.tab.modes": "Modes",
|
||||
"marketplace.search.skills": "Rechercher des skills...",
|
||||
"marketplace.category.all": "Tout",
|
||||
"marketplace.empty.skills": "Aucune skill trouvée",
|
||||
"marketplace.placeholder": "À implémenter",
|
||||
"marketplace.card.installed": "Installé",
|
||||
"marketplace.card.install": "Installer",
|
||||
"marketplace.card.remove": "Supprimer",
|
||||
"marketplace.card.removeScope": "Supprimer ({{scope}})",
|
||||
"marketplace.card.showMore": "Afficher plus",
|
||||
"marketplace.card.showLess": "Afficher moins",
|
||||
"marketplace.install.title": "Installer {{name}}",
|
||||
"marketplace.install.scope": "Portée",
|
||||
"marketplace.install.scope.project": "Projet",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Êtes-vous sûr de vouloir supprimer ce {{type}} ? Cela le supprimera de votre configuration {{scope}}.",
|
||||
"marketplace.remove.cancel": "Annuler",
|
||||
"marketplace.remove.confirm.button": "Supprimer",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Rechercher...",
|
||||
"marketplace.filter.all": "Tous les éléments",
|
||||
"marketplace.filter.notInstalled": "Non installé",
|
||||
"marketplace.empty": "Aucun élément trouvé",
|
||||
"marketplace.badge.mcpServer": "Serveur MCP",
|
||||
"marketplace.badge.mode": "Mode",
|
||||
"marketplace.card.by": "par {{author}}",
|
||||
"marketplace.install.method": "Méthode d'installation",
|
||||
"marketplace.install.parameters": "Paramètres",
|
||||
"marketplace.install.optional": "(facultatif)",
|
||||
"marketplace.install.required": "{{name}} est requis",
|
||||
"marketplace.scope.project": "projet",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "serveur MCP",
|
||||
"marketplace.remove.type.skill": "compétence",
|
||||
"marketplace.remove.type.mode": "mode",
|
||||
"marketplace.remove.failed": "Échec de la suppression de {{name}}",
|
||||
"marketplace.install": "Installer",
|
||||
"marketplace.filter.installed": "Installé",
|
||||
"marketplace.error.dismiss": "Ignorer",
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "スキル",
|
||||
"marketplace.tab.mcpServers": "MCPサーバー",
|
||||
"marketplace.tab.modes": "モード",
|
||||
"marketplace.search.skills": "スキルを検索...",
|
||||
"marketplace.category.all": "すべて",
|
||||
"marketplace.empty.skills": "スキルが見つかりません",
|
||||
"marketplace.placeholder": "未実装",
|
||||
"marketplace.card.installed": "インストール済み",
|
||||
"marketplace.card.install": "インストール",
|
||||
"marketplace.card.remove": "削除",
|
||||
"marketplace.card.removeScope": "削除 ({{scope}})",
|
||||
"marketplace.card.showMore": "もっと見る",
|
||||
"marketplace.card.showLess": "折りたたむ",
|
||||
"marketplace.install.title": "{{name}} のインストール",
|
||||
"marketplace.install.scope": "スコープ",
|
||||
"marketplace.install.scope.project": "プロジェクト",
|
||||
@@ -41,4 +41,25 @@ export const dict = {
|
||||
"marketplace.remove.confirm": "この{{type}}を削除してもよろしいですか? これにより、{{scope}}設定から削除されます。",
|
||||
"marketplace.remove.cancel": "キャンセル",
|
||||
"marketplace.remove.confirm.button": "削除",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "検索...",
|
||||
"marketplace.filter.all": "すべてのアイテム",
|
||||
"marketplace.filter.notInstalled": "未インストール",
|
||||
"marketplace.empty": "アイテムが見つかりません",
|
||||
"marketplace.badge.mcpServer": "MCPサーバー",
|
||||
"marketplace.badge.mode": "モード",
|
||||
"marketplace.card.by": "作成者: {{author}}",
|
||||
"marketplace.install.method": "インストール方法",
|
||||
"marketplace.install.parameters": "パラメーター",
|
||||
"marketplace.install.optional": "(任意)",
|
||||
"marketplace.install.required": "{{name}} は必須です",
|
||||
"marketplace.scope.project": "プロジェクト",
|
||||
"marketplace.scope.global": "グローバル",
|
||||
"marketplace.remove.type.mcp": "MCPサーバー",
|
||||
"marketplace.remove.type.skill": "スキル",
|
||||
"marketplace.remove.type.mode": "モード",
|
||||
"marketplace.remove.failed": "{{name}} の削除に失敗しました",
|
||||
"marketplace.install": "インストール",
|
||||
"marketplace.filter.installed": "インストール済み",
|
||||
"marketplace.error.dismiss": "閉じる",
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "스킬",
|
||||
"marketplace.tab.mcpServers": "MCP 서버",
|
||||
"marketplace.tab.modes": "모드",
|
||||
"marketplace.search.skills": "스킬 검색...",
|
||||
"marketplace.category.all": "전체",
|
||||
"marketplace.empty.skills": "스킬을 찾을 수 없습니다",
|
||||
"marketplace.placeholder": "구현 예정",
|
||||
"marketplace.card.installed": "설치됨",
|
||||
"marketplace.card.install": "설치",
|
||||
"marketplace.card.remove": "제거",
|
||||
"marketplace.card.removeScope": "제거 ({{scope}})",
|
||||
"marketplace.card.showMore": "더 보기",
|
||||
"marketplace.card.showLess": "접기",
|
||||
"marketplace.install.title": "{{name}} 설치",
|
||||
"marketplace.install.scope": "범위",
|
||||
"marketplace.install.scope.project": "프로젝트",
|
||||
@@ -41,4 +41,25 @@ export const dict = {
|
||||
"marketplace.remove.confirm": "이 {{type}}을(를) 제거하시겠습니까? {{scope}} 구성에서 제거됩니다.",
|
||||
"marketplace.remove.cancel": "취소",
|
||||
"marketplace.remove.confirm.button": "제거",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "검색...",
|
||||
"marketplace.filter.all": "모든 항목",
|
||||
"marketplace.filter.notInstalled": "설치되지 않음",
|
||||
"marketplace.empty": "항목을 찾을 수 없음",
|
||||
"marketplace.badge.mcpServer": "MCP 서버",
|
||||
"marketplace.badge.mode": "모드",
|
||||
"marketplace.card.by": "제작: {{author}}",
|
||||
"marketplace.install.method": "설치 방법",
|
||||
"marketplace.install.parameters": "매개변수",
|
||||
"marketplace.install.optional": "(선택 사항)",
|
||||
"marketplace.install.required": "{{name}}이(가) 필요합니다",
|
||||
"marketplace.scope.project": "프로젝트",
|
||||
"marketplace.scope.global": "글로벌",
|
||||
"marketplace.remove.type.mcp": "MCP 서버",
|
||||
"marketplace.remove.type.skill": "스킬",
|
||||
"marketplace.remove.type.mode": "모드",
|
||||
"marketplace.remove.failed": "{{name}} 제거 실패",
|
||||
"marketplace.install": "설치",
|
||||
"marketplace.filter.installed": "설치됨",
|
||||
"marketplace.error.dismiss": "닫기",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "MCP-servere",
|
||||
"marketplace.tab.modes": "Moduser",
|
||||
"marketplace.search.skills": "Søk etter skills...",
|
||||
"marketplace.category.all": "Alle",
|
||||
"marketplace.empty.skills": "Ingen skills funnet",
|
||||
"marketplace.placeholder": "Skal implementeres",
|
||||
"marketplace.card.installed": "Installert",
|
||||
"marketplace.card.install": "Installer",
|
||||
"marketplace.card.remove": "Fjern",
|
||||
"marketplace.card.removeScope": "Fjern ({{scope}})",
|
||||
"marketplace.card.showMore": "Vis mer",
|
||||
"marketplace.card.showLess": "Vis mindre",
|
||||
"marketplace.install.title": "Installer {{name}}",
|
||||
"marketplace.install.scope": "Omfang",
|
||||
"marketplace.install.scope.project": "Prosjekt",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Er du sikker på at du vil fjerne denne {{type}}? Dette vil fjerne den fra din {{scope}}-konfigurasjon.",
|
||||
"marketplace.remove.cancel": "Avbryt",
|
||||
"marketplace.remove.confirm.button": "Fjern",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Søk...",
|
||||
"marketplace.filter.all": "Alle elementer",
|
||||
"marketplace.filter.notInstalled": "Ikke installert",
|
||||
"marketplace.empty": "Ingen elementer funnet",
|
||||
"marketplace.badge.mcpServer": "MCP-server",
|
||||
"marketplace.badge.mode": "Modus",
|
||||
"marketplace.card.by": "av {{author}}",
|
||||
"marketplace.install.method": "Installasjonsmetode",
|
||||
"marketplace.install.parameters": "Parametere",
|
||||
"marketplace.install.optional": "(valgfritt)",
|
||||
"marketplace.install.required": "{{name}} er påkrevd",
|
||||
"marketplace.scope.project": "prosjekt",
|
||||
"marketplace.scope.global": "global",
|
||||
"marketplace.remove.type.mcp": "MCP-server",
|
||||
"marketplace.remove.type.skill": "ferdighet",
|
||||
"marketplace.remove.type.mode": "modus",
|
||||
"marketplace.remove.failed": "Kunne ikke fjerne {{name}}",
|
||||
"marketplace.install": "Installer",
|
||||
"marketplace.filter.installed": "Installert",
|
||||
"marketplace.error.dismiss": "Avvis",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Skills",
|
||||
"marketplace.tab.mcpServers": "Serwery MCP",
|
||||
"marketplace.tab.modes": "Tryby",
|
||||
"marketplace.search.skills": "Szukaj skills...",
|
||||
"marketplace.category.all": "Wszystkie",
|
||||
"marketplace.empty.skills": "Nie znaleziono skills",
|
||||
"marketplace.placeholder": "Do zaimplementowania",
|
||||
"marketplace.card.installed": "Zainstalowano",
|
||||
"marketplace.card.install": "Zainstaluj",
|
||||
"marketplace.card.remove": "Usuń",
|
||||
"marketplace.card.removeScope": "Usuń ({{scope}})",
|
||||
"marketplace.card.showMore": "Pokaż więcej",
|
||||
"marketplace.card.showLess": "Pokaż mniej",
|
||||
"marketplace.install.title": "Instalacja: {{name}}",
|
||||
"marketplace.install.scope": "Zakres",
|
||||
"marketplace.install.scope.project": "Projekt",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Czy na pewno chcesz usunąć ten {{type}}? Spowoduje to usunięcie z konfiguracji: {{scope}}.",
|
||||
"marketplace.remove.cancel": "Anuluj",
|
||||
"marketplace.remove.confirm.button": "Usuń",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Szukaj...",
|
||||
"marketplace.filter.all": "Wszystkie elementy",
|
||||
"marketplace.filter.notInstalled": "Nie zainstalowano",
|
||||
"marketplace.empty": "Nie znaleziono elementów",
|
||||
"marketplace.badge.mcpServer": "Serwer MCP",
|
||||
"marketplace.badge.mode": "Tryb",
|
||||
"marketplace.card.by": "autor: {{author}}",
|
||||
"marketplace.install.method": "Metoda instalacji",
|
||||
"marketplace.install.parameters": "Parametry",
|
||||
"marketplace.install.optional": "(opcjonalne)",
|
||||
"marketplace.install.required": "{{name}} jest wymagane",
|
||||
"marketplace.scope.project": "projekt",
|
||||
"marketplace.scope.global": "globalny",
|
||||
"marketplace.remove.type.mcp": "serwer MCP",
|
||||
"marketplace.remove.type.skill": "umiejętność",
|
||||
"marketplace.remove.type.mode": "tryb",
|
||||
"marketplace.remove.failed": "Nie udało się usunąć {{name}}",
|
||||
"marketplace.install": "Zainstaluj",
|
||||
"marketplace.filter.installed": "Zainstalowano",
|
||||
"marketplace.error.dismiss": "Odrzuć",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "Навыки",
|
||||
"marketplace.tab.mcpServers": "MCP-серверы",
|
||||
"marketplace.tab.modes": "Режимы",
|
||||
"marketplace.search.skills": "Поиск навыков...",
|
||||
"marketplace.category.all": "Все",
|
||||
"marketplace.empty.skills": "Навыки не найдены",
|
||||
"marketplace.placeholder": "Будет реализовано",
|
||||
"marketplace.card.installed": "Установлено",
|
||||
"marketplace.card.install": "Установить",
|
||||
"marketplace.card.remove": "Удалить",
|
||||
"marketplace.card.removeScope": "Удалить ({{scope}})",
|
||||
"marketplace.card.showMore": "Показать больше",
|
||||
"marketplace.card.showLess": "Показать меньше",
|
||||
"marketplace.install.title": "Установка {{name}}",
|
||||
"marketplace.install.scope": "Область",
|
||||
"marketplace.install.scope.project": "Проект",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"Вы уверены, что хотите удалить этот {{type}}? Это удалит его из вашей конфигурации ({{scope}}).",
|
||||
"marketplace.remove.cancel": "Отмена",
|
||||
"marketplace.remove.confirm.button": "Удалить",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Поиск...",
|
||||
"marketplace.filter.all": "Все элементы",
|
||||
"marketplace.filter.notInstalled": "Не установлено",
|
||||
"marketplace.empty": "Элементы не найдены",
|
||||
"marketplace.badge.mcpServer": "MCP-сервер",
|
||||
"marketplace.badge.mode": "Режим",
|
||||
"marketplace.card.by": "от {{author}}",
|
||||
"marketplace.install.method": "Способ установки",
|
||||
"marketplace.install.parameters": "Параметры",
|
||||
"marketplace.install.optional": "(необязательно)",
|
||||
"marketplace.install.required": "Требуется {{name}}",
|
||||
"marketplace.scope.project": "проект",
|
||||
"marketplace.scope.global": "глобально",
|
||||
"marketplace.remove.type.mcp": "MCP-сервер",
|
||||
"marketplace.remove.type.skill": "навык",
|
||||
"marketplace.remove.type.mode": "режим",
|
||||
"marketplace.remove.failed": "Не удалось удалить {{name}}",
|
||||
"marketplace.install": "Установить",
|
||||
"marketplace.filter.installed": "Установлено",
|
||||
"marketplace.error.dismiss": "Закрыть",
|
||||
}
|
||||
|
||||
@@ -19,14 +19,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "ทักษะ",
|
||||
"marketplace.tab.mcpServers": "เซิร์ฟเวอร์ MCP",
|
||||
"marketplace.tab.modes": "โหมด",
|
||||
"marketplace.search.skills": "ค้นหาทักษะ...",
|
||||
"marketplace.category.all": "ทั้งหมด",
|
||||
"marketplace.empty.skills": "ไม่พบทักษะ",
|
||||
"marketplace.placeholder": "ยังไม่ได้ดำเนินการ",
|
||||
"marketplace.card.installed": "ติดตั้งแล้ว",
|
||||
"marketplace.card.install": "ติดตั้ง",
|
||||
"marketplace.card.remove": "ลบ",
|
||||
"marketplace.card.removeScope": "ลบ ({{scope}})",
|
||||
"marketplace.card.showMore": "แสดงเพิ่มเติม",
|
||||
"marketplace.card.showLess": "แสดงน้อยลง",
|
||||
"marketplace.install.title": "ติดตั้ง {{name}}",
|
||||
"marketplace.install.scope": "ขอบเขต",
|
||||
"marketplace.install.scope.project": "โปรเจกต์",
|
||||
@@ -43,4 +43,25 @@ export const dict = {
|
||||
"คุณแน่ใจหรือไม่ว่าต้องการลบ {{type}} นี้? สิ่งนี้จะลบออกจากการกำหนดค่า {{scope}} ของคุณ",
|
||||
"marketplace.remove.cancel": "ยกเลิก",
|
||||
"marketplace.remove.confirm.button": "ลบ",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "ค้นหา...",
|
||||
"marketplace.filter.all": "รายการทั้งหมด",
|
||||
"marketplace.filter.notInstalled": "ยังไม่ได้ติดตั้ง",
|
||||
"marketplace.empty": "ไม่พบรายการ",
|
||||
"marketplace.badge.mcpServer": "เซิร์ฟเวอร์ MCP",
|
||||
"marketplace.badge.mode": "โหมด",
|
||||
"marketplace.card.by": "โดย {{author}}",
|
||||
"marketplace.install.method": "วิธีการติดตั้ง",
|
||||
"marketplace.install.parameters": "พารามิเตอร์",
|
||||
"marketplace.install.optional": "(ไม่บังคับ)",
|
||||
"marketplace.install.required": "จำเป็นต้องใช้ {{name}}",
|
||||
"marketplace.scope.project": "โปรเจ็กต์",
|
||||
"marketplace.scope.global": "โกลบอล",
|
||||
"marketplace.remove.type.mcp": "เซิร์ฟเวอร์ MCP",
|
||||
"marketplace.remove.type.skill": "ทักษะ",
|
||||
"marketplace.remove.type.mode": "โหมด",
|
||||
"marketplace.remove.failed": "ไม่สามารถลบ {{name}} ได้",
|
||||
"marketplace.install": "ติดตั้ง",
|
||||
"marketplace.filter.installed": "ติดตั้งแล้ว",
|
||||
"marketplace.error.dismiss": "ปิด",
|
||||
}
|
||||
|
||||
@@ -14,4 +14,54 @@ export const dict = {
|
||||
|
||||
// Reasoning block label
|
||||
"ui.reasoning.label": "Akıl Yürütme",
|
||||
|
||||
// Marketplace
|
||||
"marketplace.tab.skills": "Yetenekler",
|
||||
"marketplace.tab.mcpServers": "MCP Sunucuları",
|
||||
"marketplace.tab.modes": "Modlar",
|
||||
"marketplace.category.all": "Tümü",
|
||||
"marketplace.placeholder": "Uygulanacak",
|
||||
"marketplace.card.installed": "Yüklendi",
|
||||
"marketplace.card.install": "Yükle",
|
||||
"marketplace.card.remove": "Kaldır",
|
||||
"marketplace.card.removeScope": "Kaldır ({{scope}})",
|
||||
"marketplace.card.showMore": "Daha fazla göster",
|
||||
"marketplace.card.showLess": "Daha az göster",
|
||||
"marketplace.install.title": "{{name}} yükle",
|
||||
"marketplace.install.scope": "Kapsam",
|
||||
"marketplace.install.scope.project": "Proje",
|
||||
"marketplace.install.scope.global": "Genel",
|
||||
"marketplace.install.prerequisites": "Ön koşullar",
|
||||
"marketplace.install.installing": "Yükleniyor...",
|
||||
"marketplace.install.cancel": "İptal",
|
||||
"marketplace.install.success": "Başarıyla yüklendi!",
|
||||
"marketplace.install.failed": "Yükleme başarısız oldu",
|
||||
"marketplace.install.done": "Bitti",
|
||||
"marketplace.install.close": "Kapat",
|
||||
"marketplace.remove.title": "{{name}} kaldırılsın mı?",
|
||||
"marketplace.remove.confirm":
|
||||
"Bu {{type}} öğesini kaldırmak istediğinizden emin misiniz? Bu, {{scope}} yapılandırmanızdan kaldırılacaktır.",
|
||||
"marketplace.remove.cancel": "İptal",
|
||||
"marketplace.remove.confirm.button": "Kaldır",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "Ara...",
|
||||
"marketplace.filter.all": "Tüm Öğeler",
|
||||
"marketplace.filter.notInstalled": "Yüklü Değil",
|
||||
"marketplace.empty": "Öğe bulunamadı",
|
||||
"marketplace.badge.mcpServer": "MCP Sunucusu",
|
||||
"marketplace.badge.mode": "Mod",
|
||||
"marketplace.card.by": "{{author}} tarafından",
|
||||
"marketplace.install.method": "Yükleme Yöntemi",
|
||||
"marketplace.install.parameters": "Parametreler",
|
||||
"marketplace.install.optional": "(isteğe bağlı)",
|
||||
"marketplace.install.required": "{{name}} gereklidir",
|
||||
"marketplace.scope.project": "proje",
|
||||
"marketplace.scope.global": "genel",
|
||||
"marketplace.remove.type.mcp": "MCP sunucusu",
|
||||
"marketplace.remove.type.skill": "yetenek",
|
||||
"marketplace.remove.type.mode": "mod",
|
||||
"marketplace.remove.failed": "{{name}} kaldırılamadı",
|
||||
"marketplace.install": "Yükle",
|
||||
"marketplace.filter.installed": "Yüklendi",
|
||||
"marketplace.error.dismiss": "Kapat",
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "技能",
|
||||
"marketplace.tab.mcpServers": "MCP 服务器",
|
||||
"marketplace.tab.modes": "模式",
|
||||
"marketplace.search.skills": "搜索技能...",
|
||||
"marketplace.category.all": "全部",
|
||||
"marketplace.empty.skills": "未找到技能",
|
||||
"marketplace.placeholder": "待实现",
|
||||
"marketplace.card.installed": "已安装",
|
||||
"marketplace.card.install": "安装",
|
||||
"marketplace.card.remove": "移除",
|
||||
"marketplace.card.removeScope": "移除 ({{scope}})",
|
||||
"marketplace.card.showMore": "展开",
|
||||
"marketplace.card.showLess": "收起",
|
||||
"marketplace.install.title": "安装 {{name}}",
|
||||
"marketplace.install.scope": "作用域",
|
||||
"marketplace.install.scope.project": "项目",
|
||||
@@ -40,4 +40,25 @@ export const dict = {
|
||||
"marketplace.remove.confirm": "确定要移除此 {{type}} 吗?这会将其从你的 {{scope}} 配置中移除。",
|
||||
"marketplace.remove.cancel": "取消",
|
||||
"marketplace.remove.confirm.button": "移除",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "搜索...",
|
||||
"marketplace.filter.all": "所有项目",
|
||||
"marketplace.filter.notInstalled": "未安装",
|
||||
"marketplace.empty": "未找到项目",
|
||||
"marketplace.badge.mcpServer": "MCP 服务器",
|
||||
"marketplace.badge.mode": "模式",
|
||||
"marketplace.card.by": "作者:{{author}}",
|
||||
"marketplace.install.method": "安装方法",
|
||||
"marketplace.install.parameters": "参数",
|
||||
"marketplace.install.optional": "(可选)",
|
||||
"marketplace.install.required": "{{name}} 是必填项",
|
||||
"marketplace.scope.project": "项目",
|
||||
"marketplace.scope.global": "全局",
|
||||
"marketplace.remove.type.mcp": "MCP 服务器",
|
||||
"marketplace.remove.type.skill": "技能",
|
||||
"marketplace.remove.type.mode": "模式",
|
||||
"marketplace.remove.failed": "移除 {{name}} 失败",
|
||||
"marketplace.install": "安装",
|
||||
"marketplace.filter.installed": "已安装",
|
||||
"marketplace.error.dismiss": "关闭",
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ export const dict = {
|
||||
"marketplace.tab.skills": "技能",
|
||||
"marketplace.tab.mcpServers": "MCP 伺服器",
|
||||
"marketplace.tab.modes": "模式",
|
||||
"marketplace.search.skills": "搜尋技能...",
|
||||
"marketplace.category.all": "全部",
|
||||
"marketplace.empty.skills": "找不到技能",
|
||||
"marketplace.placeholder": "待實作",
|
||||
"marketplace.card.installed": "已安裝",
|
||||
"marketplace.card.install": "安裝",
|
||||
"marketplace.card.remove": "移除",
|
||||
"marketplace.card.removeScope": "移除 ({{scope}})",
|
||||
"marketplace.card.showMore": "展開",
|
||||
"marketplace.card.showLess": "收起",
|
||||
"marketplace.install.title": "安裝 {{name}}",
|
||||
"marketplace.install.scope": "作用域",
|
||||
"marketplace.install.scope.project": "專案",
|
||||
@@ -40,4 +40,25 @@ export const dict = {
|
||||
"marketplace.remove.confirm": "確定要移除此 {{type}} 嗎?這會將其從你的 {{scope}} 設定中移除。",
|
||||
"marketplace.remove.cancel": "取消",
|
||||
"marketplace.remove.confirm.button": "移除",
|
||||
"marketplace.tab.mcp": "MCP",
|
||||
"marketplace.search": "搜尋...",
|
||||
"marketplace.filter.all": "所有項目",
|
||||
"marketplace.filter.notInstalled": "未安裝",
|
||||
"marketplace.empty": "找不到項目",
|
||||
"marketplace.badge.mcpServer": "MCP 伺服器",
|
||||
"marketplace.badge.mode": "模式",
|
||||
"marketplace.card.by": "作者:{{author}}",
|
||||
"marketplace.install.method": "安裝方法",
|
||||
"marketplace.install.parameters": "參數",
|
||||
"marketplace.install.optional": "(選填)",
|
||||
"marketplace.install.required": "{{name}} 是必填項",
|
||||
"marketplace.scope.project": "專案",
|
||||
"marketplace.scope.global": "全域",
|
||||
"marketplace.remove.type.mcp": "MCP 伺服器",
|
||||
"marketplace.remove.type.skill": "技能",
|
||||
"marketplace.remove.type.mode": "模式",
|
||||
"marketplace.remove.failed": "移除 {{name}} 失敗",
|
||||
"marketplace.install": "安裝",
|
||||
"marketplace.filter.installed": "已安裝",
|
||||
"marketplace.error.dismiss": "關閉",
|
||||
}
|
||||
|
||||
@@ -671,7 +671,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const workspace = this.getProjectDirectory(this.currentSession?.id)
|
||||
const scope = message.mpInstallOptions?.target ?? "project"
|
||||
const result = await this.getMarketplace().install(message.mpItem, message.mpInstallOptions, workspace)
|
||||
if (result.success) await this.disposeCliInstance(scope)
|
||||
if (result.success) {
|
||||
await this.disposeCliInstance(scope)
|
||||
this.cachedAgentsMessage = null
|
||||
await this.fetchAndSendAgents()
|
||||
}
|
||||
this.postMessage({
|
||||
type: "marketplaceInstallResult",
|
||||
success: result.success,
|
||||
@@ -684,7 +688,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
const workspace = this.getProjectDirectory(this.currentSession?.id)
|
||||
const scope = message.mpInstallOptions?.target ?? "project"
|
||||
const result = await this.getMarketplace().remove(message.mpItem, scope, workspace)
|
||||
if (result.success) await this.disposeCliInstance(scope)
|
||||
if (result.success) {
|
||||
await this.disposeCliInstance(scope)
|
||||
this.cachedAgentsMessage = null
|
||||
await this.fetchAndSendAgents()
|
||||
}
|
||||
this.postMessage({
|
||||
type: "marketplaceRemoveResult",
|
||||
success: result.success,
|
||||
@@ -1250,22 +1258,34 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
*/
|
||||
private async handleRemoveMode(name: string): Promise<void> {
|
||||
if (!this.client) return
|
||||
let removed = false
|
||||
|
||||
// 1. Try CLI removal (handles .md files and legacy .kilocodemodes)
|
||||
try {
|
||||
const dir = this.getWorkspaceDirectory()
|
||||
const result = await this.client.kilocode.removeAgent({ name, directory: dir })
|
||||
if (result.error) {
|
||||
console.error("[Kilo New] KiloProvider: removeAgent returned error:", result.error)
|
||||
this.cachedAgentsMessage = null
|
||||
await this.fetchAndSendAgents()
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to remove mode:", error)
|
||||
this.cachedAgentsMessage = null
|
||||
await this.fetchAndSendAgents()
|
||||
return
|
||||
if (!result.error) removed = true
|
||||
} catch {
|
||||
// CLI removal failed — agent may be in kilo.json instead
|
||||
}
|
||||
// Invalidate cache so next requestAgents fetches fresh data
|
||||
|
||||
// 2. Try removing from kilo.json (handles marketplace-installed modes)
|
||||
if (!removed) {
|
||||
const workspace = this.getProjectDirectory(this.currentSession?.id)
|
||||
const mp = this.getMarketplace()
|
||||
const stub = { id: name, type: "mode" as const, name, description: "", content: "" }
|
||||
const project = await mp.remove(stub, "project", workspace)
|
||||
const global = await mp.remove(stub, "global", workspace)
|
||||
if (project.success || global.success) {
|
||||
await this.disposeCliInstance("global")
|
||||
removed = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!removed) {
|
||||
console.error("[Kilo New] KiloProvider: Failed to remove mode:", name)
|
||||
}
|
||||
|
||||
this.cachedAgentsMessage = null
|
||||
await this.fetchAndSendAgents()
|
||||
}
|
||||
@@ -1281,12 +1301,13 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
|
||||
await this.client.global.dispose().catch((e: unknown) => {
|
||||
console.warn("[Kilo New] global.dispose() after marketplace change failed:", e)
|
||||
})
|
||||
} else {
|
||||
const dir = this.getWorkspaceDirectory()
|
||||
await this.client.instance.dispose({ directory: dir }).catch((e: unknown) => {
|
||||
console.warn("[Kilo New] instance.dispose() after marketplace change failed:", e)
|
||||
})
|
||||
}
|
||||
// Always dispose the per-project instance so it rebuilds state from
|
||||
// the (possibly updated) global + project config on the next request.
|
||||
const dir = this.getWorkspaceDirectory()
|
||||
await this.client.instance.dispose({ directory: dir }).catch((e: unknown) => {
|
||||
console.warn("[Kilo New] instance.dispose() after marketplace change failed:", e)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,9 +3,13 @@ import * as path from "path"
|
||||
import * as os from "os"
|
||||
import { execFile } from "child_process"
|
||||
import { promisify } from "util"
|
||||
import * as yaml from "yaml"
|
||||
import type {
|
||||
MarketplaceItem,
|
||||
SkillMarketplaceItem,
|
||||
McpMarketplaceItem,
|
||||
ModeMarketplaceItem,
|
||||
McpInstallationMethod,
|
||||
InstallMarketplaceItemOptions,
|
||||
InstallResult,
|
||||
RemoveResult,
|
||||
@@ -24,9 +28,87 @@ export class MarketplaceInstaller {
|
||||
): Promise<InstallResult> {
|
||||
const scope = options.target ?? "project"
|
||||
if (item.type === "skill") return this.installSkill(item, scope, workspace)
|
||||
return { success: false, slug: item.id, error: `${item.type} installation not yet implemented` }
|
||||
if (item.type === "mcp") return this.installMcp(item, options, scope, workspace)
|
||||
return this.installMode(item, scope, workspace)
|
||||
}
|
||||
|
||||
// ── MCP ─────────────────────────────────────────────────────────────
|
||||
|
||||
async installMcp(
|
||||
item: McpMarketplaceItem,
|
||||
options: InstallMarketplaceItemOptions,
|
||||
scope: "project" | "global",
|
||||
workspace?: string,
|
||||
): Promise<InstallResult> {
|
||||
if (scope === "project" && !workspace) {
|
||||
return { success: false, slug: item.id, error: "No workspace directory for project-scope install" }
|
||||
}
|
||||
|
||||
const config = await this.readConfig(scope, workspace)
|
||||
if (!config.mcp) config.mcp = {}
|
||||
|
||||
if (config.mcp[item.id]) {
|
||||
return { success: false, slug: item.id, error: "MCP server already installed. Remove it first." }
|
||||
}
|
||||
|
||||
const content = this.resolveMcpContent(item, options)
|
||||
if (!content) {
|
||||
return { success: false, slug: item.id, error: "No installation content for MCP server" }
|
||||
}
|
||||
|
||||
try {
|
||||
config.mcp[item.id] = this.buildMcpEntry(content, options.parameters)
|
||||
} catch (err) {
|
||||
return { success: false, slug: item.id, error: `Invalid MCP config: ${err}` }
|
||||
}
|
||||
|
||||
await this.writeConfig(scope, workspace, config)
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
|
||||
private resolveMcpContent(item: McpMarketplaceItem, options: InstallMarketplaceItemOptions): string | undefined {
|
||||
if (typeof item.content === "string") return item.content
|
||||
if (!Array.isArray(item.content) || item.content.length === 0) return undefined
|
||||
const name = options.parameters?.__method as string | undefined
|
||||
if (name) {
|
||||
const found = item.content.find((m: McpInstallationMethod) => m.name === name)
|
||||
if (found) return found.content
|
||||
}
|
||||
return item.content[0].content
|
||||
}
|
||||
|
||||
private buildMcpEntry(content: string, params?: Record<string, unknown>): Record<string, unknown> {
|
||||
const filtered = Object.fromEntries(Object.entries(params ?? {}).filter(([k]) => k !== "__method"))
|
||||
const replaced = Object.keys(filtered).length > 0 ? substituteParams(content, filtered) : content
|
||||
return JSON.parse(replaced)
|
||||
}
|
||||
|
||||
// ── Mode ────────────────────────────────────────────────────────────
|
||||
|
||||
async installMode(
|
||||
item: ModeMarketplaceItem,
|
||||
scope: "project" | "global",
|
||||
workspace?: string,
|
||||
): Promise<InstallResult> {
|
||||
if (scope === "project" && !workspace) {
|
||||
return { success: false, slug: item.id, error: "No workspace directory for project-scope install" }
|
||||
}
|
||||
|
||||
const config = await this.readConfig(scope, workspace)
|
||||
if (!config.agent) config.agent = {}
|
||||
|
||||
if (config.agent[item.id]) {
|
||||
return { success: false, slug: item.id, error: "Mode already installed. Remove it first." }
|
||||
}
|
||||
|
||||
config.agent[item.id] = convertModeToAgent(item.content)
|
||||
|
||||
await this.writeConfig(scope, workspace, config)
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
|
||||
// ── Skill ───────────────────────────────────────────────────────────
|
||||
|
||||
async installSkill(
|
||||
item: SkillMarketplaceItem,
|
||||
scope: "project" | "global",
|
||||
@@ -106,9 +188,34 @@ export class MarketplaceInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Remove ──────────────────────────────────────────────────────────
|
||||
|
||||
async remove(item: MarketplaceItem, scope: "project" | "global", workspace?: string): Promise<RemoveResult> {
|
||||
if (item.type === "skill") return this.removeSkill(item, scope, workspace)
|
||||
return { success: false, slug: item.id, error: `${item.type} removal not yet implemented` }
|
||||
if (item.type === "mcp") return this.removeMcp(item, scope, workspace)
|
||||
return this.removeMode(item, scope, workspace)
|
||||
}
|
||||
|
||||
async removeMcp(item: McpMarketplaceItem, scope: "project" | "global", workspace?: string): Promise<RemoveResult> {
|
||||
const config = await this.readConfig(scope, workspace)
|
||||
if (!config.mcp?.[item.id]) {
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
delete config.mcp[item.id]
|
||||
if (Object.keys(config.mcp).length === 0) delete config.mcp
|
||||
await this.writeConfig(scope, workspace, config)
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
|
||||
async removeMode(item: ModeMarketplaceItem, scope: "project" | "global", workspace?: string): Promise<RemoveResult> {
|
||||
const config = await this.readConfig(scope, workspace)
|
||||
if (!config.agent?.[item.id]) {
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
delete config.agent[item.id]
|
||||
if (Object.keys(config.agent).length === 0) delete config.agent
|
||||
await this.writeConfig(scope, workspace, config)
|
||||
return { success: true, slug: item.id }
|
||||
}
|
||||
|
||||
async removeSkill(
|
||||
@@ -136,6 +243,32 @@ export class MarketplaceInstaller {
|
||||
return { success: false, slug: item.id, error: String(err) }
|
||||
}
|
||||
}
|
||||
|
||||
// ── Config helpers ──────────────────────────────────────────────────
|
||||
|
||||
private async readConfig(
|
||||
scope: "project" | "global",
|
||||
workspace?: string,
|
||||
): Promise<Record<string, Record<string, unknown>>> {
|
||||
const filepath = this.paths.configPath(scope, workspace)
|
||||
try {
|
||||
const content = await fs.readFile(filepath, "utf-8")
|
||||
return JSON.parse(content)
|
||||
} catch (err) {
|
||||
if ((err as NodeJS.ErrnoException).code === "ENOENT") return {}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
private async writeConfig(
|
||||
scope: "project" | "global",
|
||||
workspace: string | undefined,
|
||||
config: Record<string, unknown>,
|
||||
): Promise<void> {
|
||||
const filepath = this.paths.configPath(scope, workspace)
|
||||
await fs.mkdir(path.dirname(filepath), { recursive: true })
|
||||
await fs.writeFile(filepath, JSON.stringify(config, null, 2) + "\n", "utf-8")
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────
|
||||
@@ -145,6 +278,66 @@ function isSafeId(id: string): boolean {
|
||||
return /^[\w\-@.]+$/.test(id)
|
||||
}
|
||||
|
||||
// Group name → opencode permission key mapping (mirrors ModesMigrator)
|
||||
const GROUP_PERMISSIONS: Record<string, string> = {
|
||||
read: "read",
|
||||
edit: "edit",
|
||||
browser: "bash",
|
||||
command: "bash",
|
||||
mcp: "mcp",
|
||||
}
|
||||
const ALL_PERMISSIONS = ["read", "edit", "bash", "mcp"]
|
||||
|
||||
function convertModeToAgent(content: string): Record<string, unknown> {
|
||||
const mode = yaml.parse(content) as Record<string, unknown>
|
||||
const groups = (mode.groups ?? []) as Array<string | [string, Record<string, unknown>]>
|
||||
|
||||
const permission: Record<string, unknown> = {}
|
||||
const allowed = new Set<string>()
|
||||
for (const group of groups) {
|
||||
if (typeof group === "string") {
|
||||
const key = GROUP_PERMISSIONS[group] ?? group
|
||||
allowed.add(key)
|
||||
permission[key] = "allow"
|
||||
} else if (Array.isArray(group)) {
|
||||
const [name, cfg] = group
|
||||
const key = GROUP_PERMISSIONS[name] ?? name
|
||||
allowed.add(key)
|
||||
permission[key] = cfg?.fileRegex ? { [String(cfg.fileRegex)]: "allow", "*": "deny" } : "allow"
|
||||
}
|
||||
}
|
||||
for (const perm of ALL_PERMISSIONS) {
|
||||
if (!allowed.has(perm)) permission[perm] = "deny"
|
||||
}
|
||||
|
||||
const prompt = [mode.roleDefinition, mode.customInstructions].filter(Boolean).join("\n\n")
|
||||
return {
|
||||
mode: "primary",
|
||||
description: mode.description ?? mode.whenToUse ?? mode.name,
|
||||
prompt,
|
||||
permission,
|
||||
}
|
||||
}
|
||||
|
||||
function escapeJsonValue(raw: string): string {
|
||||
return raw
|
||||
.replace(/\\/g, "\\\\")
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/\n/g, "\\n")
|
||||
.replace(/\r/g, "\\r")
|
||||
.replace(/\t/g, "\\t")
|
||||
}
|
||||
|
||||
function substituteParams(template: string, params: Record<string, unknown>): string {
|
||||
let result = template
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
const escaped = escapeJsonValue(String(value ?? ""))
|
||||
result = result.replaceAll(`{{${key}}}`, escaped)
|
||||
result = result.replaceAll(`\${${key}}`, escaped)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async function findEscapedPaths(dir: string): Promise<string[]> {
|
||||
const resolved = path.resolve(dir)
|
||||
const escaped: string[] = []
|
||||
|
||||
@@ -32,8 +32,10 @@ export enum TelemetryEventName {
|
||||
PROMPT_ENHANCED = "Prompt Enhanced",
|
||||
|
||||
// Marketplace
|
||||
MARKETPLACE_INSTALL_BUTTON_CLICKED = "Marketplace Install Button Clicked",
|
||||
MARKETPLACE_ITEM_INSTALLED = "Marketplace Item Installed",
|
||||
MARKETPLACE_ITEM_REMOVED = "Marketplace Item Removed",
|
||||
MARKETPLACE_TAB_VIEWED = "Marketplace Tab Viewed",
|
||||
|
||||
// Account & Auth
|
||||
ACCOUNT_CONNECT_CLICKED = "Account Connect Clicked",
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bc9274e748f94e0ae979f688a87c52b9a3d579ac015a2a49f327f8c96d002db
|
||||
size 11116
|
||||
oid sha256:0d5400d9db070953fcbf4cc3f8a4968b80c5bccb1a67ee63a463aa0539de1f41
|
||||
size 11190
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:be90b297cbdef33fa1c3c67be7a42e4c00a5f3d68147a5fbf54a04ab7b261d04
|
||||
size 52330
|
||||
oid sha256:782c1fae4bed19825b56570e573d09cc80aa2180ca5c6a4c495867f207d95beb
|
||||
size 54728
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d27dc2c85a377f7daab0b7de444a7d883a4503ab45c92c0c0a9155de89e2a221
|
||||
size 49775
|
||||
oid sha256:3d309302b177f97f198a2b889c96d08cf4578d219043d48a9d0251460be411c4
|
||||
size 52039
|
||||
|
||||
@@ -1,71 +1,119 @@
|
||||
import { Component, createSignal, onMount, onCleanup, Show, For } from "solid-js"
|
||||
import { createSignal, createEffect, onCleanup, Show, For } from "solid-js"
|
||||
import { Dialog } from "@kilocode/kilo-ui/dialog"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { RadioGroup } from "@kilocode/kilo-ui/radio-group"
|
||||
import { Select } from "@kilocode/kilo-ui/select"
|
||||
import { TextField } from "@kilocode/kilo-ui/text-field"
|
||||
import { Spinner } from "@kilocode/kilo-ui/spinner"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { useServer } from "../../context/server"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import type { MarketplaceItem } from "../../types/marketplace"
|
||||
import type { MarketplaceItem, McpMarketplaceItem, McpInstallationMethod, McpParameter } from "../../types/marketplace"
|
||||
|
||||
interface ScopeOption {
|
||||
value: "project" | "global"
|
||||
label: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface Props {
|
||||
item: MarketplaceItem
|
||||
onClose: () => void
|
||||
onInstallResult?: (success: boolean) => void
|
||||
onInstallResult: (
|
||||
success: boolean,
|
||||
scope: "project" | "global",
|
||||
extra?: { hasParameters?: boolean; installationMethodName?: string },
|
||||
) => void
|
||||
}
|
||||
|
||||
const InstallModal: Component<Props> = (props) => {
|
||||
export const InstallModal = (props: Props) => {
|
||||
const vscode = useVSCode()
|
||||
const server = useServer()
|
||||
const { t } = useLanguage()
|
||||
|
||||
const workspace = () => server.workspaceDirectory()
|
||||
const scopeOptions = (): ScopeOption[] => [
|
||||
{ value: "project", label: t("marketplace.install.scope.project"), disabled: !workspace() },
|
||||
{ value: "global", label: t("marketplace.install.scope.global") },
|
||||
]
|
||||
const [scope, setScope] = createSignal<ScopeOption>(workspace() ? scopeOptions()[0] : scopeOptions()[1])
|
||||
const options = (): ScopeOption[] =>
|
||||
workspace()
|
||||
? [
|
||||
{ value: "project", label: t("marketplace.scope.project") },
|
||||
{ value: "global", label: t("marketplace.scope.global") },
|
||||
]
|
||||
: [{ value: "global", label: t("marketplace.scope.global") }]
|
||||
const initial = workspace() ? options()[0] : options()[0]
|
||||
const [scope, setScope] = createSignal<ScopeOption>(initial)
|
||||
const [installing, setInstalling] = createSignal(false)
|
||||
const [result, setResult] = createSignal<{ success: boolean; error?: string } | null>(null)
|
||||
const [params, setParams] = createSignal<Record<string, string>>({})
|
||||
|
||||
const prerequisites = () => props.item.prerequisites ?? []
|
||||
// MCP installation methods
|
||||
const methods = (): McpInstallationMethod[] => {
|
||||
if (props.item.type !== "mcp") return []
|
||||
const mcp = props.item as McpMarketplaceItem
|
||||
if (!Array.isArray(mcp.content)) return []
|
||||
return mcp.content
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const handler = (event: MessageEvent) => {
|
||||
const msg = event.data
|
||||
if (msg?.type === "marketplaceInstallResult" && msg.slug === props.item.id) {
|
||||
const [method, setMethod] = createSignal<McpInstallationMethod | undefined>(methods()[0])
|
||||
|
||||
const prerequisites = (): string[] => {
|
||||
if (method()?.prerequisites?.length) return method()!.prerequisites!
|
||||
return props.item.prerequisites ?? []
|
||||
}
|
||||
|
||||
const parameters = (): McpParameter[] => {
|
||||
if (method()?.parameters?.length) return method()!.parameters!
|
||||
if (props.item.type === "mcp") return (props.item as McpMarketplaceItem).parameters ?? []
|
||||
return []
|
||||
}
|
||||
|
||||
const valid = () => {
|
||||
for (const param of parameters()) {
|
||||
if (!param.optional && !params()[param.key]?.trim()) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const setParam = (key: string, value: string) => {
|
||||
setParams((prev) => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const unsub = vscode.onMessage((msg) => {
|
||||
if (msg.type === "marketplaceInstallResult" && msg.slug === props.item.id) {
|
||||
setInstalling(false)
|
||||
setResult({ success: msg.success, error: msg.error })
|
||||
props.onInstallResult?.(msg.success)
|
||||
props.onInstallResult(msg.success, scope().value, {
|
||||
hasParameters: Object.keys(params()).length > 0,
|
||||
installationMethodName: method()?.name,
|
||||
})
|
||||
}
|
||||
}
|
||||
window.addEventListener("message", handler)
|
||||
onCleanup(() => window.removeEventListener("message", handler))
|
||||
})
|
||||
onCleanup(unsub)
|
||||
})
|
||||
|
||||
const handleInstall = () => {
|
||||
setInstalling(true)
|
||||
const paramValues: Record<string, unknown> = { ...params() }
|
||||
if (method()) {
|
||||
paramValues.__method = method()!.name
|
||||
}
|
||||
vscode.postMessage({
|
||||
type: "installMarketplaceItem",
|
||||
mpItem: props.item,
|
||||
mpInstallOptions: { target: scope().value },
|
||||
mpInstallOptions: {
|
||||
target: scope().value,
|
||||
parameters: Object.keys(paramValues).length > 0 ? paramValues : undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="marketplace-modal-overlay" onClick={() => !installing() && props.onClose()}>
|
||||
<div class="marketplace-modal" onClick={(e) => e.stopPropagation()}>
|
||||
<h3>{t("marketplace.install.title", { name: props.item.name })}</h3>
|
||||
|
||||
<Show when={!result()}>
|
||||
<div class="marketplace-modal-section">
|
||||
<label>{t("marketplace.install.scope")}</label>
|
||||
<Dialog title={t("marketplace.install.title", { name: props.item.name })} fit>
|
||||
<Show when={!result()}>
|
||||
<div class="install-modal-body">
|
||||
<div class="install-modal-section">
|
||||
<span class="install-modal-label">{t("marketplace.install.scope")}</span>
|
||||
<RadioGroup
|
||||
options={scopeOptions()}
|
||||
options={options()}
|
||||
current={scope()}
|
||||
value={(x: ScopeOption) => x.value}
|
||||
label={(x: ScopeOption) => x.label}
|
||||
@@ -73,46 +121,86 @@ const InstallModal: Component<Props> = (props) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Show when={methods().length > 1}>
|
||||
<div class="install-modal-section">
|
||||
<span class="install-modal-label">{t("marketplace.install.method")}</span>
|
||||
<Select
|
||||
options={methods()}
|
||||
current={method()}
|
||||
value={(m: McpInstallationMethod) => m.name}
|
||||
label={(m: McpInstallationMethod) => m.name}
|
||||
onSelect={(v: McpInstallationMethod | undefined) => {
|
||||
if (v) {
|
||||
setMethod(v)
|
||||
setParams({})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={prerequisites().length > 0}>
|
||||
<div class="marketplace-modal-section">
|
||||
<label>{t("marketplace.install.prerequisites")}</label>
|
||||
<ul class="marketplace-prerequisites">
|
||||
<div class="install-modal-section">
|
||||
<span class="install-modal-label">{t("marketplace.install.prerequisites")}</span>
|
||||
<ul class="install-modal-prerequisites">
|
||||
<For each={prerequisites()}>{(p) => <li>{p}</li>}</For>
|
||||
</ul>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="marketplace-modal-actions">
|
||||
<Show when={parameters().length > 0}>
|
||||
<div class="install-modal-section">
|
||||
<span class="install-modal-label">{t("marketplace.install.parameters")}</span>
|
||||
<For each={parameters()}>
|
||||
{(param) => (
|
||||
<div class="install-modal-param">
|
||||
<TextField
|
||||
label={param.name + (param.optional ? ` (${t("marketplace.install.optional")})` : "")}
|
||||
placeholder={param.placeholder ?? ""}
|
||||
value={params()[param.key] ?? ""}
|
||||
onChange={(v: string) => setParam(param.key, v)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="install-modal-footer">
|
||||
<Button variant="secondary" onClick={props.onClose} disabled={installing()}>
|
||||
{t("marketplace.install.cancel")}
|
||||
</Button>
|
||||
<Button variant="primary" onClick={handleInstall} disabled={installing()}>
|
||||
{installing() ? t("marketplace.install.installing") : t("marketplace.card.install")}
|
||||
<Button variant="primary" onClick={handleInstall} disabled={installing() || !valid()}>
|
||||
<Show when={installing()} fallback={t("marketplace.install")}>
|
||||
<Spinner /> {t("marketplace.install.installing")}
|
||||
</Show>
|
||||
</Button>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={result()}>
|
||||
{(r) => (
|
||||
<div class="marketplace-modal-result">
|
||||
<Show
|
||||
when={r().success}
|
||||
fallback={
|
||||
<>
|
||||
<p class="marketplace-error">{r().error ?? t("marketplace.install.failed")}</p>
|
||||
<Show when={result()}>
|
||||
{(r) => (
|
||||
<div class="install-modal-result">
|
||||
<Show
|
||||
when={r().success}
|
||||
fallback={
|
||||
<>
|
||||
<p class="install-modal-error-msg">{r().error ?? t("marketplace.install.failed")}</p>
|
||||
<div class="install-modal-footer">
|
||||
<Button onClick={props.onClose}>{t("marketplace.install.close")}</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<p class="marketplace-success">{t("marketplace.install.success")}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<p class="install-modal-success">{t("marketplace.install.success")}</p>
|
||||
<div class="install-modal-footer">
|
||||
<Button onClick={props.onClose}>{t("marketplace.install.done")}</Button>
|
||||
</Show>
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default InstallModal
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Component, Show, JSX } from "solid-js"
|
||||
import { Show, JSX, createSignal, onMount } from "solid-js"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { Card } from "@kilocode/kilo-ui/card"
|
||||
import { Tag } from "@kilocode/kilo-ui/tag"
|
||||
import type { MarketplaceItem, MarketplaceInstalledMetadata } from "../../types/marketplace"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import { installedScopes } from "./utils"
|
||||
|
||||
@@ -10,45 +12,61 @@ interface Props {
|
||||
metadata: MarketplaceInstalledMetadata
|
||||
displayName?: string
|
||||
linkUrl?: string
|
||||
typeBadge?: string
|
||||
onInstall: (item: MarketplaceItem) => void
|
||||
onRemove: (item: MarketplaceItem, scope: "project" | "global") => void
|
||||
footer?: JSX.Element
|
||||
}
|
||||
|
||||
const ItemCard: Component<Props> = (props) => {
|
||||
export const ItemCard = (props: Props) => {
|
||||
const vscode = useVSCode()
|
||||
const { t } = useLanguage()
|
||||
const scopes = () => installedScopes(props.item.id, props.item.type, props.metadata)
|
||||
const installed = () => scopes().length > 0
|
||||
const name = () => props.displayName ?? props.item.name
|
||||
const [expanded, setExpanded] = createSignal(false)
|
||||
const [clamped, setClamped] = createSignal(false)
|
||||
let ref: HTMLParagraphElement | undefined
|
||||
|
||||
onMount(() => {
|
||||
if (ref && ref.scrollHeight > ref.clientHeight) setClamped(true)
|
||||
})
|
||||
|
||||
const openLink = (url: string) => {
|
||||
vscode.postMessage({ type: "openExternal", url })
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="marketplace-card">
|
||||
<Card class="marketplace-card">
|
||||
<div class="marketplace-card-header">
|
||||
<div class="marketplace-card-title">
|
||||
<Show when={props.linkUrl} fallback={<span class="marketplace-card-name">{name()}</span>}>
|
||||
<a
|
||||
class="marketplace-card-name marketplace-card-link"
|
||||
href={props.linkUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span class="marketplace-card-name clickable" onClick={() => openLink(props.linkUrl!)}>
|
||||
{name()}
|
||||
</a>
|
||||
</Show>
|
||||
<Show when={props.typeBadge}>
|
||||
<Tag>{props.typeBadge}</Tag>
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={props.item.author}>
|
||||
<span class="marketplace-card-author">{props.item.author}</span>
|
||||
<span class="marketplace-card-author">
|
||||
<Show when={props.item.authorUrl} fallback={t("marketplace.card.by", { author: props.item.author! })}>
|
||||
<span class="link" onClick={() => openLink(props.item.authorUrl!)}>
|
||||
{t("marketplace.card.by", { author: props.item.author! })}
|
||||
</span>
|
||||
</Show>
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
<p class="marketplace-card-description">{props.item.description}</p>
|
||||
<p ref={ref} class="marketplace-card-description" classList={{ expanded: expanded() }}>
|
||||
{props.item.description}
|
||||
</p>
|
||||
<Show when={clamped()}>
|
||||
<button class="marketplace-card-expand" onClick={() => setExpanded(!expanded())}>
|
||||
{expanded() ? t("marketplace.card.showLess") : t("marketplace.card.showMore")}
|
||||
</button>
|
||||
</Show>
|
||||
<div class="marketplace-card-footer">
|
||||
<div class="marketplace-card-tags">
|
||||
<Show when={installed()}>
|
||||
<Tag class="marketplace-installed-tag">{t("marketplace.card.installed")}</Tag>
|
||||
<Tag class="marketplace-badge-installed">{t("marketplace.card.installed")}</Tag>
|
||||
</Show>
|
||||
{props.footer}
|
||||
</div>
|
||||
@@ -62,15 +80,20 @@ const ItemCard: Component<Props> = (props) => {
|
||||
}
|
||||
>
|
||||
{scopes().map((scope) => (
|
||||
<Button size="small" class="marketplace-remove-btn" onClick={() => props.onRemove(props.item, scope)}>
|
||||
{scopes().length > 1 ? t("marketplace.card.removeScope", { scope }) : t("marketplace.card.remove")}
|
||||
<Button
|
||||
size="small"
|
||||
variant="ghost"
|
||||
class="marketplace-remove-btn"
|
||||
onClick={() => props.onRemove(props.item, scope)}
|
||||
>
|
||||
{scopes().length > 1
|
||||
? t("marketplace.card.removeScope", { scope: t(`marketplace.scope.${scope}`) })
|
||||
: t("marketplace.card.remove")}
|
||||
</Button>
|
||||
))}
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default ItemCard
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
import { createSignal, createMemo, For, Show } from "solid-js"
|
||||
import { TextField } from "@kilocode/kilo-ui/text-field"
|
||||
import { Select } from "@kilocode/kilo-ui/select"
|
||||
import { Tag } from "@kilocode/kilo-ui/tag"
|
||||
import { Spinner } from "@kilocode/kilo-ui/spinner"
|
||||
import type {
|
||||
MarketplaceItem,
|
||||
McpMarketplaceItem,
|
||||
SkillMarketplaceItem,
|
||||
MarketplaceInstalledMetadata,
|
||||
} from "../../types/marketplace"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import { isInstalled } from "./utils"
|
||||
import { ItemCard } from "./ItemCard"
|
||||
|
||||
interface StatusOption {
|
||||
value: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
items: MarketplaceItem[]
|
||||
metadata: MarketplaceInstalledMetadata
|
||||
fetching: boolean
|
||||
type: "mcp" | "mode" | "skill"
|
||||
searchPlaceholder: string
|
||||
emptyMessage: string
|
||||
onInstall: (item: MarketplaceItem) => void
|
||||
onRemove: (item: MarketplaceItem, scope: "project" | "global") => void
|
||||
}
|
||||
|
||||
export const MarketplaceListView = (props: Props) => {
|
||||
const { t } = useLanguage()
|
||||
const [search, setSearch] = createSignal("")
|
||||
const [status, setStatus] = createSignal<StatusOption>({ value: "all", label: t("marketplace.filter.all") })
|
||||
const [tags, setTags] = createSignal<string[]>([])
|
||||
|
||||
const options = (): StatusOption[] => [
|
||||
{ value: "all", label: t("marketplace.filter.all") },
|
||||
{ value: "installed", label: t("marketplace.filter.installed") },
|
||||
{ value: "notInstalled", label: t("marketplace.filter.notInstalled") },
|
||||
]
|
||||
|
||||
const tagsFor = (item: MarketplaceItem): string[] => {
|
||||
if (item.type === "skill") return [(item as SkillMarketplaceItem).displayCategory]
|
||||
return item.tags ?? []
|
||||
}
|
||||
|
||||
const allTags = createMemo(() => {
|
||||
const counts = new Map<string, number>()
|
||||
for (const item of props.items) {
|
||||
for (const tag of tagsFor(item)) counts.set(tag, (counts.get(tag) ?? 0) + 1)
|
||||
}
|
||||
const min = props.type === "mcp" ? 5 : 1
|
||||
return Array.from(counts.entries())
|
||||
.filter(([, n]) => n >= min)
|
||||
.map(([tag]) => tag)
|
||||
.sort()
|
||||
})
|
||||
|
||||
const toggleTag = (tag: string) => {
|
||||
const current = tags()
|
||||
if (current.includes(tag)) {
|
||||
setTags(current.filter((t) => t !== tag))
|
||||
} else {
|
||||
setTags([...current, tag])
|
||||
}
|
||||
}
|
||||
|
||||
const filtered = createMemo(() => {
|
||||
const q = search().toLowerCase()
|
||||
const s = status().value
|
||||
const active = tags()
|
||||
return props.items.filter((item) => {
|
||||
if (s === "installed" && !isInstalled(item.id, item.type, props.metadata)) return false
|
||||
if (s === "notInstalled" && isInstalled(item.id, item.type, props.metadata)) return false
|
||||
if (active.length > 0 && !active.some((tag) => tagsFor(item).includes(tag))) return false
|
||||
if (!q) return true
|
||||
const skill = item.type === "skill" ? (item as SkillMarketplaceItem) : undefined
|
||||
return (
|
||||
item.id.toLowerCase().includes(q) ||
|
||||
item.name.toLowerCase().includes(q) ||
|
||||
item.description.toLowerCase().includes(q) ||
|
||||
(item.author?.toLowerCase().includes(q) ?? false) ||
|
||||
(skill?.displayName.toLowerCase().includes(q) ?? false)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="marketplace-list">
|
||||
<div class="marketplace-filters">
|
||||
<div class="marketplace-search-field">
|
||||
<TextField placeholder={props.searchPlaceholder} value={search()} onChange={setSearch} />
|
||||
</div>
|
||||
<Select
|
||||
options={options()}
|
||||
current={status()}
|
||||
value={(o: StatusOption) => o.value}
|
||||
label={(o: StatusOption) => o.label}
|
||||
onSelect={(v: StatusOption | undefined) => v && setStatus(v)}
|
||||
/>
|
||||
</div>
|
||||
<Show when={allTags().length > 0}>
|
||||
<div class="marketplace-active-tags">
|
||||
<For each={allTags()}>
|
||||
{(tag) => (
|
||||
<button
|
||||
class="marketplace-tag-filter"
|
||||
classList={{ active: tags().includes(tag) }}
|
||||
onClick={() => toggleTag(tag)}
|
||||
>
|
||||
<Tag>{tag}</Tag>
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
<Show
|
||||
when={!props.fetching}
|
||||
fallback={
|
||||
<div class="marketplace-loading">
|
||||
<Spinner />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Show when={filtered().length > 0} fallback={<p class="marketplace-empty">{props.emptyMessage}</p>}>
|
||||
<div class="marketplace-grid">
|
||||
<For each={filtered()}>
|
||||
{(item) => {
|
||||
const skill = item.type === "skill" ? (item as SkillMarketplaceItem) : undefined
|
||||
const mcp = item.type === "mcp" ? (item as McpMarketplaceItem) : undefined
|
||||
return (
|
||||
<ItemCard
|
||||
item={item}
|
||||
metadata={props.metadata}
|
||||
displayName={skill?.displayName}
|
||||
linkUrl={skill?.githubUrl ?? mcp?.url}
|
||||
onInstall={props.onInstall}
|
||||
onRemove={props.onRemove}
|
||||
footer={<For each={tagsFor(item)}>{(tag) => <Tag>{tag}</Tag>}</For>}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,168 +1,204 @@
|
||||
import { Component, createSignal, createMemo, onMount, onCleanup, Show } from "solid-js"
|
||||
import { createSignal, createMemo, createEffect, onCleanup, onMount, Show } from "solid-js"
|
||||
import { Tabs } from "@kilocode/kilo-ui/tabs"
|
||||
import { Card } from "@kilocode/kilo-ui/card"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { useServer } from "../../context/server"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import type { MarketplaceItem, SkillMarketplaceItem, MarketplaceInstalledMetadata } from "../../types/marketplace"
|
||||
import SkillsMarketplace from "./SkillsMarketplace"
|
||||
import InstallModal from "./InstallModal"
|
||||
import RemoveDialog from "./RemoveDialog"
|
||||
import { useDialog } from "@kilocode/kilo-ui/context/dialog"
|
||||
import type {
|
||||
MarketplaceItem,
|
||||
McpMarketplaceItem,
|
||||
ModeMarketplaceItem,
|
||||
SkillMarketplaceItem,
|
||||
MarketplaceInstalledMetadata,
|
||||
} from "../../types/marketplace"
|
||||
import { TelemetryEventName } from "../../../../src/services/telemetry/types"
|
||||
import { MarketplaceListView } from "./MarketplaceListView"
|
||||
import { InstallModal } from "./InstallModal"
|
||||
import { RemoveDialog } from "./RemoveDialog"
|
||||
import "./marketplace.css"
|
||||
|
||||
const EMPTY_METADATA: MarketplaceInstalledMetadata = { project: {}, global: {} }
|
||||
|
||||
const MarketplaceView: Component = () => {
|
||||
export const MarketplaceView = () => {
|
||||
const vscode = useVSCode()
|
||||
const server = useServer()
|
||||
const { t } = useLanguage()
|
||||
const dialog = useDialog()
|
||||
|
||||
const [items, setItems] = createSignal<MarketplaceItem[]>([])
|
||||
const [metadata, setMetadata] = createSignal<MarketplaceInstalledMetadata>(EMPTY_METADATA)
|
||||
const [fetching, setFetching] = createSignal(true)
|
||||
const [errors, setErrors] = createSignal<string[]>([])
|
||||
const [tab, setTab] = createSignal("skill")
|
||||
|
||||
// Install/Remove state
|
||||
const [installItem, setInstallItem] = createSignal<MarketplaceItem | null>(null)
|
||||
const [removeItem, setRemoveItem] = createSignal<{ item: MarketplaceItem; scope: "project" | "global" } | null>(null)
|
||||
const [pendingRemove, setPendingRemove] = createSignal<string | null>(null)
|
||||
const [removeError, setRemoveError] = createSignal<string | null>(null)
|
||||
const [tab, setTab] = createSignal("mcp")
|
||||
const [pending, setPending] = createSignal<{ item: MarketplaceItem; scope: "project" | "global" } | null>(null)
|
||||
|
||||
const skills = createMemo(() => items().filter((i): i is SkillMarketplaceItem => i.type === "skill"))
|
||||
const mcps = createMemo(() => items().filter((i): i is McpMarketplaceItem => i.type === "mcp"))
|
||||
const modes = createMemo(() => items().filter((i): i is ModeMarketplaceItem => i.type === "mode"))
|
||||
|
||||
const fetchData = () => {
|
||||
setFetching(true)
|
||||
vscode.postMessage({ type: "fetchMarketplaceData" })
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
fetchData()
|
||||
|
||||
const handler = (event: MessageEvent) => {
|
||||
const msg = event.data
|
||||
if (msg?.type === "marketplaceData") {
|
||||
// Listen for messages
|
||||
createEffect(() => {
|
||||
const unsub = vscode.onMessage((msg) => {
|
||||
if (msg.type === "marketplaceData") {
|
||||
setItems(msg.marketplaceItems ?? [])
|
||||
setMetadata(msg.marketplaceInstalledMetadata ?? EMPTY_METADATA)
|
||||
setErrors(msg.errors ?? [])
|
||||
setFetching(false)
|
||||
}
|
||||
if (msg?.type === "marketplaceRemoveResult") {
|
||||
if (msg.slug === pendingRemove()) {
|
||||
setPendingRemove(null)
|
||||
if (!msg.success) {
|
||||
setRemoveError(msg.error ?? "Failed to remove item")
|
||||
} else {
|
||||
fetchData()
|
||||
if (msg.type === "marketplaceRemoveResult") {
|
||||
const removed = pending()
|
||||
setPending(null)
|
||||
if (msg.success) {
|
||||
if (removed) {
|
||||
telemetry(TelemetryEventName.MARKETPLACE_ITEM_REMOVED, {
|
||||
itemId: removed.item.id,
|
||||
itemType: removed.item.type,
|
||||
itemName: removed.item.name,
|
||||
target: removed.scope,
|
||||
})
|
||||
}
|
||||
fetchData()
|
||||
} else {
|
||||
setErrors((prev) => [...prev, msg.error ?? t("marketplace.remove.failed", { name: msg.slug })])
|
||||
}
|
||||
}
|
||||
// Re-fetch when agents or skills change (e.g. after install via CLI)
|
||||
if (msg?.type === "agentsLoaded" || msg?.type === "skillsLoaded") {
|
||||
fetchData()
|
||||
}
|
||||
// Re-fetch when workspace directory changes
|
||||
if (msg?.type === "workspaceDirectoryChanged") {
|
||||
fetchData()
|
||||
}
|
||||
}
|
||||
window.addEventListener("message", handler)
|
||||
onCleanup(() => window.removeEventListener("message", handler))
|
||||
})
|
||||
onCleanup(unsub)
|
||||
})
|
||||
|
||||
// Re-fetch when workspace changes
|
||||
createEffect(() => {
|
||||
server.workspaceDirectory()
|
||||
fetchData()
|
||||
})
|
||||
|
||||
const telemetry = (event: string, properties?: Record<string, unknown>) => {
|
||||
vscode.postMessage({ type: "telemetry", event, properties: properties ?? {} })
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
telemetry(TelemetryEventName.MARKETPLACE_TAB_VIEWED)
|
||||
})
|
||||
|
||||
const handleInstall = (item: MarketplaceItem) => {
|
||||
setInstallItem(item)
|
||||
telemetry(TelemetryEventName.MARKETPLACE_INSTALL_BUTTON_CLICKED, {
|
||||
itemId: item.id,
|
||||
itemType: item.type,
|
||||
itemName: item.name,
|
||||
})
|
||||
dialog.show(() => (
|
||||
<InstallModal
|
||||
item={item}
|
||||
onClose={() => dialog.close()}
|
||||
onInstallResult={(success, scope, extra) => {
|
||||
if (success) {
|
||||
telemetry(TelemetryEventName.MARKETPLACE_ITEM_INSTALLED, {
|
||||
itemId: item.id,
|
||||
itemType: item.type,
|
||||
itemName: item.name,
|
||||
target: scope,
|
||||
...(extra?.hasParameters && { hasParameters: true }),
|
||||
...(extra?.installationMethodName && { installationMethodName: extra.installationMethodName }),
|
||||
})
|
||||
dialog.close()
|
||||
fetchData()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
const handleRemove = (item: MarketplaceItem, scope: "project" | "global") => {
|
||||
setRemoveItem({ item, scope })
|
||||
dialog.show(() => (
|
||||
<RemoveDialog
|
||||
item={item}
|
||||
scope={scope}
|
||||
onClose={() => dialog.close()}
|
||||
onConfirm={() => {
|
||||
setPending({ item, scope })
|
||||
vscode.postMessage({
|
||||
type: "removeInstalledMarketplaceItem",
|
||||
mpItem: item,
|
||||
mpInstallOptions: { target: scope },
|
||||
})
|
||||
dialog.close()
|
||||
}}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
||||
const confirmRemove = () => {
|
||||
const r = removeItem()
|
||||
if (!r) return
|
||||
setPendingRemove(r.item.id)
|
||||
setRemoveError(null)
|
||||
vscode.postMessage({
|
||||
type: "removeInstalledMarketplaceItem",
|
||||
mpItem: r.item,
|
||||
mpInstallOptions: { target: r.scope },
|
||||
})
|
||||
setRemoveItem(null)
|
||||
const dismissError = (idx: number) => {
|
||||
setErrors((prev) => prev.filter((_, i) => i !== idx))
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="marketplace-view">
|
||||
<Tabs value={tab()} onChange={setTab}>
|
||||
<Show when={errors().length > 0}>
|
||||
{errors().map((err, idx) => (
|
||||
<Card variant="error" class="marketplace-error-banner">
|
||||
<span>{err}</span>
|
||||
<Button variant="ghost" size="small" onClick={() => dismissError(idx)}>
|
||||
{t("marketplace.error.dismiss")}
|
||||
</Button>
|
||||
</Card>
|
||||
))}
|
||||
</Show>
|
||||
|
||||
<Tabs value={tab()} onChange={setTab} class="marketplace-tabs-root">
|
||||
<Tabs.List>
|
||||
<Tabs.Trigger value="skill">{t("marketplace.tab.skills")}</Tabs.Trigger>
|
||||
<Tabs.Trigger value="mcp">{t("marketplace.tab.mcpServers")}</Tabs.Trigger>
|
||||
<Tabs.Trigger value="mcp">{t("marketplace.tab.mcp")}</Tabs.Trigger>
|
||||
<Tabs.Trigger value="mode">{t("marketplace.tab.modes")}</Tabs.Trigger>
|
||||
<Tabs.Trigger value="skill">{t("marketplace.tab.skills")}</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
||||
<Tabs.Content value="skill">
|
||||
<SkillsMarketplace
|
||||
items={skills()}
|
||||
metadata={metadata()}
|
||||
fetching={fetching()}
|
||||
onInstall={handleInstall}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<div class="marketplace-content">
|
||||
<Tabs.Content value="mcp">
|
||||
<MarketplaceListView
|
||||
items={mcps()}
|
||||
metadata={metadata()}
|
||||
fetching={fetching()}
|
||||
type="mcp"
|
||||
searchPlaceholder={t("marketplace.search")}
|
||||
emptyMessage={t("marketplace.empty")}
|
||||
onInstall={handleInstall}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="mcp">
|
||||
<div class="marketplace-placeholder">
|
||||
<p>{t("marketplace.placeholder")}</p>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="mode">
|
||||
<MarketplaceListView
|
||||
items={modes()}
|
||||
metadata={metadata()}
|
||||
fetching={fetching()}
|
||||
type="mode"
|
||||
searchPlaceholder={t("marketplace.search")}
|
||||
emptyMessage={t("marketplace.empty")}
|
||||
onInstall={handleInstall}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="mode">
|
||||
<div class="marketplace-placeholder">
|
||||
<p>{t("marketplace.placeholder")}</p>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="skill">
|
||||
<MarketplaceListView
|
||||
items={skills()}
|
||||
metadata={metadata()}
|
||||
fetching={fetching()}
|
||||
type="skill"
|
||||
searchPlaceholder={t("marketplace.search")}
|
||||
emptyMessage={t("marketplace.empty")}
|
||||
onInstall={handleInstall}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
<Show when={errors().length > 0}>
|
||||
<div class="marketplace-errors">
|
||||
{errors().map((e) => (
|
||||
<p class="marketplace-error">{e}</p>
|
||||
))}
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={removeError()}>
|
||||
<div class="marketplace-errors">
|
||||
<p class="marketplace-error">{removeError()}</p>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={installItem()}>
|
||||
{(item) => (
|
||||
<InstallModal
|
||||
item={item()}
|
||||
onClose={() => setInstallItem(null)}
|
||||
onInstallResult={(success) => {
|
||||
if (success) {
|
||||
setInstallItem(null)
|
||||
fetchData()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
<Show when={removeItem()}>
|
||||
{(r) => (
|
||||
<RemoveDialog
|
||||
item={r().item}
|
||||
scope={r().scope}
|
||||
onClose={() => setRemoveItem(null)}
|
||||
onConfirm={confirmRemove}
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MarketplaceView
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from "solid-js"
|
||||
import { Dialog } from "@kilocode/kilo-ui/dialog"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import type { MarketplaceItem } from "../../types/marketplace"
|
||||
import { useLanguage } from "../../context/language"
|
||||
@@ -10,25 +10,26 @@ interface Props {
|
||||
onConfirm: () => void
|
||||
}
|
||||
|
||||
const RemoveDialog: Component<Props> = (props) => {
|
||||
export const RemoveDialog = (props: Props) => {
|
||||
const { t } = useLanguage()
|
||||
|
||||
const typeName = () => {
|
||||
if (props.item.type === "mcp") return t("marketplace.remove.type.mcp")
|
||||
if (props.item.type === "mode") return t("marketplace.remove.type.mode")
|
||||
return t("marketplace.remove.type.skill")
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="marketplace-modal-overlay" onClick={props.onClose}>
|
||||
<div class="marketplace-modal" onClick={(e) => e.stopPropagation()}>
|
||||
<h3>{t("marketplace.remove.title", { name: props.item.name })}</h3>
|
||||
<p>{t("marketplace.remove.confirm", { type: props.item.type, scope: props.scope })}</p>
|
||||
<div class="marketplace-modal-actions">
|
||||
<Button variant="secondary" onClick={props.onClose}>
|
||||
{t("marketplace.remove.cancel")}
|
||||
</Button>
|
||||
<Button variant="primary" class="marketplace-remove-btn" onClick={props.onConfirm}>
|
||||
{t("marketplace.remove.confirm.button")}
|
||||
</Button>
|
||||
</div>
|
||||
<Dialog title={t("marketplace.remove.title", { name: props.item.name })} fit>
|
||||
<p>{t("marketplace.remove.confirm", { type: typeName(), scope: t(`marketplace.scope.${props.scope}`) })}</p>
|
||||
<div class="marketplace-remove-actions">
|
||||
<Button variant="secondary" onClick={props.onClose}>
|
||||
{t("marketplace.remove.cancel")}
|
||||
</Button>
|
||||
<Button variant="primary" class="danger-btn" onClick={props.onConfirm}>
|
||||
{t("marketplace.remove.confirm.button")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
export default RemoveDialog
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
import { Component, createSignal, createMemo, For, Show } from "solid-js"
|
||||
import { TextField } from "@kilocode/kilo-ui/text-field"
|
||||
import { RadioGroup } from "@kilocode/kilo-ui/radio-group"
|
||||
import { Tag } from "@kilocode/kilo-ui/tag"
|
||||
import { Spinner } from "@kilocode/kilo-ui/spinner"
|
||||
import type { SkillMarketplaceItem, MarketplaceInstalledMetadata, MarketplaceItem } from "../../types/marketplace"
|
||||
import { useLanguage } from "../../context/language"
|
||||
import ItemCard from "./ItemCard"
|
||||
|
||||
interface Props {
|
||||
items: SkillMarketplaceItem[]
|
||||
metadata: MarketplaceInstalledMetadata
|
||||
fetching: boolean
|
||||
onInstall: (item: MarketplaceItem) => void
|
||||
onRemove: (item: MarketplaceItem, scope: "project" | "global") => void
|
||||
}
|
||||
|
||||
const ALL = "__all__"
|
||||
|
||||
const SkillsMarketplace: Component<Props> = (props) => {
|
||||
const { t } = useLanguage()
|
||||
const [search, setSearch] = createSignal("")
|
||||
const [category, setCategory] = createSignal(ALL)
|
||||
|
||||
const categories = createMemo(() => {
|
||||
const set = new Set<string>()
|
||||
for (const item of props.items) {
|
||||
if (item.displayCategory) set.add(item.displayCategory)
|
||||
}
|
||||
return [ALL, ...Array.from(set).sort()]
|
||||
})
|
||||
|
||||
const filtered = createMemo(() => {
|
||||
const q = search().toLowerCase()
|
||||
const cat = category()
|
||||
return props.items.filter((item) => {
|
||||
if (cat !== ALL && item.displayCategory !== cat) return false
|
||||
if (!q) return true
|
||||
return (
|
||||
item.id.toLowerCase().includes(q) ||
|
||||
item.name.toLowerCase().includes(q) ||
|
||||
item.displayName.toLowerCase().includes(q) ||
|
||||
item.description.toLowerCase().includes(q) ||
|
||||
item.displayCategory.toLowerCase().includes(q)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<div class="marketplace-list">
|
||||
<div class="marketplace-filters">
|
||||
<TextField placeholder={t("marketplace.search.skills")} value={search()} onChange={setSearch} />
|
||||
</div>
|
||||
<div class="marketplace-category-filters">
|
||||
<RadioGroup
|
||||
options={categories()}
|
||||
current={category()}
|
||||
value={(c: string) => c}
|
||||
label={(c: string) => (c === ALL ? t("marketplace.category.all") : c)}
|
||||
onSelect={(v: string | undefined) => v && setCategory(v)}
|
||||
/>
|
||||
</div>
|
||||
<Show when={!props.fetching} fallback={<Spinner />}>
|
||||
<Show when={filtered().length > 0} fallback={<p class="marketplace-empty">{t("marketplace.empty.skills")}</p>}>
|
||||
<div class="marketplace-grid">
|
||||
<For each={filtered()}>
|
||||
{(item) => (
|
||||
<ItemCard
|
||||
item={item}
|
||||
metadata={props.metadata}
|
||||
displayName={item.displayName}
|
||||
linkUrl={item.githubUrl}
|
||||
onInstall={props.onInstall}
|
||||
onRemove={props.onRemove}
|
||||
footer={<Tag>{item.displayCategory}</Tag>}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SkillsMarketplace
|
||||
@@ -1 +1 @@
|
||||
export { default as MarketplaceView } from "./MarketplaceView"
|
||||
export { MarketplaceView } from "./MarketplaceView"
|
||||
|
||||
@@ -6,6 +6,19 @@
|
||||
height: 100%;
|
||||
padding: 12px;
|
||||
overflow: auto;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.marketplace-tabs-root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.marketplace-content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* List layout */
|
||||
@@ -23,22 +36,59 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.marketplace-search-field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.marketplace-category-filters {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* Tag filters */
|
||||
|
||||
.marketplace-active-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.marketplace-tag-filter {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
|
||||
.marketplace-tag-filter:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.marketplace-tag-filter.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Loading & empty */
|
||||
|
||||
.marketplace-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.marketplace-empty {
|
||||
text-align: center;
|
||||
color: var(--text-weak);
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* Grid */
|
||||
|
||||
.marketplace-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.marketplace-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
/* Card */
|
||||
@@ -48,9 +98,6 @@
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--border-base);
|
||||
border-radius: 6px;
|
||||
background: var(--background-base);
|
||||
}
|
||||
|
||||
.marketplace-card-header {
|
||||
@@ -71,11 +118,11 @@
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
.marketplace-card-link {
|
||||
text-decoration: none;
|
||||
.marketplace-card-name.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.marketplace-card-link:hover {
|
||||
.marketplace-card-name.clickable:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -94,6 +141,22 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.marketplace-card-description.expanded {
|
||||
display: block;
|
||||
-webkit-line-clamp: unset;
|
||||
}
|
||||
|
||||
.marketplace-card-expand {
|
||||
all: unset;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: var(--text-interactive-base);
|
||||
}
|
||||
|
||||
.marketplace-card-expand:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.marketplace-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -115,117 +178,109 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.marketplace-installed-tag {
|
||||
/* Installed badge */
|
||||
|
||||
.marketplace-badge-installed {
|
||||
color: var(--text-on-success-base) !important;
|
||||
border-color: var(--border-success-base) !important;
|
||||
}
|
||||
|
||||
/* Remove button */
|
||||
|
||||
.marketplace-remove-btn {
|
||||
color: var(--text-on-critical-base) !important;
|
||||
border-color: var(--border-critical-base) !important;
|
||||
}
|
||||
|
||||
/* Placeholder */
|
||||
/* Remove dialog actions */
|
||||
|
||||
.marketplace-placeholder {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 200px;
|
||||
color: var(--text-weak);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
|
||||
.marketplace-empty {
|
||||
text-align: center;
|
||||
color: var(--text-weak);
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
/* Modal / Dialog */
|
||||
|
||||
.marketplace-modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.marketplace-modal {
|
||||
background: var(--background-base);
|
||||
border: 1px solid var(--border-base);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
max-width: 480px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.marketplace-modal h3 {
|
||||
margin: 0 0 16px;
|
||||
font-size: 16px;
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
.marketplace-modal p {
|
||||
margin: 0 0 12px;
|
||||
color: var(--text-weak);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.marketplace-modal-section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.marketplace-modal-section > label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
margin-bottom: 6px;
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
.marketplace-modal-actions {
|
||||
.marketplace-remove-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.marketplace-modal-result {
|
||||
text-align: center;
|
||||
padding: 12px 0;
|
||||
/* Danger button (remove confirm) */
|
||||
|
||||
.danger-btn {
|
||||
color: var(--text-on-critical-base) !important;
|
||||
border-color: var(--border-critical-base) !important;
|
||||
}
|
||||
|
||||
.marketplace-prerequisites {
|
||||
/* Install modal */
|
||||
|
||||
.install-modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.install-modal-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.install-modal-label {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
.install-modal-prerequisites {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
font-size: 13px;
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
/* Error/Success messages */
|
||||
|
||||
.marketplace-errors {
|
||||
margin-top: 12px;
|
||||
.install-modal-param {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.marketplace-error {
|
||||
color: var(--text-on-critical-base);
|
||||
font-size: 13px;
|
||||
.install-modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.marketplace-success {
|
||||
.install-modal-result {
|
||||
text-align: center;
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.install-modal-success {
|
||||
color: var(--text-on-success-base);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
|
||||
.install-modal-error-msg {
|
||||
color: var(--text-on-critical-base);
|
||||
font-size: 13px;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
|
||||
/* Error banner */
|
||||
|
||||
.marketplace-error-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Link style */
|
||||
|
||||
.link {
|
||||
color: var(--text-interactive-base);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import type { MarketplaceInstalledMetadata } from "../../types/marketplace"
|
||||
|
||||
export function isInstalled(
|
||||
id: string,
|
||||
type: string,
|
||||
metadata: MarketplaceInstalledMetadata,
|
||||
): "project" | "global" | false {
|
||||
return installedScopes(id, type, metadata)[0] ?? false
|
||||
}
|
||||
|
||||
export function installedScopes(
|
||||
id: string,
|
||||
type: string,
|
||||
metadata: MarketplaceInstalledMetadata,
|
||||
): Array<"project" | "global"> {
|
||||
const scopes: Array<"project" | "global"> = []
|
||||
): ("project" | "global")[] {
|
||||
const scopes: ("project" | "global")[] = []
|
||||
if (metadata.project[id]?.type === type) scopes.push("project")
|
||||
if (metadata.global[id]?.type === type) scopes.push("global")
|
||||
return scopes
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
/**
|
||||
* Stories for Marketplace components.
|
||||
*
|
||||
* Renders SkillsMarketplace and ItemCard directly with mock data
|
||||
* Renders MarketplaceListView and ItemCard directly with mock data
|
||||
* so no API requests are made.
|
||||
*/
|
||||
|
||||
import type { Meta, StoryObj } from "storybook-solidjs-vite"
|
||||
import { StoryProviders } from "./StoryProviders"
|
||||
import SkillsMarketplace from "../components/marketplace/SkillsMarketplace"
|
||||
import ItemCard from "../components/marketplace/ItemCard"
|
||||
import { MarketplaceListView } from "../components/marketplace/MarketplaceListView"
|
||||
import { ItemCard } from "../components/marketplace/ItemCard"
|
||||
import type { SkillMarketplaceItem, MarketplaceInstalledMetadata } from "../types/marketplace"
|
||||
import "../components/marketplace/marketplace.css"
|
||||
|
||||
@@ -116,10 +116,13 @@ export const SkillsTabWithItems: Story = {
|
||||
render: () => (
|
||||
<StoryProviders>
|
||||
<div style={{ width: "420px", height: "700px", overflow: "auto", padding: "12px" }}>
|
||||
<SkillsMarketplace
|
||||
<MarketplaceListView
|
||||
items={MOCK_SKILLS}
|
||||
metadata={EMPTY_METADATA}
|
||||
fetching={false}
|
||||
type="skill"
|
||||
searchPlaceholder="Search skills..."
|
||||
emptyMessage="No skills found"
|
||||
onInstall={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
@@ -133,10 +136,13 @@ export const SkillsTabWithInstalled: Story = {
|
||||
render: () => (
|
||||
<StoryProviders>
|
||||
<div style={{ width: "420px", height: "700px", overflow: "auto", padding: "12px" }}>
|
||||
<SkillsMarketplace
|
||||
<MarketplaceListView
|
||||
items={MOCK_SKILLS}
|
||||
metadata={PARTIAL_INSTALLED}
|
||||
fetching={false}
|
||||
type="skill"
|
||||
searchPlaceholder="Search skills..."
|
||||
emptyMessage="No skills found"
|
||||
onInstall={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
@@ -150,7 +156,16 @@ export const SkillsTabEmpty: Story = {
|
||||
render: () => (
|
||||
<StoryProviders>
|
||||
<div style={{ width: "420px", height: "400px", overflow: "auto", padding: "12px" }}>
|
||||
<SkillsMarketplace items={[]} metadata={EMPTY_METADATA} fetching={false} onInstall={noop} onRemove={noop} />
|
||||
<MarketplaceListView
|
||||
items={[]}
|
||||
metadata={EMPTY_METADATA}
|
||||
fetching={false}
|
||||
type="skill"
|
||||
searchPlaceholder="Search skills..."
|
||||
emptyMessage="No skills found"
|
||||
onInstall={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
</div>
|
||||
</StoryProviders>
|
||||
),
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
export interface McpParameter {
|
||||
name: string
|
||||
key: string
|
||||
placeholder?: string
|
||||
optional?: boolean
|
||||
}
|
||||
|
||||
export interface McpInstallationMethod {
|
||||
name: string
|
||||
content: string
|
||||
parameters?: McpParameter[]
|
||||
prerequisites?: string[]
|
||||
}
|
||||
|
||||
export interface MarketplaceItemBase {
|
||||
id: string
|
||||
name: string
|
||||
@@ -11,7 +25,8 @@ export interface MarketplaceItemBase {
|
||||
export interface McpMarketplaceItem extends MarketplaceItemBase {
|
||||
type: "mcp"
|
||||
url: string
|
||||
content: string | unknown[]
|
||||
content: string | McpInstallationMethod[]
|
||||
parameters?: McpParameter[]
|
||||
}
|
||||
|
||||
export interface ModeMarketplaceItem extends MarketplaceItemBase {
|
||||
@@ -41,8 +56,7 @@ export interface MarketplaceInstalledMetadata {
|
||||
}
|
||||
|
||||
export interface MarketplaceFilters {
|
||||
search?: string
|
||||
type?: string
|
||||
status?: string
|
||||
search?: string
|
||||
tags?: string[]
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ export const GlobalRoutes = lazy(() =>
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
Config.global.reset() // kilocode_change - reset cached global config so re-init reads fresh data from disk
|
||||
await Instance.disposeAll()
|
||||
GlobalBus.emit("event", {
|
||||
directory: "global",
|
||||
|
||||
Reference in New Issue
Block a user