- Add ToolsPage for managing MCP tools activation and persistence - Centralize all tool handlers in services/tools/handlers/ - toolRegistry.ts is now the single source of truth for tool state - Add tools store for pinned tools (persisted in localStorage) - Tools can be pinned to stay active across page navigation - Remove old individual tool files, replaced by centralized handlers
212 lines
7.0 KiB
TypeScript
212 lines
7.0 KiB
TypeScript
import type { ToolConfig } from './index'
|
|
import { useThemeStore } from '../../../stores/theme'
|
|
|
|
export function createThemeHandlers(): ToolConfig[] {
|
|
return [
|
|
{
|
|
name: 'get_design_tokens',
|
|
description: 'Obtiene los design tokens del tema activo',
|
|
category: 'theme',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
category: {
|
|
type: 'string',
|
|
enum: ['all', 'colors', 'text', 'accent', 'semantic', 'spacing', 'typography', 'effects'],
|
|
description: 'Categoria de tokens'
|
|
}
|
|
}
|
|
},
|
|
handler: async (args: { category?: string }) => {
|
|
const themeStore = useThemeStore()
|
|
const theme = themeStore.activeTheme
|
|
|
|
if (!theme) {
|
|
return 'No hay tema activo'
|
|
}
|
|
|
|
const category = args.category || 'all'
|
|
const variables = theme.variables
|
|
|
|
if (category !== 'all' && variables[category as keyof typeof variables]) {
|
|
const categoryVars = variables[category as keyof typeof variables]
|
|
const tokenList = Object.entries(categoryVars)
|
|
.map(([name, value]) => `--${name}: ${value}`)
|
|
.join('\n')
|
|
return `Design Tokens - ${category.toUpperCase()}:\n\n${tokenList}`
|
|
}
|
|
|
|
const allTokens = Object.entries(variables)
|
|
.map(([cat, vars]) => {
|
|
const tokenList = Object.entries(vars as Record<string, string>)
|
|
.map(([name, value]) => ` --${name}: ${value}`)
|
|
.join('\n')
|
|
return `[${cat.toUpperCase()}]\n${tokenList}`
|
|
})
|
|
.join('\n\n')
|
|
|
|
return `Design Tokens del tema "${theme.name}":\n\n${allTokens}`
|
|
}
|
|
},
|
|
{
|
|
name: 'get_active_theme',
|
|
description: 'Obtiene info del tema activo',
|
|
category: 'theme',
|
|
schema: { type: 'object', properties: {} },
|
|
handler: () => {
|
|
const themeStore = useThemeStore()
|
|
const theme = themeStore.activeTheme
|
|
|
|
if (!theme) return 'No hay tema activo'
|
|
|
|
return `Tema activo: "${theme.name}"\n` +
|
|
`ID: ${theme.id}\n` +
|
|
`Sistema: ${theme.is_system ? 'Si' : 'No'}\n` +
|
|
`Default: ${theme.is_default ? 'Si' : 'No'}`
|
|
}
|
|
},
|
|
{
|
|
name: 'set_theme_variable',
|
|
description: 'Modifica una variable CSS del tema',
|
|
category: 'theme',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string', description: 'Nombre de la variable sin --' },
|
|
value: { type: 'string', description: 'Nuevo valor' }
|
|
},
|
|
required: ['name', 'value']
|
|
},
|
|
handler: (args: { name: string; value: string }) => {
|
|
const themeStore = useThemeStore()
|
|
const root = document.documentElement
|
|
const varName = args.name.startsWith('--') ? args.name : `--${args.name}`
|
|
const keyName = args.name.startsWith('--') ? args.name.slice(2) : args.name
|
|
|
|
const currentValue = getComputedStyle(root).getPropertyValue(varName).trim()
|
|
root.style.setProperty(varName, args.value)
|
|
|
|
if (themeStore.activeTheme) {
|
|
const variables = themeStore.activeTheme.variables
|
|
for (const category of Object.keys(variables) as (keyof typeof variables)[]) {
|
|
if (keyName in variables[category]) {
|
|
themeStore.updateVariable(category, keyName, args.value)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return `Variable ${varName} cambiada:\n Anterior: ${currentValue || '(no definida)'}\n Nuevo: ${args.value}`
|
|
}
|
|
},
|
|
{
|
|
name: 'save_theme',
|
|
description: 'Guarda el tema actual',
|
|
category: 'theme',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string', description: 'Nombre del tema' },
|
|
description: { type: 'string', description: 'Descripcion' },
|
|
setAsDefault: { type: 'boolean', description: 'Establecer como default' }
|
|
},
|
|
required: ['name']
|
|
},
|
|
handler: async (args: { name: string; description?: string; setAsDefault?: boolean }) => {
|
|
const themeStore = useThemeStore()
|
|
const variablesToSave = themeStore.previewTheme || themeStore.activeTheme?.variables
|
|
|
|
if (!variablesToSave) {
|
|
return 'Error: No hay variables para guardar'
|
|
}
|
|
|
|
const result = await themeStore.saveTheme({
|
|
name: args.name,
|
|
description: args.description || `Tema creado el ${new Date().toLocaleString()}`,
|
|
variables: variablesToSave,
|
|
metadata: { author: 'Claude', version: '1.0', base: themeStore.activeTheme?.id || null }
|
|
})
|
|
|
|
if (args.setAsDefault && result.id) {
|
|
await themeStore.setDefaultTheme(result.id)
|
|
return `Tema "${args.name}" guardado y establecido como default. ID: ${result.id}`
|
|
}
|
|
|
|
return `Tema "${args.name}" guardado. ID: ${result.id}`
|
|
}
|
|
},
|
|
{
|
|
name: 'list_themes',
|
|
description: 'Lista todos los temas disponibles',
|
|
category: 'theme',
|
|
schema: { type: 'object', properties: {} },
|
|
handler: async () => {
|
|
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.is_default ? ' [DEFAULT]' : ''}`).join('\n')
|
|
result += '\n\n'
|
|
}
|
|
|
|
if (userThemes.length > 0) {
|
|
result += `[PERSONALIZADOS]\n`
|
|
result += userThemes.map(t => ` - ${t.name}${t.is_default ? ' [DEFAULT]' : ''}`).join('\n')
|
|
}
|
|
|
|
return result
|
|
}
|
|
},
|
|
{
|
|
name: 'switch_theme',
|
|
description: 'Cambia al tema especificado',
|
|
category: 'theme',
|
|
schema: {
|
|
type: 'object',
|
|
properties: {
|
|
theme: { type: 'string', description: 'Nombre o ID del tema' }
|
|
},
|
|
required: ['theme']
|
|
},
|
|
handler: async (args: { theme: string }) => {
|
|
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`
|
|
}
|
|
|
|
themeStore.selectTheme(theme)
|
|
return `Tema cambiado a "${theme.name}"`
|
|
}
|
|
},
|
|
{
|
|
name: 'reset_theme',
|
|
description: 'Descarta cambios no guardados',
|
|
category: 'theme',
|
|
schema: { type: 'object', properties: {} },
|
|
handler: () => {
|
|
const themeStore = useThemeStore()
|
|
if (!themeStore.previewTheme) {
|
|
return 'No hay cambios pendientes'
|
|
}
|
|
themeStore.resetPreview()
|
|
return 'Cambios descartados'
|
|
}
|
|
}
|
|
]
|
|
}
|