Rene Fichtmueller d43b9f5298 feat: TokenVault MVP — hybrid MCP + proxy for LLM token savings
4-package monorepo:
- @tokenvault/core: Fastify 5.x proxy server, 7-stage pipeline,
  3 provider adapters (Anthropic, OpenAI, Ollama), PostgreSQL
  ticket system, cost calculator with real provider pricing
- @tokenvault/mcp: MCP server (stdio) with tv_ticket, tv_cost,
  tv_health tools for IDE integration
- @tokenvault/client: TypeScript SDK with createTokenVaultClient()
- @tokenvault/dashboard: Single-file HTML dashboard with MAGATAMA
  CI style (indigo #6366f1), bilingual DE+EN, 4 tabs

OpenAI-compatible proxy at /v1/chat/completions — drop-in replacement.
Every LLM request becomes a trackable ticket (TV-00001).
2026-04-14 10:10:22 +02:00

52 lines
1.5 KiB
TypeScript

import Fastify from 'fastify';
import fastifyStatic from '@fastify/static';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const PORT = parseInt(process.env['PORT'] ?? '3301', 10);
const CORE_URL = process.env['TOKENVAULT_CORE_URL'] ?? 'http://localhost:3300';
const app = Fastify({ logger: false });
// Serve static dashboard HTML
await app.register(fastifyStatic, {
root: join(__dirname, '..', 'public'),
prefix: '/',
});
// Proxy API requests to core
app.get('/api/health', async () => {
const res = await fetch(`${CORE_URL}/health`);
return res.json();
});
app.get('/api/tickets', async (req) => {
const qs = new URL(req.url, 'http://localhost').search;
const res = await fetch(`${CORE_URL}/v1/tickets${qs}`);
return res.json();
});
app.get('/api/tickets/stats', async (req) => {
const qs = new URL(req.url, 'http://localhost').search;
const res = await fetch(`${CORE_URL}/v1/tickets/stats${qs}`);
return res.json();
});
app.get('/api/cost', async (req) => {
const qs = new URL(req.url, 'http://localhost').search;
const res = await fetch(`${CORE_URL}/v1/cost${qs}`);
return res.json();
});
app.get('/api/cost/breakdown', async (req) => {
const qs = new URL(req.url, 'http://localhost').search;
const res = await fetch(`${CORE_URL}/v1/cost/breakdown${qs}`);
return res.json();
});
await app.listen({ port: PORT, host: '0.0.0.0' });
console.log(`TokenVault Dashboard running on http://localhost:${PORT}`);