Files
agent-ui/server/routes/index.ts
josedario87 c98f3e2b99 refactor: Use dedicated WebSocket server for torch sync
- Add torch WebSocket server on port 4106
- Remove HTTP polling, use WebSocket for instant sync
- Torch state changes broadcast immediately to all clients
- Auto-reconnect on disconnect
- Add port 4106 to kill-ports script
2026-02-14 16:40:40 -06:00

239 lines
6.7 KiB
TypeScript

import { optionsResponse, notFoundResponse } from '../utils/cors'
import { handleHistory } from './history'
import { handleConfig, handleHealth } from './config'
import { handleWebMCPToken, handleWebMCPRequestToken } from './webmcp'
import { handleComponents, handleComponentById, handleComponentUsage } from './components'
import { handleThemes, handleActiveTheme, handleDesignTokens, handleThemeById, handleThemeExport } from './themes'
import { handleCanvas, handleCanvasById, handleToolbarCanvas, handleDefaultCanvas, handleCanvasComponents, handleCanvasComponentById } from './canvas'
import { handleGiteaRepo, handleGiteaTree, handleGiteaFile } from './gitea'
import { handleTables, handleStats, handleTableSchema, handleTableData, handleQuery } from './database'
import { handleWhisperRoutes } from './whisper'
import { handleRecordingsRoutes } from './recordings'
import { handleClaudeStatus } from './claude-status'
import { handleGitStatus, handleGitDiff, handleGitLog, handleGitLogCommit, handleGitCompare, handleGitBranches, handleGitCurrentBranch, handleGitTree, handleGitFile } from './git'
export async function handleRequest(req: Request): Promise<Response> {
const url = new URL(req.url)
const path = url.pathname
// CORS preflight
if (req.method === 'OPTIONS') {
return optionsResponse()
}
// Health
if (path === '/api/health') {
return handleHealth()
}
// History
if (path === '/api/history') {
const res = await handleHistory(req, url)
if (res) return res
}
// Config
if (path === '/api/config') {
const res = await handleConfig(req, url)
if (res) return res
}
// WebMCP Token (for polling - legacy)
if (path === '/api/webmcp-token') {
const res = await handleWebMCPToken(req)
if (res) return res
}
// WebMCP Request Token (direct request to WebMCP server)
if (path === '/api/webmcp-request-token') {
const res = await handleWebMCPRequestToken(req)
if (res) return res
}
// Claude Code status (thinking/idle)
if (path === '/api/claude-status') {
const res = await handleClaudeStatus(req)
if (res) return res
}
// Components
if (path === '/api/components') {
const res = await handleComponents(req)
if (res) return res
}
// Component usage
const componentUsageMatch = path.match(/^\/api\/components\/([^/]+)\/usage$/)
if (componentUsageMatch && req.method === 'GET') {
return handleComponentUsage(componentUsageMatch[1])
}
// Component by ID
if (path.startsWith('/api/components/') && !path.includes('/usage')) {
const id = path.split('/').pop()!
const res = await handleComponentById(req, id)
if (res) return res
}
// Themes
if (path === '/api/themes') {
const res = await handleThemes(req)
if (res) return res
}
if (path === '/api/themes/active') {
return handleActiveTheme()
}
if (path === '/api/design-tokens') {
return handleDesignTokens()
}
// Theme export
if (path.startsWith('/api/themes/export/')) {
const id = path.split('/').pop()!
if (req.method === 'GET') {
return handleThemeExport(id)
}
}
// Theme by ID
if (path.startsWith('/api/themes/') && !path.includes('/active') && !path.includes('/export')) {
const pathParts = path.split('/')
const id = pathParts[3]
const action = pathParts[4]
const res = await handleThemeById(req, id, action)
if (res) return res
}
// Canvas toolbar
if (path === '/api/canvas/toolbar') {
return handleToolbarCanvas()
}
// Canvas default
if (path === '/api/canvas/default') {
return handleDefaultCanvas()
}
// Canvas list/create
if (path === '/api/canvas') {
const res = await handleCanvas(req)
if (res) return res
}
// Canvas components
const canvasComponentsMatch = path.match(/^\/api\/canvas\/([^/]+)\/components\/?$/)
if (canvasComponentsMatch) {
const res = await handleCanvasComponents(req, canvasComponentsMatch[1])
if (res) return res
}
// Canvas component by ID
const canvasComponentMatch = path.match(/^\/api\/canvas\/([^/]+)\/components\/([^/]+)$/)
if (canvasComponentMatch) {
const res = await handleCanvasComponentById(req, canvasComponentMatch[1], canvasComponentMatch[2])
if (res) return res
}
// Canvas by ID
if (path.startsWith('/api/canvas/') && !path.includes('/components')) {
const pathParts = path.split('/')
const id = pathParts[3]
const action = pathParts[4]
const res = await handleCanvasById(req, id, action)
if (res) return res
}
// Gitea
if (path === '/api/gitea/repo' && req.method === 'POST') {
return handleGiteaRepo(req)
}
if (path === '/api/gitea/tree' && req.method === 'POST') {
return handleGiteaTree(req)
}
if (path === '/api/gitea/file' && req.method === 'POST') {
return handleGiteaFile(req)
}
// Database Explorer
if (path === '/api/database/tables') {
return handleTables()
}
if (path === '/api/database/stats') {
return handleStats()
}
// Table schema
const tableSchemaMatch = path.match(/^\/api\/database\/tables\/([^/]+)\/schema$/)
if (tableSchemaMatch && req.method === 'GET') {
return handleTableSchema(decodeURIComponent(tableSchemaMatch[1]))
}
// Table data
const tableDataMatch = path.match(/^\/api\/database\/tables\/([^/]+)\/data$/)
if (tableDataMatch && req.method === 'GET') {
return handleTableData(decodeURIComponent(tableDataMatch[1]), url)
}
// Database query
if (path === '/api/database/query' && req.method === 'POST') {
return handleQuery(req)
}
// Whisper (GPU speech-to-text)
if (path.startsWith('/api/whisper/')) {
const res = await handleWhisperRoutes(req)
if (res) return res
}
// Voice recordings (for training custom models)
if (path.startsWith('/api/recordings')) {
const res = await handleRecordingsRoutes(req)
if (res) return res
}
// Git
if (path === '/api/git/status' && req.method === 'GET') {
return handleGitStatus()
}
if (path === '/api/git/diff' && req.method === 'GET') {
return handleGitDiff(url)
}
if (path === '/api/git/log' && req.method === 'GET') {
return handleGitLog(url)
}
const gitLogCommitMatch = path.match(/^\/api\/git\/log\/([a-f0-9]+)$/)
if (gitLogCommitMatch && req.method === 'GET') {
return handleGitLogCommit(gitLogCommitMatch[1])
}
if (path === '/api/git/compare' && req.method === 'POST') {
return handleGitCompare(req)
}
if (path === '/api/git/branches' && req.method === 'GET') {
return handleGitBranches()
}
if (path === '/api/git/branch/current' && req.method === 'GET') {
return handleGitCurrentBranch()
}
if (path === '/api/git/tree' && req.method === 'GET') {
return handleGitTree(url)
}
if (path === '/api/git/file' && req.method === 'GET') {
return handleGitFile(url)
}
return notFoundResponse()
}