@tokentop/ttop 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +2 -5
  2. package/package.json +8 -5
  3. package/src/agents/aggregator.ts +39 -19
  4. package/src/agents/costing.ts +11 -9
  5. package/src/agents/index.ts +7 -9
  6. package/src/agents/types.ts +2 -2
  7. package/src/cli.ts +28 -23
  8. package/src/config/schema.test.ts +42 -40
  9. package/src/config/schema.ts +26 -26
  10. package/src/demo/simulator.ts +161 -122
  11. package/src/plugins/agents/index.ts +2 -2
  12. package/src/plugins/auth-sources.ts +42 -38
  13. package/src/plugins/lifecycle.ts +32 -32
  14. package/src/plugins/loader.test.ts +49 -49
  15. package/src/plugins/loader.ts +67 -63
  16. package/src/plugins/notification-bus.ts +21 -16
  17. package/src/plugins/notifications/index.ts +2 -2
  18. package/src/plugins/notifications/terminal-bell.ts +29 -23
  19. package/src/plugins/notifications/visual-flash.ts +21 -19
  20. package/src/plugins/npm-installer.ts +23 -25
  21. package/src/plugins/plugin-context-factory.ts +10 -10
  22. package/src/plugins/plugin-host.ts +12 -5
  23. package/src/plugins/providers/anthropic.ts +64 -57
  24. package/src/plugins/providers/antigravity.ts +81 -69
  25. package/src/plugins/providers/codex.ts +42 -42
  26. package/src/plugins/providers/gemini.ts +106 -87
  27. package/src/plugins/providers/github-copilot.ts +49 -45
  28. package/src/plugins/providers/index.ts +10 -12
  29. package/src/plugins/providers/minimax.ts +50 -44
  30. package/src/plugins/providers/openai-api.ts +82 -62
  31. package/src/plugins/providers/opencode-zen.ts +46 -39
  32. package/src/plugins/providers/perplexity.ts +55 -46
  33. package/src/plugins/providers/zai.ts +66 -57
  34. package/src/plugins/registry.ts +47 -43
  35. package/src/plugins/sandbox-guard.test.ts +45 -48
  36. package/src/plugins/sandbox-guard.ts +20 -25
  37. package/src/plugins/sandbox.ts +26 -48
  38. package/src/plugins/themes/catppuccin-latte.ts +29 -29
  39. package/src/plugins/themes/catppuccin-mocha.ts +29 -29
  40. package/src/plugins/themes/claude-code.ts +29 -29
  41. package/src/plugins/themes/dracula.ts +29 -29
  42. package/src/plugins/themes/github-light.ts +29 -29
  43. package/src/plugins/themes/gruvbox-dark.ts +29 -29
  44. package/src/plugins/themes/gruvbox-light.ts +29 -29
  45. package/src/plugins/themes/index.ts +15 -15
  46. package/src/plugins/themes/kanagawa.ts +29 -29
  47. package/src/plugins/themes/nord.ts +29 -29
  48. package/src/plugins/themes/one-dark.ts +29 -29
  49. package/src/plugins/themes/opencode.ts +31 -31
  50. package/src/plugins/themes/rose-pine-dawn.ts +29 -29
  51. package/src/plugins/themes/rose-pine.ts +29 -29
  52. package/src/plugins/themes/solarized-light.ts +29 -29
  53. package/src/plugins/themes/tokyo-night.ts +29 -29
  54. package/src/plugins/types/agent.ts +5 -5
  55. package/src/plugins/types/base.ts +35 -24
  56. package/src/plugins/types/index.ts +9 -9
  57. package/src/plugins/types/notification.ts +12 -12
  58. package/src/plugins/types/provider.ts +12 -8
  59. package/src/plugins/types/theme.ts +31 -23
  60. package/src/plugins/update-checker.ts +6 -6
  61. package/src/pricing/estimator.test.ts +39 -44
  62. package/src/pricing/estimator.ts +7 -13
  63. package/src/pricing/fallback.test.ts +30 -34
  64. package/src/pricing/fallback.ts +54 -27
  65. package/src/pricing/index.ts +18 -12
  66. package/src/pricing/models-dev.ts +6 -6
  67. package/src/storage/database.ts +56 -46
  68. package/src/storage/db.ts +12 -12
  69. package/src/storage/index.ts +44 -45
  70. package/src/storage/migrations/index.ts +2 -2
  71. package/src/storage/paths.ts +13 -13
  72. package/src/storage/repos/agentSessions.ts +33 -23
  73. package/src/storage/repos/providerSnapshots.ts +5 -5
  74. package/src/storage/repos/usageEvents.ts +40 -28
  75. package/src/storage/types.ts +5 -5
  76. package/src/tui/App.tsx +180 -137
  77. package/src/tui/components/CommandPalette.tsx +46 -34
  78. package/src/tui/components/DebugConsole.tsx +39 -33
  79. package/src/tui/components/DebugPanel.tsx +295 -177
  80. package/src/tui/components/FooterHints.tsx +2 -2
  81. package/src/tui/components/GhostProviderCard.tsx +37 -35
  82. package/src/tui/components/Header.tsx +68 -35
  83. package/src/tui/components/HelpOverlay.tsx +99 -29
  84. package/src/tui/components/InlineGauge.tsx +10 -7
  85. package/src/tui/components/InlineSparkline.tsx +17 -11
  86. package/src/tui/components/KpiStrip.tsx +128 -98
  87. package/src/tui/components/LimitGauge.tsx +96 -59
  88. package/src/tui/components/ModalBackdrop.tsx +4 -4
  89. package/src/tui/components/ProviderAggregateStrip.tsx +69 -38
  90. package/src/tui/components/ProviderCard.tsx +232 -226
  91. package/src/tui/components/ProviderDetailPanel.tsx +133 -58
  92. package/src/tui/components/ProviderLimitsPanel.tsx +126 -89
  93. package/src/tui/components/ProvidersList.tsx +215 -126
  94. package/src/tui/components/SessionDetailsDrawer.tsx +191 -94
  95. package/src/tui/components/SessionsTable.tsx +313 -166
  96. package/src/tui/components/SettingsModal.tsx +231 -214
  97. package/src/tui/components/SidebarBreakdown.tsx +30 -16
  98. package/src/tui/components/Skeleton.tsx +24 -17
  99. package/src/tui/components/SmartSidebar.tsx +360 -258
  100. package/src/tui/components/Sparkline.tsx +64 -52
  101. package/src/tui/components/Spinner.tsx +3 -3
  102. package/src/tui/components/StatusBar.tsx +27 -27
  103. package/src/tui/components/ThemePicker.tsx +67 -66
  104. package/src/tui/components/Toast.tsx +9 -6
  105. package/src/tui/components/UsageGauge.tsx +10 -13
  106. package/src/tui/components/index.ts +5 -5
  107. package/src/tui/contexts/AgentSessionContext.tsx +193 -144
  108. package/src/tui/contexts/ConfigContext.tsx +15 -13
  109. package/src/tui/contexts/DashboardRuntimeContext.tsx +26 -26
  110. package/src/tui/contexts/DemoModeContext.tsx +22 -15
  111. package/src/tui/contexts/DrawerContext.tsx +11 -9
  112. package/src/tui/contexts/InputContext.tsx +2 -2
  113. package/src/tui/contexts/LogContext.tsx +62 -47
  114. package/src/tui/contexts/PluginContext.tsx +232 -183
  115. package/src/tui/contexts/RealTimeActivityContext.tsx +70 -36
  116. package/src/tui/contexts/StorageContext.tsx +151 -117
  117. package/src/tui/contexts/ThemeContext.tsx +21 -16
  118. package/src/tui/contexts/TimeWindowContext.tsx +72 -61
  119. package/src/tui/contexts/ToastContext.tsx +10 -7
  120. package/src/tui/contexts/index.ts +9 -5
  121. package/src/tui/createApp.tsx +8 -12
  122. package/src/tui/debug/captureFrame.ts +25 -28
  123. package/src/tui/debug/snapshot.tsx +179 -162
  124. package/src/tui/driver/assertions.ts +30 -22
  125. package/src/tui/driver/cli.ts +231 -221
  126. package/src/tui/driver/coverage.ts +27 -44
  127. package/src/tui/driver/demo-snapshot.ts +33 -33
  128. package/src/tui/driver/diff.ts +26 -32
  129. package/src/tui/driver/driver.ts +43 -48
  130. package/src/tui/driver/index.ts +36 -40
  131. package/src/tui/driver/recorder.ts +37 -48
  132. package/src/tui/driver/test-workflow.ts +51 -51
  133. package/src/tui/driver/test.ts +25 -25
  134. package/src/tui/hooks/index.ts +24 -20
  135. package/src/tui/hooks/useAnimatedValue.ts +13 -18
  136. package/src/tui/hooks/useDashboardKeyboard.ts +118 -98
  137. package/src/tui/hooks/useDashboardState.ts +26 -24
  138. package/src/tui/hooks/useEmaActivity.ts +82 -74
  139. package/src/tui/hooks/useEntranceAnimation.ts +11 -11
  140. package/src/tui/hooks/useExitAnimation.ts +3 -3
  141. package/src/tui/hooks/usePulse.ts +4 -4
  142. package/src/tui/hooks/useSafeRenderer.ts +5 -5
  143. package/src/tui/hooks/useSessionEnrichedProviders.ts +150 -0
  144. package/src/tui/hooks/useValueFlash.ts +10 -14
  145. package/src/tui/index.tsx +29 -6
  146. package/src/tui/shutdown.ts +19 -0
  147. package/src/tui/utils/providerColor.ts +1 -1
  148. package/src/tui/views/Dashboard.tsx +127 -102
  149. package/src/tui/views/HistoricalTrendsView.tsx +579 -250
  150. package/src/tui/views/ProjectsView.tsx +466 -237
  151. package/src/tui/views/RealTimeDashboard.tsx +150 -111
  152. package/src/tui/views/SettingsView.tsx +222 -191
  153. package/src/tui/views/index.ts +2 -2
  154. package/src/types/opentui-test-utils.d.ts +7 -7
  155. package/src/utils/clipboard.ts +29 -29
  156. package/src/utils/currency.test.ts +53 -53
  157. package/src/utils/currency.ts +35 -32
  158. package/src/version.ts +1 -1
