@hasna/economy 0.2.10 → 0.2.11
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/README.md +37 -45
- package/dist/cli/index.js +127 -82
- package/dist/index.js +2 -2
- package/dist/ingest/claude.d.ts +1 -1
- package/dist/ingest/claude.d.ts.map +1 -1
- package/dist/ingest/codex.d.ts +1 -1
- package/dist/ingest/codex.d.ts.map +1 -1
- package/dist/ingest/gemini.d.ts +1 -1
- package/dist/ingest/gemini.d.ts.map +1 -1
- package/dist/lib/package-metadata.d.ts +8 -0
- package/dist/lib/package-metadata.d.ts.map +1 -0
- package/dist/lib/pricing.d.ts +1 -1
- package/dist/lib/pricing.d.ts.map +1 -1
- package/dist/lib/webhooks.d.ts +1 -1
- package/dist/lib/webhooks.d.ts.map +1 -1
- package/dist/mcp/index.js +305 -331
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +168 -10
- package/dist/server/serve.d.ts +1 -1
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,69 +1,61 @@
|
|
|
1
1
|
# @hasna/economy
|
|
2
2
|
|
|
3
|
-
AI coding cost tracker for Claude Code, Codex, and Gemini
|
|
3
|
+
AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, and Gemini
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- **Claude Code** — exact costs from telemetry JSONL (`costUSD` per request)
|
|
10
|
-
- **Codex** — estimated costs from token count × model pricing
|
|
11
|
-
- **SQLite backend** — all data stored locally at `~/.economy/economy.db`
|
|
12
|
-
- **DB-backed pricing** — model rates editable via CLI, seeded from defaults
|
|
13
|
-
- **CLI** — `economy sync`, `economy today`, `economy sessions`, `economy watch`, etc.
|
|
14
|
-
- **Live watch** — `economy watch` streams costs as they arrive
|
|
15
|
-
- **Budgets** — set per-project or global budgets with alert thresholds
|
|
16
|
-
- **MCP server** — agents can query their own costs
|
|
17
|
-
- **REST API** — `economy serve` on port 3456
|
|
18
|
-
- **Web dashboard** — charts, sessions table, model/project breakdown
|
|
19
|
-
- **macOS menubar** — live cost display in your menu bar
|
|
20
|
-
- **SDK** — `@hasna/economy-sdk` for programmatic access
|
|
5
|
+
[](https://www.npmjs.com/package/@hasna/economy)
|
|
6
|
+
[](LICENSE)
|
|
21
7
|
|
|
22
8
|
## Install
|
|
23
9
|
|
|
24
10
|
```bash
|
|
25
|
-
bun
|
|
26
|
-
economy sync
|
|
27
|
-
economy today
|
|
11
|
+
bun install -g @hasna/economy
|
|
28
12
|
```
|
|
29
13
|
|
|
30
|
-
## Usage
|
|
14
|
+
## CLI Usage
|
|
31
15
|
|
|
32
16
|
```bash
|
|
33
|
-
economy
|
|
34
|
-
economy today # today's cost summary
|
|
35
|
-
economy week # this week
|
|
36
|
-
economy month # this month
|
|
37
|
-
economy sessions # list sessions with costs
|
|
38
|
-
economy top # most expensive sessions
|
|
39
|
-
economy watch # live cost stream
|
|
40
|
-
economy breakdown # by model/agent/project
|
|
41
|
-
economy budget set --period monthly --limit 100
|
|
42
|
-
economy budget list
|
|
43
|
-
economy project add /path/to/project --name "My Project"
|
|
44
|
-
economy pricing list
|
|
45
|
-
economy pricing set gpt-4o --input 2.50 --output 10.00
|
|
46
|
-
economy serve # start REST API on port 3456
|
|
47
|
-
economy dashboard # open web dashboard
|
|
48
|
-
economy mcp --all # show MCP install commands
|
|
17
|
+
economy --help
|
|
49
18
|
```
|
|
50
19
|
|
|
51
20
|
## MCP Server
|
|
52
21
|
|
|
53
22
|
```bash
|
|
54
|
-
|
|
23
|
+
economy-mcp --help
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## REST API
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
economy-serve --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Native macOS Menubar
|
|
33
|
+
|
|
34
|
+
The `menubar/` app is a native SwiftUI menu bar app built with `MenuBarExtra`, not Electron. It targets macOS 26 and talks to the REST API exposed by `economy-serve`. The server URL is configurable inside the app and defaults to `http://127.0.0.1:3456`.
|
|
35
|
+
|
|
36
|
+
Build it on macOS with Xcode / Swift 6.2:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd menubar
|
|
40
|
+
swift build -c release
|
|
55
41
|
```
|
|
56
42
|
|
|
57
|
-
##
|
|
43
|
+
## Cloud Sync
|
|
58
44
|
|
|
59
|
-
|
|
60
|
-
import { EconomyClient } from '@hasna/economy-sdk'
|
|
45
|
+
This package supports cloud sync via `@hasna/cloud`:
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
```bash
|
|
48
|
+
cloud setup
|
|
49
|
+
cloud sync push --service economy
|
|
50
|
+
cloud sync pull --service economy
|
|
65
51
|
```
|
|
66
52
|
|
|
53
|
+
## Data Directory
|
|
54
|
+
|
|
55
|
+
Data is stored in `~/.hasna/economy/`.
|
|
56
|
+
|
|
57
|
+
The main SQLite database lives at `~/.hasna/economy/economy.db`. Older `~/.economy/` data is auto-migrated on first open.
|
|
58
|
+
|
|
67
59
|
## License
|
|
68
60
|
|
|
69
|
-
Apache-2.0
|
|
61
|
+
Apache-2.0 -- see [LICENSE](LICENSE)
|
package/dist/cli/index.js
CHANGED
|
@@ -689,7 +689,7 @@ var init_claude = __esm(() => {
|
|
|
689
689
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
690
690
|
import { homedir as homedir3 } from "os";
|
|
691
691
|
import { join as join5, basename as basename2 } from "path";
|
|
692
|
-
import { Database as
|
|
692
|
+
import { Database as BunDatabase } from "bun:sqlite";
|
|
693
693
|
async function ingestCodex(db, verbose = false) {
|
|
694
694
|
if (!existsSync4(CODEX_DB_PATH)) {
|
|
695
695
|
if (verbose)
|
|
@@ -699,7 +699,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
699
699
|
let codexDb = null;
|
|
700
700
|
let ingested = 0;
|
|
701
701
|
try {
|
|
702
|
-
codexDb = new
|
|
702
|
+
codexDb = new BunDatabase(CODEX_DB_PATH, { readonly: true });
|
|
703
703
|
const threads = codexDb.prepare(`SELECT id, cwd, created_at, updated_at, tokens_used, title FROM threads WHERE tokens_used > 0`).all();
|
|
704
704
|
for (const thread of threads) {
|
|
705
705
|
const stateKey = thread.id;
|
|
@@ -739,6 +739,86 @@ var init_codex = __esm(() => {
|
|
|
739
739
|
CODEX_CONFIG_PATH = join5(homedir3(), ".codex", "config.toml");
|
|
740
740
|
});
|
|
741
741
|
|
|
742
|
+
// src/ingest/gemini.ts
|
|
743
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync4, existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
744
|
+
import { homedir as homedir4 } from "os";
|
|
745
|
+
import { join as join6 } from "path";
|
|
746
|
+
async function ingestGemini(db, verbose) {
|
|
747
|
+
if (!existsSync5(GEMINI_TMP_DIR)) {
|
|
748
|
+
if (verbose)
|
|
749
|
+
console.log("Gemini tmp dir not found:", GEMINI_TMP_DIR);
|
|
750
|
+
return { sessions: 0 };
|
|
751
|
+
}
|
|
752
|
+
let totalSessions = 0;
|
|
753
|
+
const touchedSessions = new Set;
|
|
754
|
+
let projectHashDirs = [];
|
|
755
|
+
try {
|
|
756
|
+
projectHashDirs = readdirSync3(GEMINI_TMP_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && /^[0-9a-f]{64}$/.test(d.name)).map((d) => join6(GEMINI_TMP_DIR, d.name));
|
|
757
|
+
} catch {
|
|
758
|
+
return { sessions: 0 };
|
|
759
|
+
}
|
|
760
|
+
for (const projectDir of projectHashDirs) {
|
|
761
|
+
const chatsDir = join6(projectDir, "chats");
|
|
762
|
+
if (!existsSync5(chatsDir))
|
|
763
|
+
continue;
|
|
764
|
+
let chatFiles = [];
|
|
765
|
+
try {
|
|
766
|
+
chatFiles = readdirSync3(chatsDir).filter((f) => f.endsWith(".json")).map((f) => join6(chatsDir, f));
|
|
767
|
+
} catch {
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
for (const filePath of chatFiles) {
|
|
771
|
+
const stateKey = filePath.replace(homedir4(), "~");
|
|
772
|
+
let fileMtime = "0";
|
|
773
|
+
try {
|
|
774
|
+
fileMtime = statSync3(filePath).mtimeMs.toString();
|
|
775
|
+
} catch {
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
const processed = getIngestState(db, "gemini", stateKey);
|
|
779
|
+
if (processed === fileMtime)
|
|
780
|
+
continue;
|
|
781
|
+
let chatData;
|
|
782
|
+
try {
|
|
783
|
+
chatData = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
784
|
+
} catch {
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
const sessionId = chatData.sessionId;
|
|
788
|
+
if (!sessionId)
|
|
789
|
+
continue;
|
|
790
|
+
const startTime = chatData.startTime ?? new Date().toISOString();
|
|
791
|
+
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
792
|
+
if (!existing) {
|
|
793
|
+
const session = {
|
|
794
|
+
id: sessionId,
|
|
795
|
+
agent: "gemini",
|
|
796
|
+
project_path: "",
|
|
797
|
+
project_name: "",
|
|
798
|
+
started_at: startTime,
|
|
799
|
+
ended_at: chatData.lastUpdated ?? null,
|
|
800
|
+
total_cost_usd: 0,
|
|
801
|
+
total_tokens: 0,
|
|
802
|
+
request_count: 0
|
|
803
|
+
};
|
|
804
|
+
upsertSession(db, session);
|
|
805
|
+
touchedSessions.add(sessionId);
|
|
806
|
+
totalSessions++;
|
|
807
|
+
}
|
|
808
|
+
setIngestState(db, "gemini", stateKey, fileMtime);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
for (const sessionId of touchedSessions) {
|
|
812
|
+
rollupSession(db, sessionId);
|
|
813
|
+
}
|
|
814
|
+
return { sessions: totalSessions };
|
|
815
|
+
}
|
|
816
|
+
var GEMINI_TMP_DIR;
|
|
817
|
+
var init_gemini = __esm(() => {
|
|
818
|
+
init_database();
|
|
819
|
+
GEMINI_TMP_DIR = join6(homedir4(), ".gemini", "tmp");
|
|
820
|
+
});
|
|
821
|
+
|
|
742
822
|
// src/lib/config.ts
|
|
743
823
|
var exports_config = {};
|
|
744
824
|
__export(exports_config, {
|
|
@@ -747,12 +827,12 @@ __export(exports_config, {
|
|
|
747
827
|
loadConfig: () => loadConfig2,
|
|
748
828
|
getConfigValue: () => getConfigValue
|
|
749
829
|
});
|
|
750
|
-
import { existsSync as existsSync6, readFileSync as
|
|
830
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
751
831
|
import { join as join7 } from "path";
|
|
752
832
|
function loadConfig2() {
|
|
753
833
|
try {
|
|
754
834
|
if (existsSync6(CONFIG_PATH2)) {
|
|
755
|
-
const raw =
|
|
835
|
+
const raw = readFileSync6(CONFIG_PATH2, "utf-8");
|
|
756
836
|
return { ...DEFAULTS, ...JSON.parse(raw) };
|
|
757
837
|
}
|
|
758
838
|
} catch {}
|
|
@@ -962,6 +1042,20 @@ function ok(data, meta) {
|
|
|
962
1042
|
function err(message, status = 400) {
|
|
963
1043
|
return json({ error: message }, status);
|
|
964
1044
|
}
|
|
1045
|
+
function normalizeBudgetPeriod(value) {
|
|
1046
|
+
switch (value) {
|
|
1047
|
+
case "day":
|
|
1048
|
+
case "daily":
|
|
1049
|
+
return "daily";
|
|
1050
|
+
case "week":
|
|
1051
|
+
case "weekly":
|
|
1052
|
+
return "weekly";
|
|
1053
|
+
case "month":
|
|
1054
|
+
case "monthly":
|
|
1055
|
+
default:
|
|
1056
|
+
return "monthly";
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
965
1059
|
function applyFields(obj, fields) {
|
|
966
1060
|
if (!fields || fields.length === 0)
|
|
967
1061
|
return obj;
|
|
@@ -987,12 +1081,20 @@ function createHandler(db) {
|
|
|
987
1081
|
if (path === "/api/sessions" && method === "GET") {
|
|
988
1082
|
const agent = url.searchParams.get("agent");
|
|
989
1083
|
const project = url.searchParams.get("project") ?? undefined;
|
|
1084
|
+
const search = url.searchParams.get("search") ?? undefined;
|
|
990
1085
|
const limit = Number(url.searchParams.get("limit") ?? 50);
|
|
991
1086
|
const offset = Number(url.searchParams.get("offset") ?? 0);
|
|
992
1087
|
const since = url.searchParams.get("since") ?? undefined;
|
|
993
1088
|
const fieldsParam = url.searchParams.get("fields");
|
|
994
1089
|
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
995
|
-
const sessions = querySessions(db, {
|
|
1090
|
+
const sessions = querySessions(db, {
|
|
1091
|
+
agent: agent ?? undefined,
|
|
1092
|
+
project,
|
|
1093
|
+
search,
|
|
1094
|
+
limit,
|
|
1095
|
+
offset,
|
|
1096
|
+
since
|
|
1097
|
+
});
|
|
996
1098
|
return ok(fields ? sessions.map((s) => applyFields(s, fields)) : sessions, { limit, offset });
|
|
997
1099
|
}
|
|
998
1100
|
if (path === "/api/top" && method === "GET") {
|
|
@@ -1020,7 +1122,7 @@ function createHandler(db) {
|
|
|
1020
1122
|
id: randomUUID(),
|
|
1021
1123
|
project_path: body["project_path"] ?? null,
|
|
1022
1124
|
agent: body["agent"] ?? null,
|
|
1023
|
-
period: body["period"]
|
|
1125
|
+
period: normalizeBudgetPeriod(body["period"]),
|
|
1024
1126
|
limit_usd: Number(body["limit_usd"]),
|
|
1025
1127
|
alert_at_percent: Number(body["alert_at_percent"] ?? 80),
|
|
1026
1128
|
created_at: now,
|
|
@@ -1083,6 +1185,8 @@ function createHandler(db) {
|
|
|
1083
1185
|
results["claude"] = await ingestClaude(db);
|
|
1084
1186
|
if (sources === "all" || sources === "codex")
|
|
1085
1187
|
results["codex"] = await ingestCodex(db);
|
|
1188
|
+
if (sources === "all" || sources === "gemini")
|
|
1189
|
+
results["gemini"] = await ingestGemini(db);
|
|
1086
1190
|
return ok(results);
|
|
1087
1191
|
}
|
|
1088
1192
|
const sessionRequestsMatch = path.match(/^\/api\/sessions\/([^/]+)\/requests$/);
|
|
@@ -1155,6 +1259,7 @@ var init_serve = __esm(() => {
|
|
|
1155
1259
|
init_database();
|
|
1156
1260
|
init_claude();
|
|
1157
1261
|
init_codex();
|
|
1262
|
+
init_gemini();
|
|
1158
1263
|
init_pricing();
|
|
1159
1264
|
CORS = {
|
|
1160
1265
|
"Access-Control-Allow-Origin": "*",
|
|
@@ -1650,90 +1755,30 @@ ${chalk.dim("Set it active:")} economy brains model set ${String(status["fine_tu
|
|
|
1650
1755
|
init_database();
|
|
1651
1756
|
init_claude();
|
|
1652
1757
|
init_codex();
|
|
1758
|
+
init_gemini();
|
|
1653
1759
|
|
|
1654
|
-
// src/
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
const touchedSessions = new Set;
|
|
1668
|
-
let projectHashDirs = [];
|
|
1669
|
-
try {
|
|
1670
|
-
projectHashDirs = readdirSync3(GEMINI_TMP_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && /^[0-9a-f]{64}$/.test(d.name)).map((d) => join6(GEMINI_TMP_DIR, d.name));
|
|
1671
|
-
} catch {
|
|
1672
|
-
return { sessions: 0 };
|
|
1673
|
-
}
|
|
1674
|
-
for (const projectDir of projectHashDirs) {
|
|
1675
|
-
const chatsDir = join6(projectDir, "chats");
|
|
1676
|
-
if (!existsSync5(chatsDir))
|
|
1677
|
-
continue;
|
|
1678
|
-
let chatFiles = [];
|
|
1679
|
-
try {
|
|
1680
|
-
chatFiles = readdirSync3(chatsDir).filter((f) => f.endsWith(".json")).map((f) => join6(chatsDir, f));
|
|
1681
|
-
} catch {
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
for (const filePath of chatFiles) {
|
|
1685
|
-
const stateKey = filePath.replace(homedir4(), "~");
|
|
1686
|
-
let fileMtime = "0";
|
|
1687
|
-
try {
|
|
1688
|
-
fileMtime = statSync3(filePath).mtimeMs.toString();
|
|
1689
|
-
} catch {
|
|
1690
|
-
continue;
|
|
1691
|
-
}
|
|
1692
|
-
const processed = getIngestState(db, "gemini", stateKey);
|
|
1693
|
-
if (processed === fileMtime)
|
|
1694
|
-
continue;
|
|
1695
|
-
let chatData;
|
|
1696
|
-
try {
|
|
1697
|
-
chatData = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
1698
|
-
} catch {
|
|
1699
|
-
continue;
|
|
1700
|
-
}
|
|
1701
|
-
const sessionId = chatData.sessionId;
|
|
1702
|
-
if (!sessionId)
|
|
1703
|
-
continue;
|
|
1704
|
-
const startTime = chatData.startTime ?? new Date().toISOString();
|
|
1705
|
-
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
1706
|
-
if (!existing) {
|
|
1707
|
-
const session = {
|
|
1708
|
-
id: sessionId,
|
|
1709
|
-
agent: "gemini",
|
|
1710
|
-
project_path: "",
|
|
1711
|
-
project_name: "",
|
|
1712
|
-
started_at: startTime,
|
|
1713
|
-
ended_at: chatData.lastUpdated ?? null,
|
|
1714
|
-
total_cost_usd: 0,
|
|
1715
|
-
total_tokens: 0,
|
|
1716
|
-
request_count: 0
|
|
1717
|
-
};
|
|
1718
|
-
upsertSession(db, session);
|
|
1719
|
-
touchedSessions.add(sessionId);
|
|
1720
|
-
totalSessions++;
|
|
1721
|
-
}
|
|
1722
|
-
setIngestState(db, "gemini", stateKey, fileMtime);
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
for (const sessionId of touchedSessions) {
|
|
1726
|
-
rollupSession(db, sessionId);
|
|
1727
|
-
}
|
|
1728
|
-
return { sessions: totalSessions };
|
|
1760
|
+
// src/lib/package-metadata.ts
|
|
1761
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
1762
|
+
var cachedMetadata = null;
|
|
1763
|
+
function getPackageMetadata() {
|
|
1764
|
+
if (cachedMetadata)
|
|
1765
|
+
return cachedMetadata;
|
|
1766
|
+
const raw = readFileSync5(new URL("../../package.json", import.meta.url), "utf8");
|
|
1767
|
+
const parsed = JSON.parse(raw);
|
|
1768
|
+
cachedMetadata = {
|
|
1769
|
+
name: parsed.name ?? "@hasna/economy",
|
|
1770
|
+
version: parsed.version ?? "0.0.0"
|
|
1771
|
+
};
|
|
1772
|
+
return cachedMetadata;
|
|
1729
1773
|
}
|
|
1774
|
+
var packageMetadata = getPackageMetadata();
|
|
1730
1775
|
|
|
1731
1776
|
// src/cli/index.ts
|
|
1732
1777
|
init_pricing();
|
|
1733
1778
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1734
1779
|
import { execSync as execSync2 } from "child_process";
|
|
1735
1780
|
var program = new Command;
|
|
1736
|
-
program.name("economy").description("AI coding cost tracker \u2014 Claude Code, Codex, and Gemini").version(
|
|
1781
|
+
program.name("economy").description("AI coding cost tracker \u2014 Claude Code, Codex, and Gemini").version(packageMetadata.version);
|
|
1737
1782
|
async function autoSync() {
|
|
1738
1783
|
const db = openDatabase();
|
|
1739
1784
|
ensurePricingSeeded(db);
|
package/dist/index.js
CHANGED
|
@@ -903,7 +903,7 @@ init_database();
|
|
|
903
903
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
904
904
|
import { homedir as homedir3 } from "os";
|
|
905
905
|
import { join as join4, basename as basename2 } from "path";
|
|
906
|
-
import { Database as
|
|
906
|
+
import { Database as BunDatabase } from "bun:sqlite";
|
|
907
907
|
var CODEX_DB_PATH = join4(homedir3(), ".codex", "state_5.sqlite");
|
|
908
908
|
var CODEX_CONFIG_PATH = join4(homedir3(), ".codex", "config.toml");
|
|
909
909
|
function readCodexModel() {
|
|
@@ -926,7 +926,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
926
926
|
let codexDb = null;
|
|
927
927
|
let ingested = 0;
|
|
928
928
|
try {
|
|
929
|
-
codexDb = new
|
|
929
|
+
codexDb = new BunDatabase(CODEX_DB_PATH, { readonly: true });
|
|
930
930
|
const threads = codexDb.prepare(`SELECT id, cwd, created_at, updated_at, tokens_used, title FROM threads WHERE tokens_used > 0`).all();
|
|
931
931
|
for (const thread of threads) {
|
|
932
932
|
const stateKey = thread.id;
|
package/dist/ingest/claude.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA2D7D,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,CA2HhE"}
|
package/dist/ingest/codex.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/ingest/codex.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/ingest/codex.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAkB7D,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,CAyD9F;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
package/dist/ingest/gemini.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/ingest/gemini.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/ingest/gemini.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA0B7D,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA2EjG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-metadata.d.ts","sourceRoot":"","sources":["../../src/lib/package-metadata.ts"],"names":[],"mappings":"AAEA,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAID,wBAAgB,kBAAkB,IAAI,eAAe,CAYpD;AAED,eAAO,MAAM,eAAe,iBAAuB,CAAA"}
|
package/dist/lib/pricing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Database } from '
|
|
1
|
+
import type { SqliteAdapter as Database } from '@hasna/cloud';
|
|
2
2
|
import type { ModelPricing } from '../types/index.js';
|
|
3
3
|
export declare const DEFAULT_PRICING: Record<string, ModelPricing>;
|
|
4
4
|
export declare function normalizeModelName(raw: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/lib/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/lib/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAKrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CA6BxD,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"}
|
package/dist/lib/webhooks.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAE7D,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBtE"}
|