@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.
@@ -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: 15, outputPer1M: 75, cacheReadPer1M: 1.5, cacheWritePer1M: 18.75 },
93
- "claude-opus-4-5": { inputPer1M: 15, outputPer1M: 75, cacheReadPer1M: 1.5, cacheWritePer1M: 18.75 },
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: 0.8, outputPer1M: 4, cacheReadPer1M: 0.08, cacheWritePer1M: 1 },
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: 0.8, outputPer1M: 4, cacheReadPer1M: 0.08, cacheWritePer1M: 1 },
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: 30, outputPer1M: 120, cacheReadPer1M: 7.5, cacheWritePer1M: 0 },
103
- "gpt-5.2-codex": { inputPer1M: 30, outputPer1M: 120, cacheReadPer1M: 7.5, cacheWritePer1M: 0 },
104
- "gpt-5-codex": { inputPer1M: 30, outputPer1M: 120, cacheReadPer1M: 7.5, cacheWritePer1M: 0 },
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 s = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}`).get();
304
- return { total_usd: r.total_usd, requests: r.requests, tokens: r.tokens, sessions: s.sessions, period };
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 s.project_path, s.project_name,
320
- COUNT(DISTINCT s.id) as sessions,
321
- COALESCE(SUM(r.input_tokens + r.output_tokens + r.cache_read_tokens + r.cache_create_tokens), 0) as total_tokens,
322
- COUNT(r.id) as requests,
323
- COALESCE(SUM(s.total_cost_usd), 0) as cost_usd,
324
- MAX(s.started_at) as last_active
325
- FROM sessions s LEFT JOIN requests r ON r.session_id = s.id
326
- GROUP BY s.project_path ORDER BY cost_usd DESC
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
- import { readdirSync, readFileSync, existsSync as existsSync2 } from "fs";
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 resolveProjectPath(sessionId) {
442
- if (!existsSync2(PROJECTS_DIR))
443
- return { projectPath: "", projectName: "unknown" };
444
- try {
445
- const projectDirs = readdirSync(PROJECTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
446
- for (const dir of projectDirs) {
447
- const sessionFile = join2(PROJECTS_DIR, dir.name, `${sessionId}.jsonl`);
448
- if (existsSync2(sessionFile)) {
449
- const projectPath = dir.name.replace(/^-/, "/").replace(/-/g, "/");
450
- return { projectPath, projectName: basename(projectPath) };
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
- } catch {}
454
- return { projectPath: "", projectName: "unknown" };
452
+ } catch {}
453
+ }
454
+ walk(projectDir);
455
+ return files;
455
456
  }
456
- async function ingestClaude(db, verbose = false, telemetryDir = TELEMETRY_DIR) {
457
- if (!existsSync2(telemetryDir)) {
457
+ async function ingestClaude(db, verbose = false, _telemetryDir) {
458
+ if (!existsSync2(PROJECTS_DIR)) {
458
459
  if (verbose)
459
- console.log("Claude telemetry dir not found:", telemetryDir);
460
+ console.log("Claude projects dir not found:", PROJECTS_DIR);
460
461
  return { files: 0, requests: 0, sessions: 0 };
461
462
  }
462
- const files = readdirSync(telemetryDir).filter((f) => f.endsWith(".json"));
463
+ let totalFiles = 0;
463
464
  let totalRequests = 0;
464
- let processedFiles = 0;
465
465
  const touchedSessions = new Set;
466
- for (const filename of files) {
467
- const stateKey = filename;
468
- const processed = getIngestState(db, "claude", stateKey);
469
- if (processed === "done")
470
- continue;
471
- const filePath = join2(telemetryDir, filename);
472
- let events;
473
- try {
474
- const raw = readFileSync(filePath, "utf-8");
475
- events = JSON.parse(raw);
476
- if (!Array.isArray(events))
477
- events = [events];
478
- } catch {
479
- if (verbose)
480
- console.log("Skip unreadable:", filename);
481
- continue;
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
- const meta = ed.additional_metadata;
488
- if (!meta)
483
+ let lines;
484
+ try {
485
+ lines = readFileSync(filePath, "utf-8").split(`
486
+ `).filter((l) => l.trim());
487
+ } catch {
489
488
  continue;
490
- const sessionId = ed.session_id ?? randomUUID();
491
- const timestamp = ed.client_timestamp ?? new Date().toISOString();
492
- const model = meta.model ?? ed.model ?? "unknown";
493
- const costUsd = meta.costUSD ?? 0;
494
- const inputTokens = meta.inputTokens ?? (meta.uncachedInputTokens ?? 0);
495
- const outputTokens = meta.outputTokens ?? 0;
496
- const cacheReadTokens = meta.cachedInputTokens ?? 0;
497
- const requestId = meta.requestId ?? randomUUID();
498
- upsertRequest(db, {
499
- id: `claude-${requestId}`,
500
- agent: "claude",
501
- session_id: sessionId,
502
- model,
503
- input_tokens: inputTokens,
504
- output_tokens: outputTokens,
505
- cache_read_tokens: cacheReadTokens,
506
- cache_create_tokens: 0,
507
- cost_usd: costUsd,
508
- duration_ms: meta.durationMs ?? 0,
509
- timestamp,
510
- source_request_id: requestId
511
- });
512
- if (!touchedSessions.has(sessionId)) {
513
- const { projectPath, projectName } = resolveProjectPath(sessionId);
514
- const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
515
- if (!existing) {
516
- const session = {
517
- id: sessionId,
518
- agent: "claude",
519
- project_path: projectPath,
520
- project_name: projectName,
521
- started_at: timestamp,
522
- ended_at: null,
523
- total_cost_usd: 0,
524
- total_tokens: 0,
525
- request_count: 0
526
- };
527
- upsertSession(db, session);
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
- touchedSessions.add(sessionId);
554
+ totalRequests++;
530
555
  }
531
- totalRequests++;
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: processedFiles, requests: totalRequests, sessions: touchedSessions.size };
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 inputTokens = Math.floor(thread.tokens_used * 0.6);
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 as randomUUID2 } from "crypto";
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: randomUUID2(),
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: randomUUID2(),
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 handler = createHandler(db);
753
- Bun.serve({ port, fetch: handler });
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,4 @@
1
+ import type { Database } from 'bun:sqlite';
2
+ export declare function createHandler(db: Database): (req: Request) => Promise<Response>;
3
+ export declare function startServer(port?: number): void;
4
+ //# sourceMappingURL=serve.d.ts.map
@@ -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.1.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": ["dist", "LICENSE"],
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": ["economy", "cost", "ai", "claude", "codex", "gemini", "mcp", "cli", "budget", "tracking"],
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": {