@@ -1,6 +1,12 @@
1
- import type { ModelPricing, ProviderPlugin, ProviderPricing } from '@/plugins/types/provider.ts';
2
- import { getModelPricing, getProviderModels, normalizeProviderName, setProviderAliases, clearCache as clearModelsDevCache } from './models-dev.ts';
3
- import { getFallbackPricing, getFallbackProviderPricing } from './fallback.ts';
1
+ import type { ModelPricing, ProviderPlugin, ProviderPricing } from "@/plugins/types/provider.ts";
2
+ import { getFallbackPricing, getFallbackProviderPricing } from "./fallback.ts";
3
+ import {
4
+ clearCache as clearModelsDevCache,
5
+ getModelPricing,
6
+ getProviderModels,
7
+ normalizeProviderName,
8
+ setProviderAliases,
9
+ } from "./models-dev.ts";
4
10
 
5
11
  export function initPricingFromPlugins(
6
12
  plugins: readonly ProviderPlugin[],
@@ -12,8 +18,8 @@ export function initPricingFromPlugins(
12
18
  const pricing = plugin.pricing;
13
19
  if (
14
20
  pricing &&
15
- 'modelsDevProviderId' in pricing &&
16
- typeof (pricing as ProviderPricing).modelsDevProviderId === 'string'
21
+ "modelsDevProviderId" in pricing &&
22
+ typeof (pricing as ProviderPricing).modelsDevProviderId === "string"
17
23
  ) {
18
24
  aliases.set(plugin.id, (pricing as ProviderPricing).modelsDevProviderId!);
19
25
  }
@@ -30,10 +36,10 @@ export function initPricingFromPlugins(
30
36
 
31
37
  export async function getPricing(
32
38
  providerId: string,
33
- modelId: string
39
+ modelId: string,
34
40
  ): Promise<ModelPricing | null> {
35
41
  const normalizedProvider = normalizeProviderName(providerId);
36
-
42
+
37
43
  const modelsDevPricing = await getModelPricing(normalizedProvider, modelId);
38
44
  if (modelsDevPricing) return modelsDevPricing;
39
45
 
@@ -44,10 +50,10 @@ export async function getPricing(
44
50
  }
45
51
 
46
52
  export async function getProviderPricing(
47
- providerId: string
53
+ providerId: string,
48
54
  ): Promise<Record<string, ModelPricing>> {
49
55
  const normalizedProvider = normalizeProviderName(providerId);
50
-
56
+
51
57
  const modelsDevPricing = await getProviderModels(normalizedProvider);
52
58
  if (modelsDevPricing && Object.keys(modelsDevPricing).length > 0) {
53
59
  return modelsDevPricing;
@@ -61,6 +67,6 @@ export function clearPricingCache(): void {
61
67
  clearModelsDevCache();
62
68
  }
63
69
 
64
- export { estimateCost, estimateSessionCost, formatCost, formatTokenCount } from './estimator.ts';
65
- export type { TokenUsage } from './estimator.ts';
66
- export { FALLBACK_PRICING } from './fallback.ts';
70
+ export type { TokenUsage } from "./estimator.ts";
71
+ export { estimateCost, estimateSessionCost, formatCost, formatTokenCount } from "./estimator.ts";
72
+ export { FALLBACK_PRICING } from "./fallback.ts";
@@ -1,6 +1,6 @@
1
- import type { ModelPricing } from '@/plugins/types/provider.ts';
1
+ import type { ModelPricing } from "@/plugins/types/provider.ts";
2
2
 
3
- const MODELS_DEV_API = 'https://models.dev/api.json';
3
+ const MODELS_DEV_API = "https://models.dev/api.json";
4
4
  const CACHE_TTL_MS = 3600000;
5
5
 
6
6
  interface ModelsDevCost {
@@ -63,7 +63,7 @@ export function normalizeProviderName(providerId: string): string {
63
63
 
64
64
  export async function getModelPricing(
65
65
  providerId: string,
66
- modelId: string
66
+ modelId: string,
67
67
  ): Promise<ModelPricing | null> {
68
68
  const data = await fetchModelsDevData();
69
69
  if (!data) return null;
@@ -78,7 +78,7 @@ export async function getModelPricing(
78
78
  const pricing: ModelPricing = {
79
79
  input: model.cost.input,
80
80
  output: model.cost.output,
81
- source: 'models.dev',
81
+ source: "models.dev",
82
82
  };
83
83
 
84
84
  if (model.cost.cache_read !== undefined) {
@@ -92,7 +92,7 @@ export async function getModelPricing(
92
92
  }
93
93
 
94
94
  export async function getProviderModels(
95
- providerId: string
95
+ providerId: string,
96
96
  ): Promise<Record<string, ModelPricing> | null> {
97
97
  const data = await fetchModelsDevData();
98
98
  if (!data) return null;
@@ -109,7 +109,7 @@ export async function getProviderModels(
109
109
  const pricing: ModelPricing = {
110
110
  input: model.cost.input,
111
111
  output: model.cost.output,
112
- source: 'models.dev',
112
+ source: "models.dev",
113
113
  };
114
114
 
115
115
  if (model.cost.cache_read !== undefined) {
@@ -1,6 +1,6 @@
1
- import { Database } from 'bun:sqlite';
2
- import * as fs from 'fs/promises';
3
- import { PATHS } from './paths.ts';
1
+ import { Database } from "bun:sqlite";
2
+ import * as fs from "fs/promises";
3
+ import { PATHS } from "./paths.ts";
4
4
 
5
5
  let db: Database | null = null;
6
6
 
@@ -76,8 +76,8 @@ export async function initDatabase(): Promise<Database> {
76
76
  await fs.mkdir(PATHS.data.dir, { recursive: true });
77
77
 
78
78
  db = new Database(PATHS.data.database, { create: true });
79
- db.exec('PRAGMA journal_mode = WAL');
80
- db.exec('PRAGMA synchronous = NORMAL');
79
+ db.exec("PRAGMA journal_mode = WAL");
80
+ db.exec("PRAGMA synchronous = NORMAL");
81
81
  db.exec(SCHEMA);
82
82
 
83
83
  return db;
@@ -85,7 +85,7 @@ export async function initDatabase(): Promise<Database> {
85
85
 
86
86
  export function getDatabase(): Database {
87
87
  if (!db) {
88
- throw new Error('Database not initialized. Call initDatabase() first.');
88
+ throw new Error("Database not initialized. Call initDatabase() first.");
89
89
  }
90
90
  return db;
91
91
  }
@@ -166,7 +166,7 @@ export function insertUsage(record: UsageRecord): void {
166
166
  record.cacheReadTokens ?? 0,
167
167
  record.cacheWriteTokens ?? 0,
168
168
  record.costUsd,
169
- record.projectPath ?? null
169
+ record.projectPath ?? null,
170
170
  );
171
171
  }
172
172
 
@@ -193,7 +193,7 @@ export function insertUsageBatch(records: UsageRecord[]): void {
193
193
  record.cacheReadTokens ?? 0,
194
194
  record.cacheWriteTokens ?? 0,
195
195
  record.costUsd,
196
- record.projectPath ?? null
196
+ record.projectPath ?? null,
197
197
  );
198
198
  }
199
199
  });
@@ -218,7 +218,7 @@ export function insertProviderSnapshot(snapshot: ProviderSnapshot): void {
218
218
  snapshot.tokensInput ?? null,
219
219
  snapshot.tokensOutput ?? null,
220
220
  snapshot.costUsd ?? null,
221
- snapshot.rawJson ?? null
221
+ snapshot.rawJson ?? null,
222
222
  );
223
223
  }
224
224
 
@@ -228,33 +228,33 @@ export function queryUsage(query: UsageQuery): UsageRecord[] {
228
228
  const params: (string | number)[] = [];
229
229
 
230
230
  if (query.startTime !== undefined) {
231
- conditions.push('timestamp >= ?');
231
+ conditions.push("timestamp >= ?");
232
232
  params.push(query.startTime);
233
233
  }
234
234
  if (query.endTime !== undefined) {
235
- conditions.push('timestamp <= ?');
235
+ conditions.push("timestamp <= ?");
236
236
  params.push(query.endTime);
237
237
  }
238
238
  if (query.provider) {
239
- conditions.push('provider = ?');
239
+ conditions.push("provider = ?");
240
240
  params.push(query.provider);
241
241
  }
242
242
  if (query.model) {
243
- conditions.push('model = ?');
243
+ conditions.push("model = ?");
244
244
  params.push(query.model);
245
245
  }
246
246
  if (query.agent) {
247
- conditions.push('agent = ?');
247
+ conditions.push("agent = ?");
248
248
  params.push(query.agent);
249
249
  }
250
250
  if (query.sessionId) {
251
- conditions.push('session_id = ?');
251
+ conditions.push("session_id = ?");
252
252
  params.push(query.sessionId);
253
253
  }
254
254
 
255
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
256
- const limitClause = query.limit ? `LIMIT ${query.limit}` : '';
257
- const offsetClause = query.offset ? `OFFSET ${query.offset}` : '';
255
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
256
+ const limitClause = query.limit ? `LIMIT ${query.limit}` : "";
257
+ const offsetClause = query.offset ? `OFFSET ${query.offset}` : "";
258
258
 
259
259
  const sql = `
260
260
  SELECT * FROM usage
@@ -303,7 +303,8 @@ export interface UsageSummary {
303
303
 
304
304
  export function getUsageSummary(startTime: number, endTime: number): UsageSummary {
305
305
  const db = getDatabase();
306
- const row = db.prepare(`
306
+ const row = db
307
+ .prepare(`
307
308
  SELECT
308
309
  COALESCE(SUM(input_tokens), 0) as total_input,
309
310
  COALESCE(SUM(output_tokens), 0) as total_output,
@@ -313,7 +314,8 @@ export function getUsageSummary(startTime: number, endTime: number): UsageSummar
313
314
  COUNT(*) as request_count
314
315
  FROM usage
315
316
  WHERE timestamp >= ? AND timestamp <= ?
316
- `).get(startTime, endTime) as {
317
+ `)
318
+ .get(startTime, endTime) as {
317
319
  total_input: number;
318
320
  total_output: number;
319
321
  total_cache_read: number;
@@ -342,7 +344,8 @@ export interface ProviderSummary {
342
344
 
343
345
  export function getUsageByProvider(startTime: number, endTime: number): ProviderSummary[] {
344
346
  const db = getDatabase();
345
- const rows = db.prepare(`
347
+ const rows = db
348
+ .prepare(`
346
349
  SELECT
347
350
  provider,
348
351
  COALESCE(SUM(input_tokens), 0) as total_input,
@@ -353,7 +356,8 @@ export function getUsageByProvider(startTime: number, endTime: number): Provider
353
356
  WHERE timestamp >= ? AND timestamp <= ?
354
357
  GROUP BY provider
355
358
  ORDER BY total_cost DESC
356
- `).all(startTime, endTime) as Array<{
359
+ `)
360
+ .all(startTime, endTime) as Array<{
357
361
  provider: string;
358
362
  total_input: number;
359
363
  total_output: number;
@@ -381,7 +385,8 @@ export interface ModelSummary {
381
385
 
382
386
  export function getUsageByModel(startTime: number, endTime: number): ModelSummary[] {
383
387
  const db = getDatabase();
384
- const rows = db.prepare(`
388
+ const rows = db
389
+ .prepare(`
385
390
  SELECT
386
391
  model,
387
392
  provider,
@@ -393,7 +398,8 @@ export function getUsageByModel(startTime: number, endTime: number): ModelSummar
393
398
  WHERE timestamp >= ? AND timestamp <= ?
394
399
  GROUP BY model, provider
395
400
  ORDER BY total_cost DESC
396
- `).all(startTime, endTime) as Array<{
401
+ `)
402
+ .all(startTime, endTime) as Array<{
397
403
  model: string;
398
404
  provider: string;
399
405
  total_input: number;
@@ -422,12 +428,13 @@ export interface TimeSeriesPoint {
422
428
  export function getUsageTimeSeries(
423
429
  startTime: number,
424
430
  endTime: number,
425
- bucketMinutes: number = 5
431
+ bucketMinutes: number = 5,
426
432
  ): TimeSeriesPoint[] {
427
433
  const db = getDatabase();
428
434
  const bucketSeconds = bucketMinutes * 60;
429
435
 
430
- const rows = db.prepare(`
436
+ const rows = db
437
+ .prepare(`
431
438
  SELECT
432
439
  (timestamp / ? * ?) as bucket_time,
433
440
  COALESCE(SUM(input_tokens + output_tokens), 0) as total_tokens,
@@ -437,7 +444,8 @@ export function getUsageTimeSeries(
437
444
  WHERE timestamp >= ? AND timestamp <= ?
438
445
  GROUP BY bucket_time
439
446
  ORDER BY bucket_time ASC
440
- `).all(bucketSeconds, bucketSeconds, startTime, endTime) as Array<{
447
+ `)
448
+ .all(bucketSeconds, bucketSeconds, startTime, endTime) as Array<{
441
449
  bucket_time: number;
442
450
  total_tokens: number;
443
451
  total_cost: number;
@@ -456,15 +464,17 @@ export function getProviderSnapshots(
456
464
  provider: string,
457
465
  startTime: number,
458
466
  endTime: number,
459
- limit: number = 100
467
+ limit: number = 100,
460
468
  ): ProviderSnapshot[] {
461
469
  const db = getDatabase();
462
- const rows = db.prepare(`
470
+ const rows = db
471
+ .prepare(`
463
472
  SELECT * FROM provider_snapshots
464
473
  WHERE provider = ? AND timestamp >= ? AND timestamp <= ?
465
474
  ORDER BY timestamp DESC
466
475
  LIMIT ?
467
- `).all(provider, startTime, endTime, limit) as Array<{
476
+ `)
477
+ .all(provider, startTime, endTime, limit) as Array<{
468
478
  timestamp: number;
469
479
  provider: string;
470
480
  used_percent: number | null;
@@ -514,29 +524,31 @@ export function upsertDailyAggregate(aggregate: DailyAggregate): void {
514
524
  aggregate.totalCacheRead,
515
525
  aggregate.totalCacheWrite,
516
526
  aggregate.totalCostUsd,
517
- aggregate.requestCount
527
+ aggregate.requestCount,
518
528
  );
519
529
  }
520
530
 
521
531
  export function getDailyAggregates(
522
532
  startDate: string,
523
533
  endDate: string,
524
- provider?: string
534
+ provider?: string,
525
535
  ): DailyAggregate[] {
526
536
  const db = getDatabase();
527
- const conditions = ['date >= ?', 'date <= ?'];
537
+ const conditions = ["date >= ?", "date <= ?"];
528
538
  const params: string[] = [startDate, endDate];
529
539
 
530
540
  if (provider) {
531
- conditions.push('provider = ?');
541
+ conditions.push("provider = ?");
532
542
  params.push(provider);
533
543
  }
534
544
 
535
- const rows = db.prepare(`
545
+ const rows = db
546
+ .prepare(`
536
547
  SELECT * FROM daily_aggregates
537
- WHERE ${conditions.join(' AND ')}
548
+ WHERE ${conditions.join(" AND ")}
538
549
  ORDER BY date DESC, total_cost_usd DESC
539
- `).all(...params) as Array<{
550
+ `)
551
+ .all(...params) as Array<{
540
552
  date: string;
541
553
  provider: string;
542
554
  model: string | null;
@@ -582,9 +594,9 @@ export function getThisMonthSummary(): UsageSummary {
582
594
 
583
595
  export function pluginStorageGet(pluginId: string, key: string): string | null {
584
596
  const db = getDatabase();
585
- const row = db.prepare(
586
- 'SELECT value FROM plugin_storage WHERE plugin_id = ? AND key = ?',
587
- ).get(pluginId, key) as { value: string } | null;
597
+ const row = db
598
+ .prepare("SELECT value FROM plugin_storage WHERE plugin_id = ? AND key = ?")
599
+ .get(pluginId, key) as { value: string } | null;
588
600
  return row?.value ?? null;
589
601
  }
590
602
 
@@ -599,15 +611,13 @@ export function pluginStorageSet(pluginId: string, key: string, value: string):
599
611
 
600
612
  export function pluginStorageDelete(pluginId: string, key: string): void {
601
613
  const db = getDatabase();
602
- db.prepare(
603
- 'DELETE FROM plugin_storage WHERE plugin_id = ? AND key = ?',
604
- ).run(pluginId, key);
614
+ db.prepare("DELETE FROM plugin_storage WHERE plugin_id = ? AND key = ?").run(pluginId, key);
605
615
  }
606
616
 
607
617
  export function pluginStorageHas(pluginId: string, key: string): boolean {
608
618
  const db = getDatabase();
609
- const row = db.prepare(
610
- 'SELECT 1 FROM plugin_storage WHERE plugin_id = ? AND key = ?',
611
- ).get(pluginId, key);
619
+ const row = db
620
+ .prepare("SELECT 1 FROM plugin_storage WHERE plugin_id = ? AND key = ?")
621
+ .get(pluginId, key);
612
622
  return row !== null && row !== undefined;
613
623
  }
package/src/storage/db.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { Database } from 'bun:sqlite';
2
- import * as fs from 'fs/promises';
3
- import { PATHS } from './paths.ts';
4
- import { applyMigrations } from './migrations/index.ts';
1
+ import { Database } from "bun:sqlite";
2
+ import * as fs from "fs/promises";
3
+ import { applyMigrations } from "./migrations/index.ts";
4
+ import { PATHS } from "./paths.ts";
5
5
 
6
6
  let db: Database | null = null;
7
7
  let currentAppRunId: number | null = null;
@@ -13,10 +13,10 @@ export async function initDatabase(): Promise<Database> {
13
13
 
14
14
  db = new Database(PATHS.data.database, { create: true });
15
15
 
16
- db.exec('PRAGMA journal_mode = WAL');
17
- db.exec('PRAGMA synchronous = NORMAL');
18
- db.exec('PRAGMA foreign_keys = ON');
19
- db.exec('PRAGMA busy_timeout = 2000');
16
+ db.exec("PRAGMA journal_mode = WAL");
17
+ db.exec("PRAGMA synchronous = NORMAL");
18
+ db.exec("PRAGMA foreign_keys = ON");
19
+ db.exec("PRAGMA busy_timeout = 2000");
20
20
 
21
21
  applyMigrations(db);
22
22
 
@@ -27,9 +27,9 @@ export async function initDatabase(): Promise<Database> {
27
27
 
28
28
  const result = stmt.run(
29
29
  Date.now(),
30
- process.env.npm_package_version ?? '0.0.0',
30
+ process.env.npm_package_version ?? "0.0.0",
31
31
  process.pid,
32
- require('os').hostname()
32
+ require("os").hostname(),
33
33
  );
34
34
 
35
35
  currentAppRunId = Number(result.lastInsertRowid);
@@ -39,7 +39,7 @@ export async function initDatabase(): Promise<Database> {
39
39
 
40
40
  export function getDatabase(): Database {
41
41
  if (!db) {
42
- throw new Error('Database not initialized. Call initDatabase() first.');
42
+ throw new Error("Database not initialized. Call initDatabase() first.");
43
43
  }
44
44
  return db;
45
45
  }
@@ -50,7 +50,7 @@ export function getAppRunId(): number | null {
50
50
 
51
51
  export function closeDatabase(): void {
52
52
  if (db && currentAppRunId) {
53
- db.prepare('UPDATE app_runs SET ended_at = ? WHERE id = ?').run(Date.now(), currentAppRunId);
53
+ db.prepare("UPDATE app_runs SET ended_at = ? WHERE id = ?").run(Date.now(), currentAppRunId);
54
54
  }
55
55
  if (db) {
56
56
  db.close();
@@ -1,66 +1,65 @@
1
- export { PATHS } from './paths.ts';
2
-
3
1
  export {
4
- initDatabase,
5
- getDatabase,
6
2
  closeDatabase,
7
- isDatabaseInitialized,
8
3
  getAppRunId,
9
- } from './db.ts';
10
-
4
+ getDatabase,
5
+ initDatabase,
6
+ isDatabaseInitialized,
7
+ } from "./db.ts";
8
+ export { PATHS } from "./paths.ts";
9
+ export type { LatestStreamTotals } from "./repos/agentSessions.ts";
11
10
  export {
11
+ getAgentSession,
12
+ getLatestStreamTotalsForAllSessions,
13
+ getRecentSessions,
14
+ getSessionsByProject,
15
+ insertAgentSessionSnapshot,
16
+ upsertAgentSession,
17
+ } from "./repos/agentSessions.ts";
18
+ export {
19
+ getLatestProviderSnapshot,
12
20
  insertProviderSnapshot,
13
21
  insertProviderSnapshotBatch,
14
22
  queryProviderSnapshots,
15
- getLatestProviderSnapshot,
16
- } from './repos/providerSnapshots.ts';
17
-
23
+ } from "./repos/providerSnapshots.ts";
24
+ export type {
25
+ ModelDailyCost,
26
+ ProjectDailyCost,
27
+ ProviderDailyCost,
28
+ SessionActivityPoint,
29
+ } from "./repos/usageEvents.ts";
18
30
  export {
31
+ calculateBurnRate,
32
+ getSessionActivityTimeline,
33
+ getTotalUsageInWindow,
19
34
  insertUsageEvent,
20
35
  insertUsageEventBatch,
21
- queryUsageTimeSeries,
22
- queryProviderDailyCosts,
23
36
  queryModelDailyCosts,
24
37
  queryProjectDailyCosts,
25
- calculateBurnRate,
26
- getTotalUsageInWindow,
27
- getSessionActivityTimeline,
28
- } from './repos/usageEvents.ts';
29
-
30
- export type { SessionActivityPoint, ProviderDailyCost, ModelDailyCost, ProjectDailyCost } from './repos/usageEvents.ts';
31
-
32
- export {
33
- upsertAgentSession,
34
- insertAgentSessionSnapshot,
35
- getAgentSession,
36
- getRecentSessions,
37
- getSessionsByProject,
38
- getLatestStreamTotalsForAllSessions,
39
- } from './repos/agentSessions.ts';
40
-
41
- export type { LatestStreamTotals } from './repos/agentSessions.ts';
38
+ queryProviderDailyCosts,
39
+ queryUsageTimeSeries,
40
+ } from "./repos/usageEvents.ts";
42
41
 
43
42
  export type {
44
- UsageEventSource,
45
- SessionStatus,
46
- CostSource,
47
- PricingSource,
48
- AppRunRow,
49
- ProviderSnapshotRow,
50
- ProviderSnapshotInsert,
51
43
  AgentSessionDim,
52
- AgentSessionUpsert,
53
- AgentSessionSnapshotRow,
54
44
  AgentSessionSnapshotInsert,
45
+ AgentSessionSnapshotRow,
55
46
  AgentSessionStreamSnapshotRow,
56
- UsageEventRow,
57
- UsageEventInsert,
58
- HourlyAggregateRow,
47
+ AgentSessionUpsert,
48
+ AppRunRow,
49
+ CostSource,
59
50
  DailyAggregateRow,
60
- TimeSeriesPoint,
51
+ HourlyAggregateRow,
52
+ PricingSource,
53
+ ProviderSnapshotInsert,
54
+ ProviderSnapshotRow,
55
+ SessionStatus,
56
+ StreamTotals,
61
57
  TimeSeriesFilters,
58
+ TimeSeriesPoint,
59
+ UsageEventInsert,
60
+ UsageEventRow,
61
+ UsageEventSource,
62
62
  UsageQueryOptions,
63
- StreamTotals,
64
- } from './types.ts';
63
+ } from "./types.ts";
65
64
 
66
- export { computeStreamDelta } from './types.ts';
65
+ export { computeStreamDelta } from "./types.ts";
@@ -1,4 +1,4 @@
1
- import type { Database } from 'bun:sqlite';
1
+ import type { Database } from "bun:sqlite";
2
2
 
3
3
  export interface Migration {
4
4
  version: number;
@@ -167,7 +167,7 @@ export const migrations: Migration[] = [
167
167
  ];
168
168
 
169
169
  export function getCurrentVersion(db: Database): number {
170
- const result = db.prepare('PRAGMA user_version').get() as { user_version: number } | null;
170
+ const result = db.prepare("PRAGMA user_version").get() as { user_version: number } | null;
171
171
  return result?.user_version ?? 0;
172
172
  }
173
173
 
@@ -1,24 +1,24 @@
1
- import * as path from 'path';
2
- import * as os from 'os';
1
+ import * as os from "os";
2
+ import * as path from "path";
3
3
 
4
4
  const HOME = os.homedir();
5
5
 
6
6
  export const PATHS = {
7
7
  config: {
8
- dir: path.join(HOME, '.config/tokentop'),
9
- file: path.join(HOME, '.config/tokentop/config.json'),
10
- fileJsonc: path.join(HOME, '.config/tokentop/config.jsonc'),
11
- plugins: path.join(HOME, '.config/tokentop/plugins'),
8
+ dir: path.join(HOME, ".config/tokentop"),
9
+ file: path.join(HOME, ".config/tokentop/config.json"),
10
+ fileJsonc: path.join(HOME, ".config/tokentop/config.jsonc"),
11
+ plugins: path.join(HOME, ".config/tokentop/plugins"),
12
12
  },
13
13
  data: {
14
- dir: path.join(HOME, '.local/share/tokentop'),
15
- database: path.join(HOME, '.local/share/tokentop/usage.db'),
16
- sessions: path.join(HOME, '.local/share/tokentop/sessions'),
17
- cache: path.join(HOME, '.local/share/tokentop/cache'),
18
- logs: path.join(HOME, '.local/share/tokentop/logs'),
14
+ dir: path.join(HOME, ".local/share/tokentop"),
15
+ database: path.join(HOME, ".local/share/tokentop/usage.db"),
16
+ sessions: path.join(HOME, ".local/share/tokentop/sessions"),
17
+ cache: path.join(HOME, ".local/share/tokentop/cache"),
18
+ logs: path.join(HOME, ".local/share/tokentop/logs"),
19
19
  },
20
20
  cache: {
21
- dir: path.join(HOME, '.cache/tokentop'),
22
- nodeModules: path.join(HOME, '.cache/tokentop/node_modules'),
21
+ dir: path.join(HOME, ".cache/tokentop"),
22
+ nodeModules: path.join(HOME, ".cache/tokentop/node_modules"),
23
23
  },
24
24
  } as const;