@hasna/economy 0.1.0 → 0.2.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.
- package/dist/cli/commands/watch.d.ts +8 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +681 -150
- package/dist/db/database.d.ts +47 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +143 -109
- package/dist/ingest/claude.d.ts +7 -0
- package/dist/ingest/claude.d.ts.map +1 -0
- package/dist/ingest/codex.d.ts +7 -0
- package/dist/ingest/codex.d.ts.map +1 -0
- package/dist/lib/pricing.d.ts +10 -0
- package/dist/lib/pricing.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +147 -110
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +172 -129
- package/dist/server/serve.d.ts +4 -0
- package/dist/server/serve.d.ts.map +1 -0
- package/dist/types/index.d.ts +100 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +17 -3
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import type { EconomyRequest, EconomySession, EconomyProject, Budget, BudgetStatus, CostSummary, ModelBreakdown, ProjectBreakdown, Period, SessionFilter } from '../types/index.js';
|
|
3
|
+
export declare function getDbPath(): string;
|
|
4
|
+
export declare function openDatabase(dbPath?: string, skipSeed?: boolean): Database;
|
|
5
|
+
export declare function upsertRequest(db: Database, req: EconomyRequest): void;
|
|
6
|
+
export declare function upsertSession(db: Database, session: EconomySession): void;
|
|
7
|
+
export declare function rollupSession(db: Database, sessionId: string): void;
|
|
8
|
+
export declare function querySessions(db: Database, filter?: SessionFilter): EconomySession[];
|
|
9
|
+
export declare function queryTopSessions(db: Database, n?: number, agent?: string): EconomySession[];
|
|
10
|
+
export declare function querySummary(db: Database, period: Period): CostSummary;
|
|
11
|
+
export declare function queryModelBreakdown(db: Database): ModelBreakdown[];
|
|
12
|
+
export declare function queryProjectBreakdown(db: Database): ProjectBreakdown[];
|
|
13
|
+
export declare function queryDailyBreakdown(db: Database, days?: number): Array<{
|
|
14
|
+
date: string;
|
|
15
|
+
cost_usd: number;
|
|
16
|
+
agent: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function upsertProject(db: Database, project: EconomyProject): void;
|
|
19
|
+
export declare function getProject(db: Database, path: string): EconomyProject | null;
|
|
20
|
+
export declare function listProjects(db: Database): EconomyProject[];
|
|
21
|
+
export declare function deleteProject(db: Database, path: string): void;
|
|
22
|
+
export declare function upsertBudget(db: Database, budget: Budget): void;
|
|
23
|
+
export declare function listBudgets(db: Database): Budget[];
|
|
24
|
+
export declare function deleteBudget(db: Database, id: string): void;
|
|
25
|
+
export declare function getBudgetStatuses(db: Database): BudgetStatus[];
|
|
26
|
+
export declare function getIngestState(db: Database, source: string, key: string): string | null;
|
|
27
|
+
export declare function setIngestState(db: Database, source: string, key: string, value: string): void;
|
|
28
|
+
export declare function queryRequestsSince(db: Database, since: string): EconomyRequest[];
|
|
29
|
+
export interface DbModelPricing {
|
|
30
|
+
model: string;
|
|
31
|
+
input_per_1m: number;
|
|
32
|
+
output_per_1m: number;
|
|
33
|
+
cache_read_per_1m: number;
|
|
34
|
+
cache_write_per_1m: number;
|
|
35
|
+
updated_at: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function upsertModelPricing(db: Database, p: DbModelPricing): void;
|
|
38
|
+
export declare function getModelPricing(db: Database, model: string): DbModelPricing | null;
|
|
39
|
+
export declare function listModelPricing(db: Database): DbModelPricing[];
|
|
40
|
+
export declare function deleteModelPricing(db: Database, model: string): void;
|
|
41
|
+
export declare function seedModelPricing(db: Database, defaults: Record<string, {
|
|
42
|
+
inputPer1M: number;
|
|
43
|
+
outputPer1M: number;
|
|
44
|
+
cacheReadPer1M: number;
|
|
45
|
+
cacheWritePer1M: number;
|
|
46
|
+
}>): void;
|
|
47
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -73,19 +73,19 @@ var DEFAULT_PRICING;
|
|
|
73
73
|
var init_pricing = __esm(() => {
|
|
74
74
|
init_database();
|
|
75
75
|
DEFAULT_PRICING = {
|
|
76
|
-
"claude-opus-4-6": { inputPer1M:
|
|
77
|
-
"claude-opus-4-5": { inputPer1M:
|
|
76
|
+
"claude-opus-4-6": { inputPer1M: 5, outputPer1M: 25, cacheReadPer1M: 0.5, cacheWritePer1M: 6.25 },
|
|
77
|
+
"claude-opus-4-5": { inputPer1M: 5, outputPer1M: 25, cacheReadPer1M: 0.5, cacheWritePer1M: 6.25 },
|
|
78
78
|
"claude-sonnet-4-6": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
79
79
|
"claude-sonnet-4-5": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
80
|
-
"claude-haiku-4-5": { inputPer1M:
|
|
80
|
+
"claude-haiku-4-5": { inputPer1M: 1, outputPer1M: 5, cacheReadPer1M: 0.1, cacheWritePer1M: 1.25 },
|
|
81
81
|
"claude-3-5-sonnet": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
82
|
-
"claude-3-5-haiku": { inputPer1M:
|
|
82
|
+
"claude-3-5-haiku": { inputPer1M: 1, outputPer1M: 5, cacheReadPer1M: 0.1, cacheWritePer1M: 1.25 },
|
|
83
83
|
"claude-3-opus": { inputPer1M: 15, outputPer1M: 75, cacheReadPer1M: 1.5, cacheWritePer1M: 18.75 },
|
|
84
84
|
"claude-3-sonnet": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
85
85
|
"claude-3-haiku": { inputPer1M: 0.25, outputPer1M: 1.25, cacheReadPer1M: 0.03, cacheWritePer1M: 0.3 },
|
|
86
|
-
"gpt-5.3-codex": { inputPer1M:
|
|
87
|
-
"gpt-5.2-codex": { inputPer1M:
|
|
88
|
-
"gpt-5-codex": { inputPer1M:
|
|
86
|
+
"gpt-5.3-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
87
|
+
"gpt-5.2-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
88
|
+
"gpt-5-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
89
89
|
"gpt-4o": { inputPer1M: 2.5, outputPer1M: 10, cacheReadPer1M: 1.25, cacheWritePer1M: 0 },
|
|
90
90
|
"gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.6, cacheReadPer1M: 0.075, cacheWritePer1M: 0 },
|
|
91
91
|
o1: { inputPer1M: 15, outputPer1M: 60, cacheReadPer1M: 7.5, cacheWritePer1M: 0 },
|
|
@@ -284,8 +284,22 @@ function querySummary(db, period) {
|
|
|
284
284
|
COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as tokens
|
|
285
285
|
FROM requests WHERE ${rWhere}
|
|
286
286
|
`).get();
|
|
287
|
-
const
|
|
288
|
-
|
|
287
|
+
const codexTotals = db.prepare(`
|
|
288
|
+
SELECT COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
289
|
+
COALESCE(SUM(total_tokens), 0) as tokens,
|
|
290
|
+
COUNT(*) as sessions
|
|
291
|
+
FROM sessions
|
|
292
|
+
WHERE ${sWhere}
|
|
293
|
+
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
294
|
+
`).get();
|
|
295
|
+
const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}`).get();
|
|
296
|
+
return {
|
|
297
|
+
total_usd: r.total_usd + codexTotals.cost_usd,
|
|
298
|
+
requests: r.requests,
|
|
299
|
+
tokens: r.tokens + codexTotals.tokens,
|
|
300
|
+
sessions: sessionCount.sessions,
|
|
301
|
+
period
|
|
302
|
+
};
|
|
289
303
|
}
|
|
290
304
|
function queryModelBreakdown(db) {
|
|
291
305
|
return db.prepare(`
|
|
@@ -300,14 +314,14 @@ function queryModelBreakdown(db) {
|
|
|
300
314
|
}
|
|
301
315
|
function queryProjectBreakdown(db) {
|
|
302
316
|
return db.prepare(`
|
|
303
|
-
SELECT
|
|
304
|
-
COUNT(
|
|
305
|
-
COALESCE(SUM(
|
|
306
|
-
|
|
307
|
-
COALESCE(SUM(
|
|
308
|
-
MAX(
|
|
309
|
-
FROM sessions
|
|
310
|
-
GROUP BY
|
|
317
|
+
SELECT project_path, project_name,
|
|
318
|
+
COUNT(*) as sessions,
|
|
319
|
+
COALESCE(SUM(total_tokens), 0) as total_tokens,
|
|
320
|
+
COALESCE(SUM(request_count), 0) as requests,
|
|
321
|
+
COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
322
|
+
MAX(started_at) as last_active
|
|
323
|
+
FROM sessions
|
|
324
|
+
GROUP BY project_path ORDER BY cost_usd DESC
|
|
311
325
|
`).all();
|
|
312
326
|
}
|
|
313
327
|
function queryDailyBreakdown(db, days = 30) {
|
|
@@ -426,117 +440,139 @@ init_pricing();
|
|
|
426
440
|
|
|
427
441
|
// src/ingest/claude.ts
|
|
428
442
|
init_database();
|
|
429
|
-
|
|
443
|
+
init_pricing();
|
|
444
|
+
import { readdirSync, readFileSync, existsSync as existsSync2, statSync } from "fs";
|
|
430
445
|
import { homedir as homedir2 } from "os";
|
|
431
446
|
import { join as join2, basename } from "path";
|
|
432
|
-
import { randomUUID } from "crypto";
|
|
433
|
-
var TELEMETRY_DIR = join2(homedir2(), ".claude", "telemetry");
|
|
434
447
|
var PROJECTS_DIR = join2(homedir2(), ".claude", "projects");
|
|
435
|
-
function
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
448
|
+
function dirNameToPath(dirName) {
|
|
449
|
+
return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
|
|
450
|
+
}
|
|
451
|
+
function collectJsonlFiles(projectDir) {
|
|
452
|
+
const files = [];
|
|
453
|
+
function walk(dir) {
|
|
454
|
+
try {
|
|
455
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
456
|
+
if (entry.isDirectory())
|
|
457
|
+
walk(join2(dir, entry.name));
|
|
458
|
+
else if (entry.name.endsWith(".jsonl"))
|
|
459
|
+
files.push(join2(dir, entry.name));
|
|
445
460
|
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
461
|
+
} catch {}
|
|
462
|
+
}
|
|
463
|
+
walk(projectDir);
|
|
464
|
+
return files;
|
|
449
465
|
}
|
|
450
|
-
async function ingestClaude(db, verbose = false,
|
|
451
|
-
if (!existsSync2(
|
|
466
|
+
async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
467
|
+
if (!existsSync2(PROJECTS_DIR)) {
|
|
452
468
|
if (verbose)
|
|
453
|
-
console.log("Claude
|
|
469
|
+
console.log("Claude projects dir not found:", PROJECTS_DIR);
|
|
454
470
|
return { files: 0, requests: 0, sessions: 0 };
|
|
455
471
|
}
|
|
456
|
-
|
|
472
|
+
let totalFiles = 0;
|
|
457
473
|
let totalRequests = 0;
|
|
458
|
-
let processedFiles = 0;
|
|
459
474
|
const touchedSessions = new Set;
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
} catch {
|
|
473
|
-
if (verbose)
|
|
474
|
-
console.log("Skip unreadable:", filename);
|
|
475
|
-
continue;
|
|
476
|
-
}
|
|
477
|
-
for (const event of events) {
|
|
478
|
-
const ed = event.event_data;
|
|
479
|
-
if (!ed || ed.event_name !== "tengu_api_success")
|
|
475
|
+
const projectDirs = readdirSync(PROJECTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
476
|
+
for (const projectDirEntry of projectDirs) {
|
|
477
|
+
const projectDirPath = join2(PROJECTS_DIR, projectDirEntry.name);
|
|
478
|
+
const projectPath = dirNameToPath(projectDirEntry.name);
|
|
479
|
+
const projectName = basename(projectPath);
|
|
480
|
+
const jsonlFiles = collectJsonlFiles(projectDirPath);
|
|
481
|
+
for (const filePath of jsonlFiles) {
|
|
482
|
+
const stateKey = filePath.replace(PROJECTS_DIR, "");
|
|
483
|
+
let fileMtime = "0";
|
|
484
|
+
try {
|
|
485
|
+
fileMtime = statSync(filePath).mtimeMs.toString();
|
|
486
|
+
} catch {
|
|
480
487
|
continue;
|
|
481
|
-
|
|
482
|
-
|
|
488
|
+
}
|
|
489
|
+
const processed = getIngestState(db, "claude", stateKey);
|
|
490
|
+
if (processed === fileMtime)
|
|
483
491
|
continue;
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
if (!
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
492
|
+
let lines;
|
|
493
|
+
try {
|
|
494
|
+
lines = readFileSync(filePath, "utf-8").split(`
|
|
495
|
+
`).filter((l) => l.trim());
|
|
496
|
+
} catch {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const fileBasename = basename(filePath, ".jsonl");
|
|
500
|
+
const isUuid = /^[0-9a-f-]{36}$/.test(fileBasename);
|
|
501
|
+
let sessionId = isUuid ? fileBasename : fileBasename.replace(/^agent-/, "");
|
|
502
|
+
let sessionCwd = projectPath;
|
|
503
|
+
for (const line of lines) {
|
|
504
|
+
let entry;
|
|
505
|
+
try {
|
|
506
|
+
entry = JSON.parse(line);
|
|
507
|
+
} catch {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (entry.sessionId)
|
|
511
|
+
sessionId = entry.sessionId;
|
|
512
|
+
if (entry.cwd)
|
|
513
|
+
sessionCwd = entry.cwd;
|
|
514
|
+
if (entry.message?.role !== "assistant")
|
|
515
|
+
continue;
|
|
516
|
+
const usage = entry.message.usage;
|
|
517
|
+
if (!usage)
|
|
518
|
+
continue;
|
|
519
|
+
const model = entry.message.model;
|
|
520
|
+
if (!model)
|
|
521
|
+
continue;
|
|
522
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
523
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
524
|
+
const cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
|
|
525
|
+
const cacheReadTokens = usage.cache_read_input_tokens ?? 0;
|
|
526
|
+
const timestamp = entry.timestamp ?? new Date().toISOString();
|
|
527
|
+
if (inputTokens + outputTokens + cacheWriteTokens === 0)
|
|
528
|
+
continue;
|
|
529
|
+
const costUsd = computeCostFromDb(db, model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens);
|
|
530
|
+
const reqId = `claude-${sessionId}-${timestamp}`;
|
|
531
|
+
upsertRequest(db, {
|
|
532
|
+
id: reqId,
|
|
533
|
+
agent: "claude",
|
|
534
|
+
session_id: sessionId,
|
|
535
|
+
model,
|
|
536
|
+
input_tokens: inputTokens,
|
|
537
|
+
output_tokens: outputTokens,
|
|
538
|
+
cache_read_tokens: cacheReadTokens,
|
|
539
|
+
cache_create_tokens: cacheWriteTokens,
|
|
540
|
+
cost_usd: costUsd,
|
|
541
|
+
duration_ms: 0,
|
|
542
|
+
timestamp,
|
|
543
|
+
source_request_id: reqId
|
|
544
|
+
});
|
|
545
|
+
if (!touchedSessions.has(sessionId)) {
|
|
546
|
+
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
547
|
+
if (!existing) {
|
|
548
|
+
const session = {
|
|
549
|
+
id: sessionId,
|
|
550
|
+
agent: "claude",
|
|
551
|
+
project_path: sessionCwd || projectPath,
|
|
552
|
+
project_name: basename(sessionCwd || projectPath),
|
|
553
|
+
started_at: timestamp,
|
|
554
|
+
ended_at: null,
|
|
555
|
+
total_cost_usd: 0,
|
|
556
|
+
total_tokens: 0,
|
|
557
|
+
request_count: 0
|
|
558
|
+
};
|
|
559
|
+
upsertSession(db, session);
|
|
560
|
+
}
|
|
561
|
+
touchedSessions.add(sessionId);
|
|
522
562
|
}
|
|
523
|
-
|
|
563
|
+
totalRequests++;
|
|
524
564
|
}
|
|
525
|
-
|
|
565
|
+
setIngestState(db, "claude", stateKey, fileMtime);
|
|
566
|
+
totalFiles++;
|
|
526
567
|
}
|
|
527
|
-
setIngestState(db, "claude", stateKey, "done");
|
|
528
|
-
processedFiles++;
|
|
529
|
-
if (verbose)
|
|
530
|
-
console.log(`Processed ${filename}: found ${events.length} events`);
|
|
531
568
|
}
|
|
532
569
|
for (const sessionId of touchedSessions) {
|
|
533
570
|
rollupSession(db, sessionId);
|
|
534
571
|
}
|
|
535
|
-
return { files:
|
|
572
|
+
return { files: totalFiles, requests: totalRequests, sessions: touchedSessions.size };
|
|
536
573
|
}
|
|
537
574
|
// src/ingest/codex.ts
|
|
538
575
|
init_database();
|
|
539
|
-
init_pricing();
|
|
540
576
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
541
577
|
import { homedir as homedir3 } from "os";
|
|
542
578
|
import { join as join3, basename as basename2 } from "path";
|
|
@@ -571,9 +607,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
571
607
|
const processed = getIngestState(db, "codex", stateKey);
|
|
572
608
|
if (processed === "done")
|
|
573
609
|
continue;
|
|
574
|
-
const
|
|
575
|
-
const outputTokens = thread.tokens_used - inputTokens;
|
|
576
|
-
const costUsd = computeCost(model, inputTokens, outputTokens);
|
|
610
|
+
const costUsd = 0;
|
|
577
611
|
const projectPath = thread.cwd ?? "";
|
|
578
612
|
const projectName = projectPath ? basename2(projectPath) : "unknown";
|
|
579
613
|
const startedAt = thread.created_at ? new Date(thread.created_at * 1000).toISOString() : new Date().toISOString();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAwDrC,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAsHhE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/ingest/codex.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAmBrC,iBAAS,cAAc,IAAI,MAAM,CAShC;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0D9F;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Database } from 'bun:sqlite';
|
|
2
|
+
import type { ModelPricing } from '../types/index.js';
|
|
3
|
+
export declare const DEFAULT_PRICING: Record<string, ModelPricing>;
|
|
4
|
+
export declare function normalizeModelName(raw: string): string;
|
|
5
|
+
export declare function ensurePricingSeeded(db: Database): void;
|
|
6
|
+
export declare function getPricingFromDb(db: Database, model: string): ModelPricing | null;
|
|
7
|
+
export declare function getPricing(model: string): ModelPricing | null;
|
|
8
|
+
export declare function computeCost(model: string, inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number): number;
|
|
9
|
+
export declare function computeCostFromDb(db: Database, model: string, inputTokens: number, outputTokens: number, cacheReadTokens?: number, cacheWriteTokens?: number): number;
|
|
10
|
+
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/lib/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAwBxD,CAAA;AAGD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKtD;AAGD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAEtD;AAGD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAuBjF;AAGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAO7D;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,eAAe,SAAI,EACnB,gBAAgB,SAAI,GACnB,MAAM,CASR;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,eAAe,SAAI,EACnB,gBAAgB,SAAI,GACnB,MAAM,CASR"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":""}
|