@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
package/dist/server/index.js
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
2
|
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
3
|
var __export = (target, all) => {
|
|
19
4
|
for (var name in all)
|
|
20
5
|
__defProp(target, name, {
|
|
@@ -89,19 +74,19 @@ var DEFAULT_PRICING;
|
|
|
89
74
|
var init_pricing = __esm(() => {
|
|
90
75
|
init_database();
|
|
91
76
|
DEFAULT_PRICING = {
|
|
92
|
-
"claude-opus-4-6": { inputPer1M:
|
|
93
|
-
"claude-opus-4-5": { inputPer1M:
|
|
77
|
+
"claude-opus-4-6": { inputPer1M: 5, outputPer1M: 25, cacheReadPer1M: 0.5, cacheWritePer1M: 6.25 },
|
|
78
|
+
"claude-opus-4-5": { inputPer1M: 5, outputPer1M: 25, cacheReadPer1M: 0.5, cacheWritePer1M: 6.25 },
|
|
94
79
|
"claude-sonnet-4-6": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
95
80
|
"claude-sonnet-4-5": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
96
|
-
"claude-haiku-4-5": { inputPer1M:
|
|
81
|
+
"claude-haiku-4-5": { inputPer1M: 1, outputPer1M: 5, cacheReadPer1M: 0.1, cacheWritePer1M: 1.25 },
|
|
97
82
|
"claude-3-5-sonnet": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
98
|
-
"claude-3-5-haiku": { inputPer1M:
|
|
83
|
+
"claude-3-5-haiku": { inputPer1M: 1, outputPer1M: 5, cacheReadPer1M: 0.1, cacheWritePer1M: 1.25 },
|
|
99
84
|
"claude-3-opus": { inputPer1M: 15, outputPer1M: 75, cacheReadPer1M: 1.5, cacheWritePer1M: 18.75 },
|
|
100
85
|
"claude-3-sonnet": { inputPer1M: 3, outputPer1M: 15, cacheReadPer1M: 0.3, cacheWritePer1M: 3.75 },
|
|
101
86
|
"claude-3-haiku": { inputPer1M: 0.25, outputPer1M: 1.25, cacheReadPer1M: 0.03, cacheWritePer1M: 0.3 },
|
|
102
|
-
"gpt-5.3-codex": { inputPer1M:
|
|
103
|
-
"gpt-5.2-codex": { inputPer1M:
|
|
104
|
-
"gpt-5-codex": { inputPer1M:
|
|
87
|
+
"gpt-5.3-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
88
|
+
"gpt-5.2-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
89
|
+
"gpt-5-codex": { inputPer1M: 1.75, outputPer1M: 14, cacheReadPer1M: 0.44, cacheWritePer1M: 0 },
|
|
105
90
|
"gpt-4o": { inputPer1M: 2.5, outputPer1M: 10, cacheReadPer1M: 1.25, cacheWritePer1M: 0 },
|
|
106
91
|
"gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.6, cacheReadPer1M: 0.075, cacheWritePer1M: 0 },
|
|
107
92
|
o1: { inputPer1M: 15, outputPer1M: 60, cacheReadPer1M: 7.5, cacheWritePer1M: 0 },
|
|
@@ -300,8 +285,22 @@ function querySummary(db, period) {
|
|
|
300
285
|
COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as tokens
|
|
301
286
|
FROM requests WHERE ${rWhere}
|
|
302
287
|
`).get();
|
|
303
|
-
const
|
|
304
|
-
|
|
288
|
+
const codexTotals = db.prepare(`
|
|
289
|
+
SELECT COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
290
|
+
COALESCE(SUM(total_tokens), 0) as tokens,
|
|
291
|
+
COUNT(*) as sessions
|
|
292
|
+
FROM sessions
|
|
293
|
+
WHERE ${sWhere}
|
|
294
|
+
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
295
|
+
`).get();
|
|
296
|
+
const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}`).get();
|
|
297
|
+
return {
|
|
298
|
+
total_usd: r.total_usd + codexTotals.cost_usd,
|
|
299
|
+
requests: r.requests,
|
|
300
|
+
tokens: r.tokens + codexTotals.tokens,
|
|
301
|
+
sessions: sessionCount.sessions,
|
|
302
|
+
period
|
|
303
|
+
};
|
|
305
304
|
}
|
|
306
305
|
function queryModelBreakdown(db) {
|
|
307
306
|
return db.prepare(`
|
|
@@ -316,14 +315,14 @@ function queryModelBreakdown(db) {
|
|
|
316
315
|
}
|
|
317
316
|
function queryProjectBreakdown(db) {
|
|
318
317
|
return db.prepare(`
|
|
319
|
-
SELECT
|
|
320
|
-
COUNT(
|
|
321
|
-
COALESCE(SUM(
|
|
322
|
-
|
|
323
|
-
COALESCE(SUM(
|
|
324
|
-
MAX(
|
|
325
|
-
FROM sessions
|
|
326
|
-
GROUP BY
|
|
318
|
+
SELECT project_path, project_name,
|
|
319
|
+
COUNT(*) as sessions,
|
|
320
|
+
COALESCE(SUM(total_tokens), 0) as total_tokens,
|
|
321
|
+
COALESCE(SUM(request_count), 0) as requests,
|
|
322
|
+
COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
323
|
+
MAX(started_at) as last_active
|
|
324
|
+
FROM sessions
|
|
325
|
+
GROUP BY project_path ORDER BY cost_usd DESC
|
|
327
326
|
`).all();
|
|
328
327
|
}
|
|
329
328
|
function queryDailyBreakdown(db, days = 30) {
|
|
@@ -432,118 +431,140 @@ init_database();
|
|
|
432
431
|
|
|
433
432
|
// src/ingest/claude.ts
|
|
434
433
|
init_database();
|
|
435
|
-
|
|
434
|
+
init_pricing();
|
|
435
|
+
import { readdirSync, readFileSync, existsSync as existsSync2, statSync } from "fs";
|
|
436
436
|
import { homedir as homedir2 } from "os";
|
|
437
437
|
import { join as join2, basename } from "path";
|
|
438
|
-
import { randomUUID } from "crypto";
|
|
439
|
-
var TELEMETRY_DIR = join2(homedir2(), ".claude", "telemetry");
|
|
440
438
|
var PROJECTS_DIR = join2(homedir2(), ".claude", "projects");
|
|
441
|
-
function
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
439
|
+
function dirNameToPath(dirName) {
|
|
440
|
+
return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
|
|
441
|
+
}
|
|
442
|
+
function collectJsonlFiles(projectDir) {
|
|
443
|
+
const files = [];
|
|
444
|
+
function walk(dir) {
|
|
445
|
+
try {
|
|
446
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
447
|
+
if (entry.isDirectory())
|
|
448
|
+
walk(join2(dir, entry.name));
|
|
449
|
+
else if (entry.name.endsWith(".jsonl"))
|
|
450
|
+
files.push(join2(dir, entry.name));
|
|
451
451
|
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
452
|
+
} catch {}
|
|
453
|
+
}
|
|
454
|
+
walk(projectDir);
|
|
455
|
+
return files;
|
|
455
456
|
}
|
|
456
|
-
async function ingestClaude(db, verbose = false,
|
|
457
|
-
if (!existsSync2(
|
|
457
|
+
async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
458
|
+
if (!existsSync2(PROJECTS_DIR)) {
|
|
458
459
|
if (verbose)
|
|
459
|
-
console.log("Claude
|
|
460
|
+
console.log("Claude projects dir not found:", PROJECTS_DIR);
|
|
460
461
|
return { files: 0, requests: 0, sessions: 0 };
|
|
461
462
|
}
|
|
462
|
-
|
|
463
|
+
let totalFiles = 0;
|
|
463
464
|
let totalRequests = 0;
|
|
464
|
-
let processedFiles = 0;
|
|
465
465
|
const touchedSessions = new Set;
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
for (const event of events) {
|
|
484
|
-
const ed = event.event_data;
|
|
485
|
-
if (!ed || ed.event_name !== "tengu_api_success")
|
|
466
|
+
const projectDirs = readdirSync(PROJECTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
467
|
+
for (const projectDirEntry of projectDirs) {
|
|
468
|
+
const projectDirPath = join2(PROJECTS_DIR, projectDirEntry.name);
|
|
469
|
+
const projectPath = dirNameToPath(projectDirEntry.name);
|
|
470
|
+
const projectName = basename(projectPath);
|
|
471
|
+
const jsonlFiles = collectJsonlFiles(projectDirPath);
|
|
472
|
+
for (const filePath of jsonlFiles) {
|
|
473
|
+
const stateKey = filePath.replace(PROJECTS_DIR, "");
|
|
474
|
+
let fileMtime = "0";
|
|
475
|
+
try {
|
|
476
|
+
fileMtime = statSync(filePath).mtimeMs.toString();
|
|
477
|
+
} catch {
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const processed = getIngestState(db, "claude", stateKey);
|
|
481
|
+
if (processed === fileMtime)
|
|
486
482
|
continue;
|
|
487
|
-
|
|
488
|
-
|
|
483
|
+
let lines;
|
|
484
|
+
try {
|
|
485
|
+
lines = readFileSync(filePath, "utf-8").split(`
|
|
486
|
+
`).filter((l) => l.trim());
|
|
487
|
+
} catch {
|
|
489
488
|
continue;
|
|
490
|
-
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
489
|
+
}
|
|
490
|
+
const fileBasename = basename(filePath, ".jsonl");
|
|
491
|
+
const isUuid = /^[0-9a-f-]{36}$/.test(fileBasename);
|
|
492
|
+
let sessionId = isUuid ? fileBasename : fileBasename.replace(/^agent-/, "");
|
|
493
|
+
let sessionCwd = projectPath;
|
|
494
|
+
for (const line of lines) {
|
|
495
|
+
let entry;
|
|
496
|
+
try {
|
|
497
|
+
entry = JSON.parse(line);
|
|
498
|
+
} catch {
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (entry.sessionId)
|
|
502
|
+
sessionId = entry.sessionId;
|
|
503
|
+
if (entry.cwd)
|
|
504
|
+
sessionCwd = entry.cwd;
|
|
505
|
+
if (entry.message?.role !== "assistant")
|
|
506
|
+
continue;
|
|
507
|
+
const usage = entry.message.usage;
|
|
508
|
+
if (!usage)
|
|
509
|
+
continue;
|
|
510
|
+
const model = entry.message.model;
|
|
511
|
+
if (!model)
|
|
512
|
+
continue;
|
|
513
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
514
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
515
|
+
const cacheWriteTokens = usage.cache_creation_input_tokens ?? 0;
|
|
516
|
+
const cacheReadTokens = usage.cache_read_input_tokens ?? 0;
|
|
517
|
+
const timestamp = entry.timestamp ?? new Date().toISOString();
|
|
518
|
+
if (inputTokens + outputTokens + cacheWriteTokens === 0)
|
|
519
|
+
continue;
|
|
520
|
+
const costUsd = computeCostFromDb(db, model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens);
|
|
521
|
+
const reqId = `claude-${sessionId}-${timestamp}`;
|
|
522
|
+
upsertRequest(db, {
|
|
523
|
+
id: reqId,
|
|
524
|
+
agent: "claude",
|
|
525
|
+
session_id: sessionId,
|
|
526
|
+
model,
|
|
527
|
+
input_tokens: inputTokens,
|
|
528
|
+
output_tokens: outputTokens,
|
|
529
|
+
cache_read_tokens: cacheReadTokens,
|
|
530
|
+
cache_create_tokens: cacheWriteTokens,
|
|
531
|
+
cost_usd: costUsd,
|
|
532
|
+
duration_ms: 0,
|
|
533
|
+
timestamp,
|
|
534
|
+
source_request_id: reqId
|
|
535
|
+
});
|
|
536
|
+
if (!touchedSessions.has(sessionId)) {
|
|
537
|
+
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
538
|
+
if (!existing) {
|
|
539
|
+
const session = {
|
|
540
|
+
id: sessionId,
|
|
541
|
+
agent: "claude",
|
|
542
|
+
project_path: sessionCwd || projectPath,
|
|
543
|
+
project_name: basename(sessionCwd || projectPath),
|
|
544
|
+
started_at: timestamp,
|
|
545
|
+
ended_at: null,
|
|
546
|
+
total_cost_usd: 0,
|
|
547
|
+
total_tokens: 0,
|
|
548
|
+
request_count: 0
|
|
549
|
+
};
|
|
550
|
+
upsertSession(db, session);
|
|
551
|
+
}
|
|
552
|
+
touchedSessions.add(sessionId);
|
|
528
553
|
}
|
|
529
|
-
|
|
554
|
+
totalRequests++;
|
|
530
555
|
}
|
|
531
|
-
|
|
556
|
+
setIngestState(db, "claude", stateKey, fileMtime);
|
|
557
|
+
totalFiles++;
|
|
532
558
|
}
|
|
533
|
-
setIngestState(db, "claude", stateKey, "done");
|
|
534
|
-
processedFiles++;
|
|
535
|
-
if (verbose)
|
|
536
|
-
console.log(`Processed ${filename}: found ${events.length} events`);
|
|
537
559
|
}
|
|
538
560
|
for (const sessionId of touchedSessions) {
|
|
539
561
|
rollupSession(db, sessionId);
|
|
540
562
|
}
|
|
541
|
-
return { files:
|
|
563
|
+
return { files: totalFiles, requests: totalRequests, sessions: touchedSessions.size };
|
|
542
564
|
}
|
|
543
565
|
|
|
544
566
|
// src/ingest/codex.ts
|
|
545
567
|
init_database();
|
|
546
|
-
init_pricing();
|
|
547
568
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
548
569
|
import { homedir as homedir3 } from "os";
|
|
549
570
|
import { join as join3, basename as basename2 } from "path";
|
|
@@ -578,9 +599,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
578
599
|
const processed = getIngestState(db, "codex", stateKey);
|
|
579
600
|
if (processed === "done")
|
|
580
601
|
continue;
|
|
581
|
-
const
|
|
582
|
-
const outputTokens = thread.tokens_used - inputTokens;
|
|
583
|
-
const costUsd = computeCost(model, inputTokens, outputTokens);
|
|
602
|
+
const costUsd = 0;
|
|
584
603
|
const projectPath = thread.cwd ?? "";
|
|
585
604
|
const projectName = projectPath ? basename2(projectPath) : "unknown";
|
|
586
605
|
const startedAt = thread.created_at ? new Date(thread.created_at * 1000).toISOString() : new Date().toISOString();
|
|
@@ -609,7 +628,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
609
628
|
|
|
610
629
|
// src/server/serve.ts
|
|
611
630
|
init_pricing();
|
|
612
|
-
import { randomUUID
|
|
631
|
+
import { randomUUID } from "crypto";
|
|
613
632
|
var CORS = {
|
|
614
633
|
"Access-Control-Allow-Origin": "*",
|
|
615
634
|
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS",
|
|
@@ -675,7 +694,7 @@ function createHandler(db) {
|
|
|
675
694
|
const body = await req.json();
|
|
676
695
|
const now = new Date().toISOString();
|
|
677
696
|
upsertBudget(db, {
|
|
678
|
-
id:
|
|
697
|
+
id: randomUUID(),
|
|
679
698
|
project_path: body["project_path"] ?? null,
|
|
680
699
|
agent: body["agent"] ?? null,
|
|
681
700
|
period: body["period"] ?? "monthly",
|
|
@@ -699,7 +718,7 @@ function createHandler(db) {
|
|
|
699
718
|
const { basename: basename3 } = await import("path");
|
|
700
719
|
const projPath = body["path"];
|
|
701
720
|
upsertProject(db, {
|
|
702
|
-
id:
|
|
721
|
+
id: randomUUID(),
|
|
703
722
|
path: projPath,
|
|
704
723
|
name: body["name"] ?? basename3(projPath),
|
|
705
724
|
description: body["description"] ?? null,
|
|
@@ -749,8 +768,32 @@ function createHandler(db) {
|
|
|
749
768
|
function startServer(port = 3456) {
|
|
750
769
|
const db = openDatabase();
|
|
751
770
|
ensurePricingSeeded(db);
|
|
752
|
-
const
|
|
753
|
-
|
|
771
|
+
const apiHandler = createHandler(db);
|
|
772
|
+
const dashboardDir = new URL("../../dashboard/dist", import.meta.url).pathname;
|
|
773
|
+
Bun.serve({
|
|
774
|
+
port,
|
|
775
|
+
async fetch(req) {
|
|
776
|
+
const url = new URL(req.url);
|
|
777
|
+
if (url.pathname.startsWith("/api") || url.pathname === "/health") {
|
|
778
|
+
return apiHandler(req);
|
|
779
|
+
}
|
|
780
|
+
try {
|
|
781
|
+
const { existsSync: existsSync4 } = await import("fs");
|
|
782
|
+
if (existsSync4(dashboardDir)) {
|
|
783
|
+
let filePath = url.pathname === "/" ? "/index.html" : url.pathname;
|
|
784
|
+
const fullPath = dashboardDir + filePath;
|
|
785
|
+
if (existsSync4(fullPath)) {
|
|
786
|
+
return new Response(Bun.file(fullPath));
|
|
787
|
+
}
|
|
788
|
+
const indexPath = dashboardDir + "/index.html";
|
|
789
|
+
if (existsSync4(indexPath)) {
|
|
790
|
+
return new Response(Bun.file(indexPath));
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
} catch {}
|
|
794
|
+
return apiHandler(req);
|
|
795
|
+
}
|
|
796
|
+
});
|
|
754
797
|
console.log(`economy-serve listening on http://localhost:${port}`);
|
|
755
798
|
}
|
|
756
799
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAoC1C,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA2I/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,GAAG,IAAI,CAuC7C"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export type Agent = 'claude' | 'codex' | 'gemini';
|
|
2
|
+
export type Period = 'today' | 'week' | 'month' | 'all';
|
|
3
|
+
export interface EconomyRequest {
|
|
4
|
+
id: string;
|
|
5
|
+
agent: Agent;
|
|
6
|
+
session_id: string;
|
|
7
|
+
model: string;
|
|
8
|
+
input_tokens: number;
|
|
9
|
+
output_tokens: number;
|
|
10
|
+
cache_read_tokens: number;
|
|
11
|
+
cache_create_tokens: number;
|
|
12
|
+
cost_usd: number;
|
|
13
|
+
duration_ms: number;
|
|
14
|
+
timestamp: string;
|
|
15
|
+
source_request_id: string;
|
|
16
|
+
}
|
|
17
|
+
export interface EconomySession {
|
|
18
|
+
id: string;
|
|
19
|
+
agent: Agent;
|
|
20
|
+
project_path: string;
|
|
21
|
+
project_name: string;
|
|
22
|
+
started_at: string;
|
|
23
|
+
ended_at: string | null;
|
|
24
|
+
total_cost_usd: number;
|
|
25
|
+
total_tokens: number;
|
|
26
|
+
request_count: number;
|
|
27
|
+
}
|
|
28
|
+
export interface EconomyProject {
|
|
29
|
+
id: string;
|
|
30
|
+
path: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description: string | null;
|
|
33
|
+
tags: string[];
|
|
34
|
+
created_at: string;
|
|
35
|
+
}
|
|
36
|
+
export interface Budget {
|
|
37
|
+
id: string;
|
|
38
|
+
project_path: string | null;
|
|
39
|
+
agent: Agent | null;
|
|
40
|
+
period: 'daily' | 'weekly' | 'monthly';
|
|
41
|
+
limit_usd: number;
|
|
42
|
+
alert_at_percent: number;
|
|
43
|
+
created_at: string;
|
|
44
|
+
updated_at: string;
|
|
45
|
+
}
|
|
46
|
+
export interface BudgetStatus extends Budget {
|
|
47
|
+
current_spend_usd: number;
|
|
48
|
+
percent_used: number;
|
|
49
|
+
is_over_limit: boolean;
|
|
50
|
+
is_over_alert: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface IngestState {
|
|
53
|
+
source: string;
|
|
54
|
+
key: string;
|
|
55
|
+
value: string;
|
|
56
|
+
}
|
|
57
|
+
export interface CostSummary {
|
|
58
|
+
total_usd: number;
|
|
59
|
+
sessions: number;
|
|
60
|
+
requests: number;
|
|
61
|
+
tokens: number;
|
|
62
|
+
period: Period;
|
|
63
|
+
}
|
|
64
|
+
export interface ModelBreakdown {
|
|
65
|
+
model: string;
|
|
66
|
+
agent: Agent;
|
|
67
|
+
requests: number;
|
|
68
|
+
input_tokens: number;
|
|
69
|
+
output_tokens: number;
|
|
70
|
+
total_tokens: number;
|
|
71
|
+
cost_usd: number;
|
|
72
|
+
}
|
|
73
|
+
export interface ProjectBreakdown {
|
|
74
|
+
project_path: string;
|
|
75
|
+
project_name: string;
|
|
76
|
+
sessions: number;
|
|
77
|
+
requests: number;
|
|
78
|
+
total_tokens: number;
|
|
79
|
+
cost_usd: number;
|
|
80
|
+
last_active: string;
|
|
81
|
+
}
|
|
82
|
+
export interface ModelPricing {
|
|
83
|
+
inputPer1M: number;
|
|
84
|
+
outputPer1M: number;
|
|
85
|
+
cacheReadPer1M: number;
|
|
86
|
+
cacheWritePer1M: number;
|
|
87
|
+
}
|
|
88
|
+
export interface SyncOptions {
|
|
89
|
+
claude?: boolean;
|
|
90
|
+
codex?: boolean;
|
|
91
|
+
verbose?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface SessionFilter {
|
|
94
|
+
agent?: Agent;
|
|
95
|
+
project?: string;
|
|
96
|
+
limit?: number;
|
|
97
|
+
offset?: number;
|
|
98
|
+
since?: string;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/economy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, and Gemini",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,10 @@
|
|
|
16
16
|
"import": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
|
-
"files": [
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
20
23
|
"scripts": {
|
|
21
24
|
"build": "cd dashboard && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
22
25
|
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
@@ -30,7 +33,18 @@
|
|
|
30
33
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
31
34
|
"dev:serve": "bun run src/server/index.ts"
|
|
32
35
|
},
|
|
33
|
-
"keywords": [
|
|
36
|
+
"keywords": [
|
|
37
|
+
"economy",
|
|
38
|
+
"cost",
|
|
39
|
+
"ai",
|
|
40
|
+
"claude",
|
|
41
|
+
"codex",
|
|
42
|
+
"gemini",
|
|
43
|
+
"mcp",
|
|
44
|
+
"cli",
|
|
45
|
+
"budget",
|
|
46
|
+
"tracking"
|
|
47
|
+
],
|
|
34
48
|
"author": "hasna",
|
|
35
49
|
"license": "Apache-2.0",
|
|
36
50
|
"publishConfig": {
|