@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,10 +1,10 @@
1
- import { getDatabase } from '../db.ts';
1
+ import { getDatabase } from "../db.ts";
2
2
  import type {
3
3
  AgentSessionDim,
4
- AgentSessionUpsert,
5
4
  AgentSessionSnapshotInsert,
6
5
  AgentSessionStreamSnapshotRow,
7
- } from '../types.ts';
6
+ AgentSessionUpsert,
7
+ } from "../types.ts";
8
8
 
9
9
  const UPSERT_SESSION_SQL = `
10
10
  INSERT INTO agent_sessions (agent_id, session_id, project_path, started_at, first_seen_at, last_seen_at)
@@ -36,21 +36,23 @@ export function upsertAgentSession(session: AgentSessionUpsert): number {
36
36
  const db = getDatabase();
37
37
  const now = Date.now();
38
38
 
39
- const row = db.prepare(UPSERT_SESSION_SQL).get(
40
- session.agentId,
41
- session.sessionId,
42
- session.projectPath ?? null,
43
- session.startedAt ?? null,
44
- session.firstSeenAt ?? now,
45
- session.lastSeenAt
46
- ) as { id: number };
39
+ const row = db
40
+ .prepare(UPSERT_SESSION_SQL)
41
+ .get(
42
+ session.agentId,
43
+ session.sessionId,
44
+ session.projectPath ?? null,
45
+ session.startedAt ?? null,
46
+ session.firstSeenAt ?? now,
47
+ session.lastSeenAt,
48
+ ) as { id: number };
47
49
 
48
50
  return row.id;
49
51
  }
50
52
 
51
53
  export function insertAgentSessionSnapshot(
52
54
  snapshot: AgentSessionSnapshotInsert,
53
- streams: Omit<AgentSessionStreamSnapshotRow, 'agentSessionSnapshotId'>[]
55
+ streams: Omit<AgentSessionStreamSnapshotRow, "agentSessionSnapshotId">[],
54
56
  ): number {
55
57
  const db = getDatabase();
56
58
 
@@ -70,7 +72,7 @@ export function insertAgentSessionSnapshot(
70
72
  snapshot.totalCacheReadTokens,
71
73
  snapshot.totalCacheWriteTokens,
72
74
  snapshot.totalCostUsd,
73
- snapshot.requestCount
75
+ snapshot.requestCount,
74
76
  );
75
77
 
76
78
  snapshotId = Number(result.lastInsertRowid);
@@ -86,7 +88,7 @@ export function insertAgentSessionSnapshot(
86
88
  stream.cacheWriteTokens,
87
89
  stream.costUsd,
88
90
  stream.requestCount,
89
- stream.pricingSource ?? null
91
+ stream.pricingSource ?? null,
90
92
  );
91
93
  }
92
94
  })();
@@ -97,9 +99,11 @@ export function insertAgentSessionSnapshot(
97
99
  export function getAgentSession(agentId: string, sessionId: string): AgentSessionDim | null {
98
100
  const db = getDatabase();
99
101
 
100
- const row = db.prepare(`
102
+ const row = db
103
+ .prepare(`
101
104
  SELECT * FROM agent_sessions WHERE agent_id = ? AND session_id = ?
102
- `).get(agentId, sessionId) as DbSessionRow | null;
105
+ `)
106
+ .get(agentId, sessionId) as DbSessionRow | null;
103
107
 
104
108
  return row ? mapSessionRow(row) : null;
105
109
  }
@@ -107,11 +111,13 @@ export function getAgentSession(agentId: string, sessionId: string): AgentSessio
107
111
  export function getRecentSessions(limit = 50): AgentSessionDim[] {
108
112
  const db = getDatabase();
109
113
 
110
- const rows = db.prepare(`
114
+ const rows = db
115
+ .prepare(`
111
116
  SELECT * FROM agent_sessions
112
117
  ORDER BY last_seen_at DESC
113
118
  LIMIT ?
114
- `).all(limit) as DbSessionRow[];
119
+ `)
120
+ .all(limit) as DbSessionRow[];
115
121
 
116
122
  return rows.map(mapSessionRow);
117
123
  }
@@ -119,12 +125,14 @@ export function getRecentSessions(limit = 50): AgentSessionDim[] {
119
125
  export function getSessionsByProject(projectPath: string, limit = 50): AgentSessionDim[] {
120
126
  const db = getDatabase();
121
127
 
122
- const rows = db.prepare(`
128
+ const rows = db
129
+ .prepare(`
123
130
  SELECT * FROM agent_sessions
124
131
  WHERE project_path = ?
125
132
  ORDER BY last_seen_at DESC
126
133
  LIMIT ?
127
- `).all(projectPath, limit) as DbSessionRow[];
134
+ `)
135
+ .all(projectPath, limit) as DbSessionRow[];
128
136
 
129
137
  return rows.map(mapSessionRow);
130
138
  }
@@ -167,7 +175,8 @@ export interface LatestStreamTotals {
167
175
  export function getLatestStreamTotalsForAllSessions(): LatestStreamTotals[] {
168
176
  const db = getDatabase();
169
177
 
170
- const rows = db.prepare(`
178
+ const rows = db
179
+ .prepare(`
171
180
  SELECT
172
181
  s.agent_id, s.session_id,
173
182
  ss.provider, ss.model,
@@ -182,7 +191,8 @@ export function getLatestStreamTotalsForAllSessions(): LatestStreamTotals[] {
182
191
  FROM agent_session_snapshots snap2
183
192
  GROUP BY snap2.agent_session_id
184
193
  )
185
- `).all() as Array<{
194
+ `)
195
+ .all() as Array<{
186
196
  agent_id: string;
187
197
  session_id: string;
188
198
  provider: string;
@@ -195,7 +205,7 @@ export function getLatestStreamTotalsForAllSessions(): LatestStreamTotals[] {
195
205
  request_count: number;
196
206
  }>;
197
207
 
198
- return rows.map(r => ({
208
+ return rows.map((r) => ({
199
209
  agentId: r.agent_id,
200
210
  sessionId: r.session_id,
201
211
  provider: r.provider,
@@ -1,5 +1,5 @@
1
- import { getDatabase } from '../db.ts';
2
- import type { ProviderSnapshotInsert, ProviderSnapshotRow, CostSource } from '../types.ts';
1
+ import { getDatabase } from "../db.ts";
2
+ import type { CostSource, ProviderSnapshotInsert, ProviderSnapshotRow } from "../types.ts";
3
3
 
4
4
  const INSERT_SQL = `
5
5
  INSERT INTO provider_snapshots (
@@ -36,7 +36,7 @@ export function insertProviderSnapshot(snapshot: ProviderSnapshotInsert): number
36
36
  snapshot.tokensOutput ?? null,
37
37
  snapshot.costUsd ?? null,
38
38
  snapshot.costSource ?? null,
39
- snapshot.rawJson ?? null
39
+ snapshot.rawJson ?? null,
40
40
  );
41
41
 
42
42
  return Number(result.lastInsertRowid);
@@ -60,7 +60,7 @@ export function insertProviderSnapshotBatch(snapshots: ProviderSnapshotInsert[])
60
60
  s.tokensOutput ?? null,
61
61
  s.costUsd ?? null,
62
62
  s.costSource ?? null,
63
- s.rawJson ?? null
63
+ s.rawJson ?? null,
64
64
  );
