import { Database } from 'bun:sqlite' const PORT_HTTP = 4101 // Inicializar base de datos const db = new Database('agent-ui.db') db.run(` CREATE TABLE IF NOT EXISTS history ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT DEFAULT CURRENT_TIMESTAMP, tool_name TEXT NOT NULL, args TEXT, result TEXT ) `) db.run(` CREATE TABLE IF NOT EXISTS config ( key TEXT PRIMARY KEY, value TEXT ) `) // Tabla para componentes Vue dinĂ¡micos db.run(` CREATE TABLE IF NOT EXISTS vue_components ( id TEXT PRIMARY KEY, name TEXT NOT NULL, template TEXT NOT NULL, setup TEXT, style TEXT, props TEXT, imports TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT DEFAULT CURRENT_TIMESTAMP ) `) console.log('[DB] SQLite inicializado: agent-ui.db') // API HTTP solamente - WebSocket lo maneja webmcp Bun.serve({ port: PORT_HTTP, async fetch(req) { const url = new URL(req.url) // CORS headers const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type' } if (req.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }) } // API Routes if (url.pathname === '/api/history') { if (req.method === 'GET') { const limit = parseInt(url.searchParams.get('limit') || '50') const rows = db.query('SELECT * FROM history ORDER BY id DESC LIMIT ?').all(limit) return Response.json(rows, { headers: corsHeaders }) } if (req.method === 'POST') { const body = await req.json() const stmt = db.prepare('INSERT INTO history (tool_name, args, result) VALUES (?, ?, ?)') stmt.run(body.tool_name, JSON.stringify(body.args), body.result) return Response.json({ success: true }, { headers: corsHeaders }) } if (req.method === 'DELETE') { db.run('DELETE FROM history') return Response.json({ success: true }, { headers: corsHeaders }) } } if (url.pathname === '/api/config') { if (req.method === 'GET') { const key = url.searchParams.get('key') if (key) { const row = db.query('SELECT value FROM config WHERE key = ?').get(key) as { value: string } | null return Response.json({ value: row?.value || null }, { headers: corsHeaders }) } const rows = db.query('SELECT * FROM config').all() return Response.json(rows, { headers: corsHeaders }) } if (req.method === 'POST') { const body = await req.json() const stmt = db.prepare('INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)') stmt.run(body.key, body.value) return Response.json({ success: true }, { headers: corsHeaders }) } } if (url.pathname === '/api/health') { return Response.json({ status: 'ok', timestamp: new Date().toISOString() }, { headers: corsHeaders }) } // API de Componentes Vue if (url.pathname === '/api/components') { if (req.method === 'GET') { const rows = db.query('SELECT * FROM vue_components ORDER BY updated_at DESC').all() return Response.json(rows, { headers: corsHeaders }) } if (req.method === 'POST') { const body = await req.json() const id = body.id || `comp-${Date.now()}` const stmt = db.prepare(` INSERT OR REPLACE INTO vue_components (id, name, template, setup, style, props, imports, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP) `) stmt.run( id, body.name, body.template, body.setup || '', body.style || '', JSON.stringify(body.props || []), JSON.stringify(body.imports || []) ) return Response.json({ success: true, id }, { headers: corsHeaders }) } if (req.method === 'DELETE') { db.run('DELETE FROM vue_components') return Response.json({ success: true }, { headers: corsHeaders }) } } // Obtener componente por ID if (url.pathname.startsWith('/api/components/')) { const id = url.pathname.split('/').pop() if (req.method === 'GET') { const row = db.query('SELECT * FROM vue_components WHERE id = ?').get(id) if (!row) { return Response.json({ error: 'Component not found' }, { status: 404, headers: corsHeaders }) } return Response.json(row, { headers: corsHeaders }) } if (req.method === 'DELETE') { db.run('DELETE FROM vue_components WHERE id = ?', [id]) return Response.json({ success: true }, { headers: corsHeaders }) } } return new Response('Not Found', { status: 404, headers: corsHeaders }) } }) console.log(`[HTTP] API corriendo en http://localhost:${PORT_HTTP}`) console.log('') console.log('='.repeat(50)) console.log('Agent UI API Server iniciado') console.log(` API: http://localhost:${PORT_HTTP}`) console.log('') console.log('WebMCP se inicia por separado con Claude Code MCP') console.log('='.repeat(50))