diff --git a/frontend/src/services/tools/themeTools.ts b/frontend/src/services/tools/themeTools.ts index 3f0f9c7..4f2b96a 100644 --- a/frontend/src/services/tools/themeTools.ts +++ b/frontend/src/services/tools/themeTools.ts @@ -5,7 +5,13 @@ export const THEME_TOOLS = [ 'get_design_tokens', 'get_active_theme', 'set_theme_variable', - 'save_theme' + 'save_theme', + 'list_themes', + 'switch_theme', + 'set_default_theme', + 'delete_theme', + 'reset_theme', + 'export_theme' ] export function registerThemeTools() { @@ -205,6 +211,232 @@ export function registerThemeTools() { } } ) + + // list_themes + registerTool( + 'list_themes', + 'Lista todos los temas disponibles (del sistema y personalizados)', + { + type: 'object', + properties: {} + }, + async () => { + try { + const themeStore = useThemeStore() + await themeStore.fetchThemes() + + const themes = themeStore.themes + if (themes.length === 0) { + return 'No hay temas disponibles' + } + + const systemThemes = themes.filter(t => t.is_system) + const userThemes = themes.filter(t => !t.is_system) + + let result = `Temas disponibles (${themes.length}):\n\n` + + if (systemThemes.length > 0) { + result += `[SISTEMA]\n` + result += systemThemes.map(t => + ` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}` + ).join('\n') + result += '\n\n' + } + + if (userThemes.length > 0) { + result += `[PERSONALIZADOS]\n` + result += userThemes.map(t => + ` - ${t.name} (${t.id})${t.is_default ? ' [DEFAULT]' : ''}` + ).join('\n') + } + + return result + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) + + // switch_theme + registerTool( + 'switch_theme', + 'Cambia al tema especificado por nombre o ID', + { + type: 'object', + properties: { + theme: { + type: 'string', + description: 'Nombre o ID del tema a activar' + } + }, + required: ['theme'] + }, + async (args: { theme: string }) => { + try { + const themeStore = useThemeStore() + await themeStore.fetchThemes() + + // Find theme by ID or name + const theme = themeStore.themes.find(t => + t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase() + ) + + if (!theme) { + const available = themeStore.themes.map(t => t.name).join(', ') + return `Tema "${args.theme}" no encontrado.\nDisponibles: ${available}` + } + + themeStore.selectTheme(theme) + return `Tema cambiado a "${theme.name}"\nID: ${theme.id}` + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) + + // set_default_theme + registerTool( + 'set_default_theme', + 'Establece un tema como el default (se cargará automáticamente al iniciar)', + { + type: 'object', + properties: { + theme: { + type: 'string', + description: 'Nombre o ID del tema a establecer como default' + } + }, + required: ['theme'] + }, + async (args: { theme: string }) => { + try { + const themeStore = useThemeStore() + await themeStore.fetchThemes() + + const theme = themeStore.themes.find(t => + t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase() + ) + + if (!theme) { + const available = themeStore.themes.map(t => t.name).join(', ') + return `Tema "${args.theme}" no encontrado.\nDisponibles: ${available}` + } + + await themeStore.setDefaultTheme(theme.id) + return `Tema "${theme.name}" establecido como default.\nSe cargará automáticamente al iniciar la aplicación.` + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) + + // delete_theme + registerTool( + 'delete_theme', + 'Elimina un tema personalizado (no se pueden eliminar temas del sistema)', + { + type: 'object', + properties: { + theme: { + type: 'string', + description: 'Nombre o ID del tema a eliminar' + } + }, + required: ['theme'] + }, + async (args: { theme: string }) => { + try { + const themeStore = useThemeStore() + await themeStore.fetchThemes() + + const theme = themeStore.themes.find(t => + t.id === args.theme || t.name.toLowerCase() === args.theme.toLowerCase() + ) + + if (!theme) { + return `Tema "${args.theme}" no encontrado` + } + + if (theme.is_system) { + return `No se puede eliminar "${theme.name}" porque es un tema del sistema` + } + + const success = await themeStore.deleteTheme(theme.id) + if (success) { + return `Tema "${theme.name}" eliminado correctamente` + } else { + return `Error al eliminar el tema "${theme.name}"` + } + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) + + // reset_theme + registerTool( + 'reset_theme', + 'Descarta todos los cambios no guardados y restaura el tema activo original', + { + type: 'object', + properties: {} + }, + () => { + try { + const themeStore = useThemeStore() + + if (!themeStore.previewTheme) { + return 'No hay cambios pendientes para descartar' + } + + const themeName = themeStore.activeTheme?.name || 'desconocido' + themeStore.resetPreview() + return `Cambios descartados. Tema "${themeName}" restaurado a su estado original.` + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) + + // export_theme + registerTool( + 'export_theme', + 'Exporta un tema como JSON para respaldo o compartir', + { + type: 'object', + properties: { + theme: { + type: 'string', + description: 'Nombre o ID del tema a exportar. Si no se especifica, exporta el tema activo.' + } + } + }, + async (args: { theme?: string }) => { + try { + const themeStore = useThemeStore() + + let theme = themeStore.activeTheme + + if (args.theme) { + await themeStore.fetchThemes() + theme = themeStore.themes.find(t => + t.id === args.theme || t.name.toLowerCase() === args.theme!.toLowerCase() + ) || null + } + + if (!theme) { + return args.theme + ? `Tema "${args.theme}" no encontrado` + : 'No hay tema activo para exportar' + } + + const exported = themeStore.exportTheme(theme) + return `Tema "${theme.name}" exportado:\n\n${exported}` + } catch (e: any) { + return `Error: ${e.message}` + } + } + ) } export function unregisterThemeTools() {