65
65
  }
66
66
  });
@@ -72,7 +72,7 @@ export function queryProviderSnapshots(
72
72
  provider: string,
73
73
  startMs: number,
74
74
  endMs: number,
75
- limit = 100
75
+ limit = 100,
76
76
  ): ProviderSnapshotRow[] {
77
77
  const db = getDatabase();
78
78
  const rows = db.prepare(QUERY_BY_PROVIDER_SQL).all(provider, startMs, endMs, limit) as DbRow[];
@@ -1,5 +1,5 @@
1
- import { getDatabase } from '../db.ts';
2
- import type { UsageEventInsert, TimeSeriesPoint, TimeSeriesFilters } from '../types.ts';
1
+ import { getDatabase } from "../db.ts";
2
+ import type { TimeSeriesFilters, TimeSeriesPoint, UsageEventInsert } from "../types.ts";
3
3
 
4
4
  const INSERT_SQL = `
5
5
  INSERT INTO usage_events (
@@ -27,7 +27,7 @@ export function insertUsageEvent(event: UsageEventInsert): number {
27
27
  event.cacheWriteTokens,
28
28
  event.costUsd,
29
29
  event.requestCount,
30
- event.pricingSource ?? null
30
+ event.pricingSource ?? null,
31
31
  );
32
32
 
33
33
  return Number(result.lastInsertRowid);
@@ -55,7 +55,7 @@ export function insertUsageEventBatch(events: UsageEventInsert[]): void {
55
55
  e.cacheWriteTokens,
56
56
  e.costUsd,
57
57
  e.requestCount,
58
- e.pricingSource ?? null
58
+ e.pricingSource ?? null,
59
59
  );
60
60
  }
61
61
  });
@@ -67,31 +67,31 @@ export function queryUsageTimeSeries(
67
67
  startMs: number,
68
68
  endMs: number,
69
69
  bucketMs: number,
70
- filters: TimeSeriesFilters = {}
70
+ filters: TimeSeriesFilters = {},
71
71
  ): TimeSeriesPoint[] {
72
72
  const db = getDatabase();
73
73
 
74
- const conditions: string[] = ['timestamp >= ?', 'timestamp <= ?'];
74
+ const conditions: string[] = ["timestamp >= ?", "timestamp <= ?"];
75
75
  const params: (string | number)[] = [startMs, endMs];
76
76
 
77
77
  if (filters.provider) {
78
- conditions.push('provider = ?');
78
+ conditions.push("provider = ?");
79
79
  params.push(filters.provider);
80
80
  }
81
81
  if (filters.model) {
82
- conditions.push('model = ?');
82
+ conditions.push("model = ?");
83
83
  params.push(filters.model);
84
84
  }
85
85
  if (filters.agentId) {
86
- conditions.push('agent_id = ?');
86
+ conditions.push("agent_id = ?");
87
87
  params.push(filters.agentId);
88
88
  }
89
89
  if (filters.sessionId) {
90
- conditions.push('session_id = ?');
90
+ conditions.push("session_id = ?");
91
91
  params.push(filters.sessionId);
92
92
  }
93
93
  if (filters.projectPath) {
94
- conditions.push('project_path = ?');
94
+ conditions.push("project_path = ?");
95
95
  params.push(filters.projectPath);
96
96
  }
97
97
 
@@ -102,7 +102,7 @@ export function queryUsageTimeSeries(
102
102
  COALESCE(SUM(cost_usd), 0) AS cost_usd,
103
103
  COALESCE(SUM(request_count), 0) AS request_count
104
104
  FROM usage_events
105
- WHERE ${conditions.join(' AND ')}
105
+ WHERE ${conditions.join(" AND ")}
106
106
  GROUP BY bucket_start
107
107
  ORDER BY bucket_start ASC
108
108
  `;
@@ -114,7 +114,7 @@ export function queryUsageTimeSeries(
114
114
  request_count: number;
115
115
  }>;
116
116
 
117
- return rows.map(r => ({
117
+ return rows.map((r) => ({
118
118
  bucketStart: r.bucket_start,
119
119
  tokens: r.tokens,
120
120
  costUsd: r.cost_usd,
@@ -122,17 +122,22 @@ export function queryUsageTimeSeries(
122
122
  }));
123
123
  }
124
124
 
125
- export function calculateBurnRate(windowMs: number, nowMs = Date.now()): { costPerHour: number; tokensPerMinute: number } {
125
+ export function calculateBurnRate(
126
+ windowMs: number,
127
+ nowMs = Date.now(),
128
+ ): { costPerHour: number; tokensPerMinute: number } {
126
129
  const db = getDatabase();
127
130
  const startMs = nowMs - windowMs;
128
131
 
129
- const row = db.prepare(`
132
+ const row = db
133
+ .prepare(`
130
134
  SELECT
131
135
  COALESCE(SUM(cost_usd), 0) AS cost,
132
136
  COALESCE(SUM(input_tokens + output_tokens), 0) AS tokens
133
137
  FROM usage_events
134
138
  WHERE timestamp >= ? AND timestamp <= ?
135
- `).get(startMs, nowMs) as { cost: number; tokens: number };
139
+ `)
140
+ .get(startMs, nowMs) as { cost: number; tokens: number };
136
141
 
137
142
  const hours = windowMs / (1000 * 60 * 60);
138
143
  const minutes = windowMs / (1000 * 60);
@@ -143,7 +148,10 @@ export function calculateBurnRate(windowMs: number, nowMs = Date.now()): { costP
143
148
  };
144
149
  }
145
150
 
146
- export function getTotalUsageInWindow(startMs: number, endMs: number): {
151
+ export function getTotalUsageInWindow(
152
+ startMs: number,
153
+ endMs: number,
154
+ ): {
147
155
  inputTokens: number;
148
156
  outputTokens: number;
149
157
  costUsd: number;
@@ -151,7 +159,8 @@ export function getTotalUsageInWindow(startMs: number, endMs: number): {
151
159
  } {
152
160
  const db = getDatabase();
153
161
 
154
- const row = db.prepare(`
162
+ const row = db
163
+ .prepare(`
155
164
  SELECT
156
165
  COALESCE(SUM(input_tokens), 0) AS input_tokens,
157
166
  COALESCE(SUM(output_tokens), 0) AS output_tokens,
@@ -159,7 +168,8 @@ export function getTotalUsageInWindow(startMs: number, endMs: number): {
159
168
  COALESCE(SUM(request_count), 0) AS request_count
160
169
  FROM usage_events
161
170
  WHERE timestamp >= ? AND timestamp <= ?
162
- `).get(startMs, endMs) as {
171
+ `)
172
+ .get(startMs, endMs) as {
163
173
  input_tokens: number;
164
174
  output_tokens: number;
165
175
  cost_usd: number;
@@ -190,7 +200,7 @@ export interface ProviderDailyCost {
190
200
  export function queryProviderDailyCosts(
191
201
  startMs: number,
192
202
  endMs: number,
193
- bucketMs: number
203
+ bucketMs: number,
194
204
  ): ProviderDailyCost[] {
195
205
  const db = getDatabase();
196
206
 
@@ -216,7 +226,7 @@ export function queryProviderDailyCosts(
216
226
  request_count: number;
217
227
  }>;
218
228
 
219
- return rows.map(r => ({
229
+ return rows.map((r) => ({
220
230
  provider: r.provider,
221
231
  bucketStart: r.bucket_start,
222
232
  costUsd: r.cost_usd,
@@ -236,7 +246,7 @@ export interface ModelDailyCost {
236
246
  export function queryModelDailyCosts(
237
247
  startMs: number,
238
248
  endMs: number,
239
- bucketMs: number
249
+ bucketMs: number,
240
250
  ): ModelDailyCost[] {
241
251
  const db = getDatabase();
242
252
 
@@ -262,7 +272,7 @@ export function queryModelDailyCosts(
262
272
  request_count: number;
263
273
  }>;
264
274
 
265
- return rows.map(r => ({
275
+ return rows.map((r) => ({
266
276
  model: r.model,
267
277
  bucketStart: r.bucket_start,
268
278
  costUsd: r.cost_usd,
@@ -282,7 +292,7 @@ export interface ProjectDailyCost {
282
292
  export function queryProjectDailyCosts(
283
293
  startMs: number,
284
294
  endMs: number,
285
- bucketMs: number
295
+ bucketMs: number,
286
296
  ): ProjectDailyCost[] {
287
297
  const db = getDatabase();
288
298
 
@@ -308,7 +318,7 @@ export function queryProjectDailyCosts(
308
318
  request_count: number;
309
319
  }>;
310
320
 
311
- return rows.map(r => ({
321
+ return rows.map((r) => ({
312
322
  projectPath: r.project_path,
313
323
  bucketStart: r.bucket_start,
314
324
  costUsd: r.cost_usd,
@@ -320,14 +330,16 @@ export function queryProjectDailyCosts(
320
330
  export function getSessionActivityTimeline(sessionId: string): SessionActivityPoint[] {
321
331
  const db = getDatabase();
322
332
 
323
- const rows = db.prepare(`
333
+ const rows = db
334
+ .prepare(`
324
335
  SELECT timestamp, (input_tokens + output_tokens) AS tokens
325
336
  FROM usage_events
326
337
  WHERE session_id = ?
327
338
  ORDER BY timestamp ASC
328
- `).all(sessionId) as Array<{ timestamp: number; tokens: number }>;
339
+ `)
340
+ .all(sessionId) as Array<{ timestamp: number; tokens: number }>;
329
341
 
330
- return rows.map(r => ({
342
+ return rows.map((r) => ({
331
343
  timestamp: r.timestamp,
332
344
  tokens: r.tokens,
333
345
  }));
@@ -7,10 +7,10 @@
7
7
  // Enums & Literal Types
8
8
  // ============================================================================
9
9
 
10
- export type UsageEventSource = 'agent' | 'provider';
11
- export type SessionStatus = 'active' | 'idle';
12
- export type CostSource = 'api' | 'estimated';
13
- export type PricingSource = 'models.dev' | 'fallback' | 'unknown';
10
+ export type UsageEventSource = "agent" | "provider";
11
+ export type SessionStatus = "active" | "idle";
12
+ export type CostSource = "api" | "estimated";
13
+ export type PricingSource = "models.dev" | "fallback" | "unknown";
14
14
 
15
15
  // ============================================================================
16
16
  // App Runs Table
@@ -253,7 +253,7 @@ export interface StreamTotals {
253
253
  */
254
254
  export function computeStreamDelta(
255
255
  current: StreamTotals,
256
- previous: StreamTotals | undefined
256
+ previous: StreamTotals | undefined,
257
257
  ): StreamTotals | null {
258
258
  if (!previous) {
259
259
  // First observation - treat as a delta from zero