Rene Fichtmueller a290216183 feat: RTK integration — sync SQLite stats to TokenVault
- @tokenvault/rtk-bridge: Reads ~/Library/Application Support/rtk/history.db
  and syncs new commands to /v1/rtk/stats (stateful, batched, idempotent)
- Core: rtk_commands table + 4 endpoints (/v1/rtk/stats, /rtk/commands, /rtk/hosts)
- Dashboard: new RTK Savings tab with 6 KPI cards + top commands + host breakdown
- Multi-host aggregation: sync from Mac Studio, Mac Mini, MacBooks etc.
- First sync: 753 commands, 3.5M tokens saved aggregated

RTK is MIT-licensed (github.com/rtk-ai/rtk) — we use it as the compression
engine and add the missing pieces: central tracking, team attribution,
cross-machine dashboards, long-term trend analysis.
2026-04-14 21:08:59 +02:00

141 lines
5.0 KiB
TypeScript

import type { FastifyInstance } from 'fastify';
import { query } from '../db/client.js';
import { logger } from '../observability/logger.js';
interface RtkStatsBody {
host: string;
commands: Array<{
rtk_id: number;
timestamp: string;
original_cmd: string;
rtk_cmd: string;
input_tokens: number;
output_tokens: number;
saved_tokens: number;
savings_pct: number;
exec_time_ms: number;
project_path: string;
}>;
}
export async function rtkRoutes(app: FastifyInstance): Promise<void> {
// ─── Ingest RTK stats from client machines ───────────────────────────
app.post<{ Body: RtkStatsBody }>('/v1/rtk/stats', async (req, reply) => {
const { host, commands } = req.body;
if (!host || !Array.isArray(commands)) {
reply.code(400);
return { error: 'host and commands array required' };
}
let inserted = 0;
for (const cmd of commands) {
try {
const result = await query(
`INSERT INTO rtk_commands (
rtk_id, host, timestamp, original_cmd, rtk_cmd,
input_tokens, output_tokens, saved_tokens, savings_pct,
exec_time_ms, project_path
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
ON CONFLICT (host, rtk_id) DO NOTHING`,
[
cmd.rtk_id, host, cmd.timestamp, cmd.original_cmd, cmd.rtk_cmd,
cmd.input_tokens, cmd.output_tokens, cmd.saved_tokens, cmd.savings_pct,
cmd.exec_time_ms, cmd.project_path,
],
);
if (result.rowCount && result.rowCount > 0) inserted += 1;
} catch (err) {
logger.warn({ err, rtk_id: cmd.rtk_id }, 'Failed to insert RTK command');
}
}
logger.info({ host, received: commands.length, inserted }, 'RTK stats ingested');
return { received: commands.length, inserted };
});
// ─── Aggregate stats (all hosts) ──────────────────────────────────────
app.get<{ Querystring: { period?: string } }>('/v1/rtk/stats', async (req) => {
const intervals: Record<string, string> = {
today: "timestamp >= CURRENT_DATE",
week: "timestamp >= CURRENT_DATE - INTERVAL '7 days'",
month: "timestamp >= CURRENT_DATE - INTERVAL '30 days'",
all: '1=1',
};
const where = intervals[req.query.period ?? 'all'] ?? intervals['all']!;
const result = await query<{
total_commands: string; total_input: string; total_output: string;
total_saved: string; avg_savings: string; hosts: string; projects: string;
}>(`SELECT
COUNT(*) as total_commands,
COALESCE(SUM(input_tokens), 0) as total_input,
COALESCE(SUM(output_tokens), 0) as total_output,
COALESCE(SUM(saved_tokens), 0) as total_saved,
COALESCE(AVG(savings_pct), 0) as avg_savings,
COUNT(DISTINCT host) as hosts,
COUNT(DISTINCT project_path) as projects
FROM rtk_commands WHERE ${where}`);
const row = result.rows[0]!;
return {
period: req.query.period ?? 'all',
total_commands: parseInt(row.total_commands, 10),
total_input_tokens: parseInt(row.total_input, 10),
total_output_tokens: parseInt(row.total_output, 10),
total_saved_tokens: parseInt(row.total_saved, 10),
avg_savings_pct: parseFloat(row.avg_savings),
unique_hosts: parseInt(row.hosts, 10),
unique_projects: parseInt(row.projects, 10),
};
});
// ─── Top commands by savings ──────────────────────────────────────────
app.get('/v1/rtk/commands', async () => {
const result = await query<{
cmd: string; count: string; saved: string; avg_pct: string;
}>(`SELECT
split_part(rtk_cmd, ' ', 1) || ' ' || split_part(rtk_cmd, ' ', 2) as cmd,
COUNT(*) as count,
COALESCE(SUM(saved_tokens), 0) as saved,
COALESCE(AVG(savings_pct), 0) as avg_pct
FROM rtk_commands
WHERE timestamp >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY cmd
ORDER BY saved DESC
LIMIT 20`);
return {
commands: result.rows.map(r => ({
cmd: r.cmd,
count: parseInt(r.count, 10),
saved_tokens: parseInt(r.saved, 10),
avg_savings_pct: parseFloat(r.avg_pct),
})),
};
});
// ─── Per-host breakdown ───────────────────────────────────────────────
app.get('/v1/rtk/hosts', async () => {
const result = await query<{
host: string; count: string; saved: string; last_seen: string;
}>(`SELECT
host,
COUNT(*) as count,
COALESCE(SUM(saved_tokens), 0) as saved,
MAX(timestamp) as last_seen
FROM rtk_commands
GROUP BY host
ORDER BY saved DESC`);
return {
hosts: result.rows.map(r => ({
host: r.host,
commands: parseInt(r.count, 10),
saved_tokens: parseInt(r.saved, 10),
last_seen: r.last_seen,
})),
};
});
}