From 3a734f2426489f3254a4252cb9c5bd394bad2b40 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Fri, 13 Feb 2026 18:42:47 -0600 Subject: [PATCH] feat: Add terminal UI control tools for MCP - Add 5 terminal tools: open, close, toggle, move, resize - Create terminalHandlers.ts with UI control functions - Add terminal category to toolDefinitions and toolRegistry - Expose FloatingTerminal controls via defineExpose - Connect controls in App.vue via setTerminalControls - Fix ToolsDropdown missing terminal category --- frontend/src/App.vue | 41 ++++++++++++++++++- frontend/src/components/ToolsDropdown.vue | 3 +- frontend/src/services/toolRegistry.ts | 27 ++++++------ frontend/src/services/tools/handlers/index.ts | 4 +- .../src/services/tools/toolDefinitions.ts | 14 +++++-- 5 files changed, 71 insertions(+), 18 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 2e087be..b50fcab 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -10,11 +10,13 @@ import FloatingTerminal from './components/FloatingTerminal.vue' import PwaInstallBanner from './components/PwaInstallBanner.vue' import { initWebMCP, getWebMCP, startTokenPolling, stopTokenPolling, connectWithToken } from './services/webmcp' import { initToolRegistry, activatePageTools, initToolsOnRefresh } from './services/toolRegistry' +import { setTerminalControls } from './services/tools/handlers/terminalHandlers' import { useCanvasStore } from './stores/canvas' const route = useRoute() const router = useRouter() const showTerminal = ref(false) +const terminalRef = ref | null>(null) const canvasStore = useCanvasStore() type PageName = 'home' | 'canvas' | 'components' | 'themes' | 'projects' | 'project-canvas' | 'database' | 'source' | 'terminal' | 'tools' @@ -30,6 +32,43 @@ onMounted(async () => { const currentPage = (route.name as string) || 'canvas' initToolsOnRefresh(currentPage as PageName) + // Setup terminal controls for MCP tools + setTerminalControls({ + open: (x?: number, y?: number) => { + if (terminalRef.value) { + terminalRef.value.open(x, y) + } else { + showTerminal.value = true + } + }, + close: () => { + if (terminalRef.value) { + terminalRef.value.close() + } else { + showTerminal.value = false + } + }, + toggle: () => { + if (terminalRef.value) { + terminalRef.value.toggle() + } else { + showTerminal.value = !showTerminal.value + } + }, + move: (x: number, y: number) => { + terminalRef.value?.move(x, y) + }, + resize: (w: number, h: number) => { + terminalRef.value?.resize(w, h) + }, + getState: () => { + if (terminalRef.value) { + return terminalRef.value.getState() + } + return { isOpen: showTerminal.value, position: { x: 0, y: 0 }, size: { w: 580, h: 360 } } + } + }) + // Start polling for token if not connected const webmcp = getWebMCP() if (!webmcp?.isConnected) { @@ -94,7 +133,7 @@ watch(() => route.name, (newPage) => { - + diff --git a/frontend/src/components/ToolsDropdown.vue b/frontend/src/components/ToolsDropdown.vue index 3700d16..6d4a94a 100644 --- a/frontend/src/components/ToolsDropdown.vue +++ b/frontend/src/components/ToolsDropdown.vue @@ -21,7 +21,8 @@ const categoryTools: Record = { theme: ['get_design_tokens', 'get_active_theme', 'set_theme_variable', 'save_theme', 'list_themes', 'switch_theme', 'reset_theme'], database: ['list_tables', 'get_table_schema', 'get_table_data', 'get_database_stats', 'execute_query'], source: ['get_repo_info', 'list_repo_files', 'read_repo_file', 'search_repo_code'], - project: ['list_canvases', 'create_canvas', 'get_canvas', 'update_canvas', 'delete_canvas', 'clone_canvas', 'add_component_to_canvas', 'remove_component_from_canvas', 'get_canvas_components'] + project: ['list_canvases', 'create_canvas', 'get_canvas', 'update_canvas', 'delete_canvas', 'clone_canvas', 'add_component_to_canvas', 'remove_component_from_canvas', 'get_canvas_components'], + terminal: ['terminal_open', 'terminal_close', 'terminal_toggle', 'terminal_move', 'terminal_resize'] } const categories = computed(() => { diff --git a/frontend/src/services/toolRegistry.ts b/frontend/src/services/toolRegistry.ts index 5c14dc8..75122f6 100644 --- a/frontend/src/services/toolRegistry.ts +++ b/frontend/src/services/toolRegistry.ts @@ -19,6 +19,7 @@ import { createDatabaseHandlers, createProjectCanvasHandlers, createSourceCodeHandlers, + createTerminalHandlers, type ToolConfig } from './tools/handlers' import { setRouter } from './tools/handlers/globalHandlers' @@ -111,7 +112,8 @@ function getToolConfigs(): Map { ...createThemeHandlers(), ...createDatabaseHandlers(), ...createProjectCanvasHandlers(), - ...createSourceCodeHandlers() + ...createSourceCodeHandlers(), + ...createTerminalHandlers() ] for (const config of allHandlers) { @@ -129,21 +131,22 @@ const categoryTools: Record = { theme: ['get_design_tokens', 'get_active_theme', 'set_theme_variable', 'save_theme', 'list_themes', 'switch_theme', 'reset_theme'], database: ['list_tables', 'get_table_schema', 'get_table_data', 'get_database_stats', 'execute_query'], source: ['get_repo_info', 'list_repo_files', 'read_repo_file', 'search_repo_code'], - project: ['list_canvases', 'create_canvas', 'get_canvas', 'update_canvas', 'delete_canvas', 'clone_canvas', 'add_component_to_canvas', 'remove_component_from_canvas', 'get_canvas_components'] + project: ['list_canvases', 'create_canvas', 'get_canvas', 'update_canvas', 'delete_canvas', 'clone_canvas', 'add_component_to_canvas', 'remove_component_from_canvas', 'get_canvas_components'], + terminal: ['terminal_open', 'terminal_close', 'terminal_toggle', 'terminal_move', 'terminal_resize'] } // Page to categories mapping const pageCategories: Record = { - home: ['global', 'canvas', 'component', 'project'], - canvas: ['global', 'canvas', 'component'], - 'project-canvas': ['global', 'canvas', 'component', 'project'], - projects: ['global', 'project'], - components: ['global', 'component'], - themes: ['global', 'theme'], - database: ['global', 'database'], - source: ['global', 'source'], - terminal: ['global'], - tools: ['global'] + home: ['global', 'canvas', 'component', 'project', 'terminal'], + canvas: ['global', 'canvas', 'component', 'terminal'], + 'project-canvas': ['global', 'canvas', 'component', 'project', 'terminal'], + projects: ['global', 'project', 'terminal'], + components: ['global', 'component', 'terminal'], + themes: ['global', 'theme', 'terminal'], + database: ['global', 'database', 'terminal'], + source: ['global', 'source', 'terminal'], + terminal: ['global', 'terminal'], + tools: ['global', 'terminal'] } let currentPage: PageName | null = null diff --git a/frontend/src/services/tools/handlers/index.ts b/frontend/src/services/tools/handlers/index.ts index eebed19..dcb7589 100644 --- a/frontend/src/services/tools/handlers/index.ts +++ b/frontend/src/services/tools/handlers/index.ts @@ -10,13 +10,15 @@ export { createThemeHandlers } from './themeHandlers' export { createDatabaseHandlers } from './databaseHandlers' export { createProjectCanvasHandlers } from './projectCanvasHandlers' export { createSourceCodeHandlers } from './sourceCodeHandlers' +export { createTerminalHandlers, setTerminalControls } from './terminalHandlers' +export type { TerminalControls } from './terminalHandlers' export type ToolHandler = (args: any) => string | Promise export interface ToolConfig { name: string description: string - category: 'global' | 'canvas' | 'component' | 'theme' | 'database' | 'source' | 'project' + category: 'global' | 'canvas' | 'component' | 'theme' | 'database' | 'source' | 'project' | 'terminal' schema: object handler: ToolHandler } diff --git a/frontend/src/services/tools/toolDefinitions.ts b/frontend/src/services/tools/toolDefinitions.ts index 9c5fbe0..d74dd6d 100644 --- a/frontend/src/services/tools/toolDefinitions.ts +++ b/frontend/src/services/tools/toolDefinitions.ts @@ -1,4 +1,4 @@ -export type ToolCategory = 'global' | 'canvas' | 'component' | 'theme' | 'database' | 'source' | 'project' +export type ToolCategory = 'global' | 'canvas' | 'component' | 'theme' | 'database' | 'source' | 'project' | 'terminal' export interface ToolMeta { name: string @@ -57,7 +57,14 @@ export const ALL_TOOL_METAS: ToolMeta[] = [ { name: 'clone_canvas', description: 'Clona un canvas existente', category: 'project' }, { name: 'add_component_to_canvas', description: 'Agrega un componente a un canvas', category: 'project' }, { name: 'remove_component_from_canvas', description: 'Remueve un componente de un canvas', category: 'project' }, - { name: 'get_canvas_components', description: 'Obtiene los componentes de un canvas', category: 'project' } + { name: 'get_canvas_components', description: 'Obtiene los componentes de un canvas', category: 'project' }, + + // Terminal UI tools + { name: 'terminal_open', description: 'Abre la ventana flotante del terminal', category: 'terminal' }, + { name: 'terminal_close', description: 'Cierra la ventana flotante del terminal', category: 'terminal' }, + { name: 'terminal_toggle', description: 'Alterna abrir/cerrar el terminal', category: 'terminal' }, + { name: 'terminal_move', description: 'Mueve la ventana del terminal a una posicion', category: 'terminal' }, + { name: 'terminal_resize', description: 'Cambia el tamano de la ventana del terminal', category: 'terminal' } ] // Get all tool names @@ -83,5 +90,6 @@ export const CATEGORY_INFO: Record