@hasna/economy 0.2.21 → 0.2.23
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/LICENSE +1 -2
- package/README.md +33 -20
- package/dist/cli/commands/extras.d.ts.map +1 -1
- package/dist/cli/index.js +580 -88
- package/dist/db/database.d.ts +4 -2
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/index.js +401 -34
- package/dist/ingest/claude.d.ts.map +1 -1
- package/dist/ingest/codex.d.ts.map +1 -1
- package/dist/ingest/cursor.d.ts.map +1 -1
- package/dist/ingest/gemini.d.ts.map +1 -1
- package/dist/ingest/hermes.d.ts.map +1 -1
- package/dist/ingest/opencode.d.ts.map +1 -1
- package/dist/ingest/pi.d.ts.map +1 -1
- package/dist/lib/accounts.d.ts +11 -0
- package/dist/lib/accounts.d.ts.map +1 -0
- package/dist/lib/cloud-sync.d.ts.map +1 -1
- package/dist/lib/savings.d.ts.map +1 -1
- package/dist/mcp/index.js +964 -582
- package/dist/otel/index.js +77 -26
- package/dist/server/index.js +526 -89
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/types/index.d.ts +43 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +9 -4
- package/dist/mcp/http.d.ts +0 -13
- package/dist/mcp/http.d.ts.map +0 -1
- package/dist/mcp/server.d.ts +0 -4
- package/dist/mcp/server.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -582,7 +582,12 @@ function initSchema(db) {
|
|
|
582
582
|
duration_ms INTEGER DEFAULT 0,
|
|
583
583
|
timestamp TEXT NOT NULL,
|
|
584
584
|
source_request_id TEXT,
|
|
585
|
-
machine_id TEXT DEFAULT ''
|
|
585
|
+
machine_id TEXT DEFAULT '',
|
|
586
|
+
account_key TEXT DEFAULT '',
|
|
587
|
+
account_tool TEXT DEFAULT '',
|
|
588
|
+
account_name TEXT DEFAULT '',
|
|
589
|
+
account_email TEXT DEFAULT '',
|
|
590
|
+
account_source TEXT DEFAULT ''
|
|
586
591
|
);
|
|
587
592
|
|
|
588
593
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
@@ -595,7 +600,12 @@ function initSchema(db) {
|
|
|
595
600
|
total_cost_usd REAL DEFAULT 0,
|
|
596
601
|
total_tokens INTEGER DEFAULT 0,
|
|
597
602
|
request_count INTEGER DEFAULT 0,
|
|
598
|
-
machine_id TEXT DEFAULT ''
|
|
603
|
+
machine_id TEXT DEFAULT '',
|
|
604
|
+
account_key TEXT DEFAULT '',
|
|
605
|
+
account_tool TEXT DEFAULT '',
|
|
606
|
+
account_name TEXT DEFAULT '',
|
|
607
|
+
account_email TEXT DEFAULT '',
|
|
608
|
+
account_source TEXT DEFAULT ''
|
|
599
609
|
);
|
|
600
610
|
|
|
601
611
|
CREATE TABLE IF NOT EXISTS projects (
|
|
@@ -750,6 +760,11 @@ function initSchema(db) {
|
|
|
750
760
|
if (!cols.some((c) => c.name === "synced_at")) {
|
|
751
761
|
db.exec(`ALTER TABLE requests ADD COLUMN synced_at TEXT DEFAULT ''`);
|
|
752
762
|
}
|
|
763
|
+
for (const column of ["account_key", "account_tool", "account_name", "account_email", "account_source"]) {
|
|
764
|
+
if (!cols.some((c) => c.name === column)) {
|
|
765
|
+
db.exec(`ALTER TABLE requests ADD COLUMN ${column} TEXT DEFAULT ''`);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
753
768
|
const sessionCols = db.prepare(`PRAGMA table_info(sessions)`).all();
|
|
754
769
|
if (!sessionCols.some((c) => c.name === "attribution_tag")) {
|
|
755
770
|
db.exec(`ALTER TABLE sessions ADD COLUMN attribution_tag TEXT DEFAULT ''`);
|
|
@@ -761,6 +776,11 @@ function initSchema(db) {
|
|
|
761
776
|
if (!sessionCols.some((c) => c.name === "synced_at")) {
|
|
762
777
|
db.exec(`ALTER TABLE sessions ADD COLUMN synced_at TEXT DEFAULT ''`);
|
|
763
778
|
}
|
|
779
|
+
for (const column of ["account_key", "account_tool", "account_name", "account_email", "account_source"]) {
|
|
780
|
+
if (!sessionCols.some((c) => c.name === column)) {
|
|
781
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN ${column} TEXT DEFAULT ''`);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
764
784
|
const pricingCols = db.prepare(`PRAGMA table_info(model_pricing)`).all();
|
|
765
785
|
if (!pricingCols.some((c) => c.name === "cache_write_1h_per_1m")) {
|
|
766
786
|
db.exec(`ALTER TABLE model_pricing ADD COLUMN cache_write_1h_per_1m REAL NOT NULL DEFAULT 0`);
|
|
@@ -771,6 +791,8 @@ function initSchema(db) {
|
|
|
771
791
|
db.exec(`
|
|
772
792
|
CREATE INDEX IF NOT EXISTS idx_requests_machine ON requests(machine_id);
|
|
773
793
|
CREATE INDEX IF NOT EXISTS idx_sessions_machine ON sessions(machine_id);
|
|
794
|
+
CREATE INDEX IF NOT EXISTS idx_requests_account ON requests(account_key);
|
|
795
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_account ON sessions(account_key);
|
|
774
796
|
`);
|
|
775
797
|
}
|
|
776
798
|
function periodWhere(period) {
|
|
@@ -805,6 +827,22 @@ function sessionPeriodWhere(period) {
|
|
|
805
827
|
return "1=1";
|
|
806
828
|
}
|
|
807
829
|
}
|
|
830
|
+
function requestPeriodWhere(period) {
|
|
831
|
+
switch (period) {
|
|
832
|
+
case "today":
|
|
833
|
+
return `DATE(timestamp) = DATE('now')`;
|
|
834
|
+
case "yesterday":
|
|
835
|
+
return `DATE(timestamp) = DATE('now', '-1 day')`;
|
|
836
|
+
case "week":
|
|
837
|
+
return `timestamp >= DATE('now', 'weekday 0', '-7 days')`;
|
|
838
|
+
case "month":
|
|
839
|
+
return `timestamp >= DATE('now', 'start of month')`;
|
|
840
|
+
case "year":
|
|
841
|
+
return `timestamp >= DATE('now', 'start of year')`;
|
|
842
|
+
case "all":
|
|
843
|
+
return "1=1";
|
|
844
|
+
}
|
|
845
|
+
}
|
|
808
846
|
function upsertRequest(db, req) {
|
|
809
847
|
const now = req.updated_at ?? new Date().toISOString();
|
|
810
848
|
db.prepare(`
|
|
@@ -812,18 +850,20 @@ function upsertRequest(db, req) {
|
|
|
812
850
|
(id, agent, session_id, model, input_tokens, output_tokens,
|
|
813
851
|
cache_read_tokens, cache_create_tokens, cache_create_5m_tokens,
|
|
814
852
|
cache_create_1h_tokens, cost_usd, cost_basis, duration_ms, timestamp,
|
|
815
|
-
source_request_id, machine_id, attribution_tag,
|
|
816
|
-
|
|
817
|
-
|
|
853
|
+
source_request_id, machine_id, attribution_tag, account_key, account_tool,
|
|
854
|
+
account_name, account_email, account_source, updated_at, synced_at)
|
|
855
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
856
|
+
`).run(req.id, req.agent, req.session_id, req.model, req.input_tokens, req.output_tokens, req.cache_read_tokens, req.cache_create_tokens, req.cache_create_5m_tokens ?? req.cache_create_tokens, req.cache_create_1h_tokens ?? 0, req.cost_usd, req.cost_basis ?? "estimated", req.duration_ms, req.timestamp, req.source_request_id, req.machine_id ?? "", req.attribution_tag ?? process.env["ECONOMY_TAG"] ?? "", req.account_key ?? "", req.account_tool ?? "", req.account_name ?? "", req.account_email ?? "", req.account_source ?? "", now, req.synced_at ?? "");
|
|
818
857
|
}
|
|
819
858
|
function upsertSession(db, session) {
|
|
820
859
|
const now = session.updated_at ?? new Date().toISOString();
|
|
821
860
|
db.prepare(`
|
|
822
861
|
INSERT OR REPLACE INTO sessions
|
|
823
862
|
(id, agent, project_path, project_name, started_at, ended_at,
|
|
824
|
-
total_cost_usd, total_tokens, request_count, machine_id, attribution_tag,
|
|
825
|
-
|
|
826
|
-
|
|
863
|
+
total_cost_usd, total_tokens, request_count, machine_id, attribution_tag,
|
|
864
|
+
account_key, account_tool, account_name, account_email, account_source, updated_at, synced_at)
|
|
865
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
866
|
+
`).run(session.id, session.agent, session.project_path, session.project_name, session.started_at, session.ended_at ?? null, session.total_cost_usd, session.total_tokens, session.request_count, session.machine_id ?? "", session.attribution_tag ?? process.env["ECONOMY_TAG"] ?? "", session.account_key ?? "", session.account_tool ?? "", session.account_name ?? "", session.account_email ?? "", session.account_source ?? "", now, session.synced_at ?? "");
|
|
827
867
|
}
|
|
828
868
|
function rollupSession(db, sessionId) {
|
|
829
869
|
db.prepare(`
|
|
@@ -834,9 +874,24 @@ function rollupSession(db, sessionId) {
|
|
|
834
874
|
ended_at = (SELECT MAX(timestamp) FROM requests WHERE session_id = ?),
|
|
835
875
|
started_at = CASE WHEN started_at = '' OR started_at IS NULL
|
|
836
876
|
THEN (SELECT MIN(timestamp) FROM requests WHERE session_id = ?)
|
|
837
|
-
ELSE started_at END
|
|
877
|
+
ELSE started_at END,
|
|
878
|
+
account_key = CASE WHEN account_key = '' OR account_key IS NULL
|
|
879
|
+
THEN COALESCE((SELECT account_key FROM requests WHERE session_id = ? AND account_key != '' ORDER BY timestamp DESC LIMIT 1), '')
|
|
880
|
+
ELSE account_key END,
|
|
881
|
+
account_tool = CASE WHEN account_tool = '' OR account_tool IS NULL
|
|
882
|
+
THEN COALESCE((SELECT account_tool FROM requests WHERE session_id = ? AND account_tool != '' ORDER BY timestamp DESC LIMIT 1), '')
|
|
883
|
+
ELSE account_tool END,
|
|
884
|
+
account_name = CASE WHEN account_name = '' OR account_name IS NULL
|
|
885
|
+
THEN COALESCE((SELECT account_name FROM requests WHERE session_id = ? AND account_name != '' ORDER BY timestamp DESC LIMIT 1), '')
|
|
886
|
+
ELSE account_name END,
|
|
887
|
+
account_email = CASE WHEN account_email = '' OR account_email IS NULL
|
|
888
|
+
THEN COALESCE((SELECT account_email FROM requests WHERE session_id = ? AND account_email != '' ORDER BY timestamp DESC LIMIT 1), '')
|
|
889
|
+
ELSE account_email END,
|
|
890
|
+
account_source = CASE WHEN account_source = '' OR account_source IS NULL
|
|
891
|
+
THEN COALESCE((SELECT account_source FROM requests WHERE session_id = ? AND account_source != '' ORDER BY timestamp DESC LIMIT 1), '')
|
|
892
|
+
ELSE account_source END
|
|
838
893
|
WHERE id = ?
|
|
839
|
-
`).run(sessionId, sessionId, sessionId, sessionId, sessionId, sessionId);
|
|
894
|
+
`).run(sessionId, sessionId, sessionId, sessionId, sessionId, sessionId, sessionId, sessionId, sessionId, sessionId, sessionId);
|
|
840
895
|
}
|
|
841
896
|
function querySessions(db, filter = {}) {
|
|
842
897
|
const conditions = [];
|
|
@@ -849,6 +904,11 @@ function querySessions(db, filter = {}) {
|
|
|
849
904
|
conditions.push("project_path LIKE ?");
|
|
850
905
|
params.push(`%${filter.project}%`);
|
|
851
906
|
}
|
|
907
|
+
if (filter.account) {
|
|
908
|
+
const q = `%${filter.account}%`;
|
|
909
|
+
conditions.push("(account_key LIKE ? OR account_name LIKE ? OR account_email LIKE ?)");
|
|
910
|
+
params.push(q, q, q);
|
|
911
|
+
}
|
|
852
912
|
if (filter.since) {
|
|
853
913
|
conditions.push("started_at >= ?");
|
|
854
914
|
params.push(filter.since);
|
|
@@ -913,6 +973,70 @@ function queryModelBreakdown(db) {
|
|
|
913
973
|
FROM requests GROUP BY model, agent ORDER BY cost_usd DESC
|
|
914
974
|
`).all();
|
|
915
975
|
}
|
|
976
|
+
function queryAgentBreakdown(db, period = "all") {
|
|
977
|
+
const requestWhere = requestPeriodWhere(period);
|
|
978
|
+
const groups = new Map;
|
|
979
|
+
const requestRows = db.prepare(`
|
|
980
|
+
SELECT agent,
|
|
981
|
+
COUNT(DISTINCT session_id) as sessions,
|
|
982
|
+
COUNT(*) as requests,
|
|
983
|
+
COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as total_tokens,
|
|
984
|
+
COALESCE(SUM(cost_usd), 0) as api_equivalent_usd,
|
|
985
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'metered_api' THEN cost_usd ELSE 0 END), 0) as metered_api_usd,
|
|
986
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'subscription_included' THEN cost_usd ELSE 0 END), 0) as subscription_included_usd,
|
|
987
|
+
COALESCE(SUM(CASE WHEN COALESCE(cost_basis, 'estimated') = 'estimated' THEN cost_usd ELSE 0 END), 0) as estimated_usd,
|
|
988
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'unknown' THEN cost_usd ELSE 0 END), 0) as unknown_usd,
|
|
989
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'metered_api' THEN cost_usd ELSE 0 END), 0) as billable_usd,
|
|
990
|
+
COALESCE(SUM(cost_usd), 0) as cost_usd,
|
|
991
|
+
MAX(timestamp) as last_active
|
|
992
|
+
FROM requests
|
|
993
|
+
WHERE ${requestWhere}
|
|
994
|
+
GROUP BY agent
|
|
995
|
+
ORDER BY api_equivalent_usd DESC
|
|
996
|
+
`).all();
|
|
997
|
+
for (const row of requestRows) {
|
|
998
|
+
groups.set(row.agent, row);
|
|
999
|
+
}
|
|
1000
|
+
const sessionWhere = sessionPeriodWhere(period);
|
|
1001
|
+
const sessionOnlyRows = db.prepare(`
|
|
1002
|
+
SELECT agent,
|
|
1003
|
+
COUNT(*) as sessions,
|
|
1004
|
+
COALESCE(SUM(request_count), 0) as requests,
|
|
1005
|
+
COALESCE(SUM(total_tokens), 0) as total_tokens,
|
|
1006
|
+
COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
1007
|
+
MAX(started_at) as last_active
|
|
1008
|
+
FROM sessions
|
|
1009
|
+
WHERE ${sessionWhere}
|
|
1010
|
+
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
1011
|
+
GROUP BY agent
|
|
1012
|
+
`).all();
|
|
1013
|
+
for (const row of sessionOnlyRows) {
|
|
1014
|
+
const existing = groups.get(row.agent) ?? {
|
|
1015
|
+
agent: row.agent,
|
|
1016
|
+
sessions: 0,
|
|
1017
|
+
requests: 0,
|
|
1018
|
+
total_tokens: 0,
|
|
1019
|
+
api_equivalent_usd: 0,
|
|
1020
|
+
billable_usd: 0,
|
|
1021
|
+
metered_api_usd: 0,
|
|
1022
|
+
subscription_included_usd: 0,
|
|
1023
|
+
estimated_usd: 0,
|
|
1024
|
+
unknown_usd: 0,
|
|
1025
|
+
cost_usd: 0,
|
|
1026
|
+
last_active: ""
|
|
1027
|
+
};
|
|
1028
|
+
existing.sessions += row.sessions;
|
|
1029
|
+
existing.requests += row.requests;
|
|
1030
|
+
existing.total_tokens += row.total_tokens;
|
|
1031
|
+
existing.api_equivalent_usd += row.cost_usd;
|
|
1032
|
+
existing.estimated_usd += row.cost_usd;
|
|
1033
|
+
existing.cost_usd += row.cost_usd;
|
|
1034
|
+
if (!existing.last_active || row.last_active > existing.last_active)
|
|
1035
|
+
existing.last_active = row.last_active;
|
|
1036
|
+
groups.set(row.agent, existing);
|
|
1037
|
+
}
|
|
1038
|
+
return [...groups.values()].sort((a, b) => b.api_equivalent_usd - a.api_equivalent_usd);
|
|
1039
|
+
}
|
|
916
1040
|
function labelForPath(projectPath, projectName) {
|
|
917
1041
|
if (projectName && projectName.trim() !== "")
|
|
918
1042
|
return projectName;
|
|
@@ -931,11 +1055,13 @@ function labelForPath(projectPath, projectName) {
|
|
|
931
1055
|
}
|
|
932
1056
|
return segments[segments.length - 1] ?? projectPath;
|
|
933
1057
|
}
|
|
934
|
-
function queryProjectBreakdown(db) {
|
|
1058
|
+
function queryProjectBreakdown(db, period = "all") {
|
|
1059
|
+
const where = sessionPeriodWhere(period);
|
|
935
1060
|
const sessions = db.prepare(`
|
|
936
1061
|
SELECT id, project_path, project_name, total_cost_usd, started_at
|
|
937
1062
|
FROM sessions
|
|
938
|
-
WHERE
|
|
1063
|
+
WHERE ${where}
|
|
1064
|
+
AND (project_path != '' OR project_name != '')
|
|
939
1065
|
`).all();
|
|
940
1066
|
const groups = new Map;
|
|
941
1067
|
for (const s of sessions) {
|
|
@@ -974,6 +1100,87 @@ function queryProjectBreakdown(db) {
|
|
|
974
1100
|
result.sort((a, b) => b.cost_usd - a.cost_usd);
|
|
975
1101
|
return result;
|
|
976
1102
|
}
|
|
1103
|
+
function queryAccountBreakdown(db, period = "all") {
|
|
1104
|
+
const sWhere = sessionPeriodWhere(period);
|
|
1105
|
+
const sessions = db.prepare(`
|
|
1106
|
+
SELECT id, account_key, account_tool, account_name, account_email, account_source,
|
|
1107
|
+
total_cost_usd, total_tokens, request_count, started_at
|
|
1108
|
+
FROM sessions
|
|
1109
|
+
WHERE ${sWhere}
|
|
1110
|
+
AND (account_key != '' OR account_tool != '' OR account_name != '' OR account_email != '')
|
|
1111
|
+
`).all();
|
|
1112
|
+
const groups = new Map;
|
|
1113
|
+
for (const session of sessions) {
|
|
1114
|
+
const key = session.account_key || `${session.account_tool}:${session.account_name}`;
|
|
1115
|
+
if (!key || key === ":")
|
|
1116
|
+
continue;
|
|
1117
|
+
const group = groups.get(key) ?? {
|
|
1118
|
+
sessionIds: [],
|
|
1119
|
+
account_tool: session.account_tool,
|
|
1120
|
+
account_name: session.account_name,
|
|
1121
|
+
account_email: session.account_email || null,
|
|
1122
|
+
account_source: session.account_source || "unknown",
|
|
1123
|
+
totalCost: 0,
|
|
1124
|
+
totalTokens: 0,
|
|
1125
|
+
requests: 0,
|
|
1126
|
+
lastActive: ""
|
|
1127
|
+
};
|
|
1128
|
+
group.sessionIds.push(session.id);
|
|
1129
|
+
group.totalCost += session.total_cost_usd || 0;
|
|
1130
|
+
group.totalTokens += session.total_tokens || 0;
|
|
1131
|
+
group.requests += session.request_count || 0;
|
|
1132
|
+
if (!group.lastActive || session.started_at > group.lastActive)
|
|
1133
|
+
group.lastActive = session.started_at;
|
|
1134
|
+
groups.set(key, group);
|
|
1135
|
+
}
|
|
1136
|
+
const result = [];
|
|
1137
|
+
for (const [key, group] of groups.entries()) {
|
|
1138
|
+
const placeholders = group.sessionIds.map(() => "?").join(",");
|
|
1139
|
+
const reqStats = placeholders ? db.prepare(`
|
|
1140
|
+
SELECT
|
|
1141
|
+
COUNT(*) as requests,
|
|
1142
|
+
COALESCE(SUM(cost_usd), 0) as cost_usd,
|
|
1143
|
+
COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as total_tokens,
|
|
1144
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'metered_api' THEN cost_usd ELSE 0 END), 0) as metered_api_usd,
|
|
1145
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'subscription_included' THEN cost_usd ELSE 0 END), 0) as subscription_included_usd,
|
|
1146
|
+
COALESCE(SUM(CASE WHEN COALESCE(cost_basis, 'estimated') = 'estimated' THEN cost_usd ELSE 0 END), 0) as estimated_usd,
|
|
1147
|
+
COALESCE(SUM(CASE WHEN cost_basis = 'unknown' THEN cost_usd ELSE 0 END), 0) as unknown_usd
|
|
1148
|
+
FROM requests WHERE session_id IN (${placeholders})
|
|
1149
|
+
`).get(...group.sessionIds) : {
|
|
1150
|
+
requests: 0,
|
|
1151
|
+
cost_usd: 0,
|
|
1152
|
+
total_tokens: 0,
|
|
1153
|
+
metered_api_usd: 0,
|
|
1154
|
+
subscription_included_usd: 0,
|
|
1155
|
+
estimated_usd: 0,
|
|
1156
|
+
unknown_usd: 0
|
|
1157
|
+
};
|
|
1158
|
+
const hasRequestCosts = reqStats.requests > 0;
|
|
1159
|
+
const apiEquivalentUsd = hasRequestCosts ? reqStats.cost_usd : group.totalCost;
|
|
1160
|
+
const estimatedUsd = hasRequestCosts ? reqStats.estimated_usd : group.totalCost;
|
|
1161
|
+
const billableUsd = reqStats.metered_api_usd;
|
|
1162
|
+
result.push({
|
|
1163
|
+
account_key: key,
|
|
1164
|
+
account_tool: group.account_tool,
|
|
1165
|
+
account_name: group.account_name,
|
|
1166
|
+
account_email: group.account_email,
|
|
1167
|
+
account_source: group.account_source,
|
|
1168
|
+
sessions: group.sessionIds.length,
|
|
1169
|
+
requests: reqStats.requests || group.requests,
|
|
1170
|
+
total_tokens: reqStats.total_tokens || group.totalTokens,
|
|
1171
|
+
api_equivalent_usd: apiEquivalentUsd,
|
|
1172
|
+
billable_usd: billableUsd,
|
|
1173
|
+
metered_api_usd: reqStats.metered_api_usd,
|
|
1174
|
+
subscription_included_usd: reqStats.subscription_included_usd,
|
|
1175
|
+
estimated_usd: estimatedUsd,
|
|
1176
|
+
unknown_usd: reqStats.unknown_usd,
|
|
1177
|
+
cost_usd: apiEquivalentUsd,
|
|
1178
|
+
last_active: group.lastActive
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
result.sort((a, b) => b.cost_usd - a.cost_usd);
|
|
1182
|
+
return result;
|
|
1183
|
+
}
|
|
977
1184
|
function queryDailyBreakdown(db, days = 30) {
|
|
978
1185
|
return db.prepare(`
|
|
979
1186
|
SELECT DATE(timestamp) as date, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
@@ -1511,6 +1718,131 @@ function defaultCostBasisForAgent(agent) {
|
|
|
1511
1718
|
return "estimated";
|
|
1512
1719
|
}
|
|
1513
1720
|
|
|
1721
|
+
// src/lib/accounts.ts
|
|
1722
|
+
var AGENT_ACCOUNT_TOOLS = {
|
|
1723
|
+
claude: ["claude"],
|
|
1724
|
+
takumi: ["takumi", "claude"],
|
|
1725
|
+
codex: ["codex"],
|
|
1726
|
+
gemini: ["gemini"],
|
|
1727
|
+
opencode: ["opencode"],
|
|
1728
|
+
cursor: ["cursor"],
|
|
1729
|
+
pi: ["pi"],
|
|
1730
|
+
hermes: ["hermes"]
|
|
1731
|
+
};
|
|
1732
|
+
function accountKey(tool, name) {
|
|
1733
|
+
return `${tool}:${name}`;
|
|
1734
|
+
}
|
|
1735
|
+
function normalizeDir(value) {
|
|
1736
|
+
return value.replace(/\/+$/, "");
|
|
1737
|
+
}
|
|
1738
|
+
function fromProfile(profile, source) {
|
|
1739
|
+
return {
|
|
1740
|
+
account_key: accountKey(profile.tool, profile.name),
|
|
1741
|
+
account_tool: profile.tool,
|
|
1742
|
+
account_name: profile.name,
|
|
1743
|
+
...profile.email ? { account_email: profile.email } : {},
|
|
1744
|
+
account_source: source
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
function fromOverride(raw, agent) {
|
|
1748
|
+
const value = raw.trim();
|
|
1749
|
+
if (!value)
|
|
1750
|
+
return null;
|
|
1751
|
+
const candidateTool = AGENT_ACCOUNT_TOOLS[agent][0] ?? agent;
|
|
1752
|
+
const [tool, name] = value.includes(":") ? value.split(":", 2) : [candidateTool, value];
|
|
1753
|
+
if (!tool || !name)
|
|
1754
|
+
return null;
|
|
1755
|
+
return {
|
|
1756
|
+
account_key: accountKey(tool, name),
|
|
1757
|
+
account_tool: tool,
|
|
1758
|
+
account_name: name,
|
|
1759
|
+
account_source: "override"
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
function envOverride(agent, env) {
|
|
1763
|
+
const agentPrefix = agent.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1764
|
+
const raw = env[`ECONOMY_${agentPrefix}_ACCOUNT_KEY`] ?? env[`ECONOMY_${agentPrefix}_ACCOUNT`] ?? env["ECONOMY_ACCOUNT_KEY"] ?? env["ECONOMY_ACCOUNT"];
|
|
1765
|
+
if (raw)
|
|
1766
|
+
return fromOverride(raw, agent);
|
|
1767
|
+
const tool = env[`ECONOMY_${agentPrefix}_ACCOUNT_TOOL`] ?? env["ECONOMY_ACCOUNT_TOOL"];
|
|
1768
|
+
const name = env[`ECONOMY_${agentPrefix}_ACCOUNT_NAME`] ?? env["ECONOMY_ACCOUNT_NAME"];
|
|
1769
|
+
if (!tool || !name)
|
|
1770
|
+
return null;
|
|
1771
|
+
return {
|
|
1772
|
+
account_key: accountKey(tool, name),
|
|
1773
|
+
account_tool: tool,
|
|
1774
|
+
account_name: name,
|
|
1775
|
+
account_email: env[`ECONOMY_${agentPrefix}_ACCOUNT_EMAIL`] ?? env["ECONOMY_ACCOUNT_EMAIL"],
|
|
1776
|
+
account_source: "override"
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
function knownToolIds(api) {
|
|
1780
|
+
try {
|
|
1781
|
+
return new Set(api.listTools().map((tool) => tool.id));
|
|
1782
|
+
} catch {
|
|
1783
|
+
return new Set;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
function profileForEnvDir(api, tool, env) {
|
|
1787
|
+
const configuredDir = env[tool.envVar];
|
|
1788
|
+
if (!configuredDir)
|
|
1789
|
+
return null;
|
|
1790
|
+
const normalized = normalizeDir(configuredDir);
|
|
1791
|
+
try {
|
|
1792
|
+
return api.listProfiles(tool.id).find((profile) => normalizeDir(profile.dir) === normalized) ?? null;
|
|
1793
|
+
} catch {
|
|
1794
|
+
return null;
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
async function resolveAccountForAgent(agent, env = process.env) {
|
|
1798
|
+
const override = envOverride(agent, env);
|
|
1799
|
+
if (override)
|
|
1800
|
+
return override;
|
|
1801
|
+
let api;
|
|
1802
|
+
try {
|
|
1803
|
+
api = await import("@hasna/accounts");
|
|
1804
|
+
} catch {
|
|
1805
|
+
return null;
|
|
1806
|
+
}
|
|
1807
|
+
const toolIds = knownToolIds(api);
|
|
1808
|
+
for (const toolId of AGENT_ACCOUNT_TOOLS[agent]) {
|
|
1809
|
+
if (!toolIds.has(toolId))
|
|
1810
|
+
continue;
|
|
1811
|
+
let tool;
|
|
1812
|
+
try {
|
|
1813
|
+
tool = api.getTool(toolId);
|
|
1814
|
+
} catch {
|
|
1815
|
+
continue;
|
|
1816
|
+
}
|
|
1817
|
+
const envProfile = profileForEnvDir(api, tool, env);
|
|
1818
|
+
if (envProfile)
|
|
1819
|
+
return fromProfile(envProfile, "env");
|
|
1820
|
+
try {
|
|
1821
|
+
const applied = api.appliedProfile(toolId);
|
|
1822
|
+
if (applied)
|
|
1823
|
+
return fromProfile(applied, "applied");
|
|
1824
|
+
} catch {}
|
|
1825
|
+
try {
|
|
1826
|
+
const current = api.currentProfile(toolId);
|
|
1827
|
+
if (current)
|
|
1828
|
+
return fromProfile(current, "current");
|
|
1829
|
+
} catch {}
|
|
1830
|
+
}
|
|
1831
|
+
return null;
|
|
1832
|
+
}
|
|
1833
|
+
function withAccount(record, account) {
|
|
1834
|
+
if (!account)
|
|
1835
|
+
return record;
|
|
1836
|
+
return {
|
|
1837
|
+
...record,
|
|
1838
|
+
account_key: account.account_key,
|
|
1839
|
+
account_tool: account.account_tool,
|
|
1840
|
+
account_name: account.account_name,
|
|
1841
|
+
account_email: account.account_email ?? "",
|
|
1842
|
+
account_source: account.account_source
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1514
1846
|
// src/ingest/claude.ts
|
|
1515
1847
|
function autoDetectProject(cwd, projects) {
|
|
1516
1848
|
return projects.find((p) => cwd === p.path || cwd.startsWith(p.path + "/"));
|
|
@@ -1552,6 +1884,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
1552
1884
|
let totalRequests = 0;
|
|
1553
1885
|
const touchedSessions = new Set;
|
|
1554
1886
|
const registeredProjects = db.prepare(`SELECT path, name FROM projects ORDER BY LENGTH(path) DESC`).all();
|
|
1887
|
+
const account = await resolveAccountForAgent(agentName);
|
|
1555
1888
|
const projectDirs = readdirSync2(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
1556
1889
|
for (const projectDirEntry of projectDirs) {
|
|
1557
1890
|
const projectDirPath = join3(projectsDir, projectDirEntry.name);
|
|
@@ -1615,7 +1948,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
1615
1948
|
}
|
|
1616
1949
|
const sourceRequestId = entry.requestId ?? entry.request_id ?? entry.message.id ?? entry.uuid ?? `${sessionId}-${timestamp}`;
|
|
1617
1950
|
const reqId = `${agentName}-${sourceRequestId}`;
|
|
1618
|
-
upsertRequest(db, {
|
|
1951
|
+
upsertRequest(db, withAccount({
|
|
1619
1952
|
id: reqId,
|
|
1620
1953
|
agent: agentName,
|
|
1621
1954
|
session_id: sessionId,
|
|
@@ -1632,7 +1965,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
1632
1965
|
timestamp,
|
|
1633
1966
|
source_request_id: sourceRequestId,
|
|
1634
1967
|
machine_id: machineId
|
|
1635
|
-
});
|
|
1968
|
+
}, account));
|
|
1636
1969
|
if (!touchedSessions.has(sessionId)) {
|
|
1637
1970
|
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
1638
1971
|
if (!existing) {
|
|
@@ -1650,7 +1983,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
1650
1983
|
request_count: 0,
|
|
1651
1984
|
machine_id: machineId
|
|
1652
1985
|
};
|
|
1653
|
-
upsertSession(db, session);
|
|
1986
|
+
upsertSession(db, withAccount(session, account));
|
|
1654
1987
|
}
|
|
1655
1988
|
touchedSessions.add(sessionId);
|
|
1656
1989
|
}
|
|
@@ -1695,7 +2028,7 @@ import { join as join4, basename as basename2 } from "path";
|
|
|
1695
2028
|
import { Database as BunDatabase } from "bun:sqlite";
|
|
1696
2029
|
var DEFAULT_CODEX_DB_PATH = join4(homedir3(), ".codex", "state_5.sqlite");
|
|
1697
2030
|
var DEFAULT_CODEX_CONFIG_PATH = join4(homedir3(), ".codex", "config.toml");
|
|
1698
|
-
var CODEX_INGEST_VERSION = "rollout-
|
|
2031
|
+
var CODEX_INGEST_VERSION = "rollout-aggregate-v3";
|
|
1699
2032
|
function codexDbPath() {
|
|
1700
2033
|
return process.env["HASNA_ECONOMY_CODEX_DB_PATH"] ?? DEFAULT_CODEX_DB_PATH;
|
|
1701
2034
|
}
|
|
@@ -1728,8 +2061,9 @@ function buildThreadQuery(codexDb) {
|
|
|
1728
2061
|
function readTokenEvents(rolloutPath) {
|
|
1729
2062
|
if (!rolloutPath || !existsSync4(rolloutPath))
|
|
1730
2063
|
return [];
|
|
1731
|
-
const
|
|
1732
|
-
|
|
2064
|
+
const fallbackUsages = new Map;
|
|
2065
|
+
let fallbackTimestamp;
|
|
2066
|
+
let aggregate = null;
|
|
1733
2067
|
for (const line of readFileSync3(rolloutPath, "utf-8").split(`
|
|
1734
2068
|
`)) {
|
|
1735
2069
|
if (!line.trim())
|
|
@@ -1746,20 +2080,48 @@ function readTokenEvents(rolloutPath) {
|
|
|
1746
2080
|
if (!payload || payload["type"] !== "token_count")
|
|
1747
2081
|
continue;
|
|
1748
2082
|
const info = payload["info"];
|
|
2083
|
+
const timestamp = entry["timestamp"];
|
|
2084
|
+
const entryTimestamp = typeof timestamp === "string" ? timestamp : undefined;
|
|
2085
|
+
const totalUsage = info?.["total_token_usage"];
|
|
2086
|
+
if (totalUsage && tokenTotal(totalUsage) > 0) {
|
|
2087
|
+
aggregate = { usage: totalUsage, timestamp: entryTimestamp };
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
1749
2090
|
const usage = info?.["last_token_usage"];
|
|
1750
2091
|
if (!usage)
|
|
1751
2092
|
continue;
|
|
1752
|
-
|
|
1753
|
-
if (total <= 0)
|
|
2093
|
+
if (tokenTotal(usage) <= 0)
|
|
1754
2094
|
continue;
|
|
1755
2095
|
const key = JSON.stringify(usage);
|
|
1756
|
-
if (
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
const timestamp = entry["timestamp"];
|
|
1760
|
-
events.push({ usage, timestamp: typeof timestamp === "string" ? timestamp : undefined });
|
|
2096
|
+
if (!fallbackUsages.has(key))
|
|
2097
|
+
fallbackUsages.set(key, usage);
|
|
2098
|
+
fallbackTimestamp = entryTimestamp ?? fallbackTimestamp;
|
|
1761
2099
|
}
|
|
1762
|
-
|
|
2100
|
+
if (aggregate)
|
|
2101
|
+
return [aggregate];
|
|
2102
|
+
if (fallbackUsages.size === 0)
|
|
2103
|
+
return [];
|
|
2104
|
+
return [{ usage: sumTokenUsages([...fallbackUsages.values()]), timestamp: fallbackTimestamp }];
|
|
2105
|
+
}
|
|
2106
|
+
function tokenTotal(usage) {
|
|
2107
|
+
return usage.total_tokens ?? (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0);
|
|
2108
|
+
}
|
|
2109
|
+
function sumTokenUsages(usages) {
|
|
2110
|
+
const result = {
|
|
2111
|
+
input_tokens: 0,
|
|
2112
|
+
cached_input_tokens: 0,
|
|
2113
|
+
output_tokens: 0,
|
|
2114
|
+
reasoning_output_tokens: 0,
|
|
2115
|
+
total_tokens: 0
|
|
2116
|
+
};
|
|
2117
|
+
for (const usage of usages) {
|
|
2118
|
+
result.input_tokens = (result.input_tokens ?? 0) + (usage.input_tokens ?? 0);
|
|
2119
|
+
result.cached_input_tokens = (result.cached_input_tokens ?? 0) + (usage.cached_input_tokens ?? 0);
|
|
2120
|
+
result.output_tokens = (result.output_tokens ?? 0) + (usage.output_tokens ?? 0);
|
|
2121
|
+
result.reasoning_output_tokens = (result.reasoning_output_tokens ?? 0) + (usage.reasoning_output_tokens ?? 0);
|
|
2122
|
+
result.total_tokens = (result.total_tokens ?? 0) + tokenTotal(usage);
|
|
2123
|
+
}
|
|
2124
|
+
return result;
|
|
1763
2125
|
}
|
|
1764
2126
|
function fallbackEvents(totalTokens) {
|
|
1765
2127
|
const inputTokens = Math.floor(totalTokens * 0.6);
|
|
@@ -1783,6 +2145,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
1783
2145
|
let codexDb = null;
|
|
1784
2146
|
let ingested = 0;
|
|
1785
2147
|
let requests = 0;
|
|
2148
|
+
const account = await resolveAccountForAgent("codex");
|
|
1786
2149
|
try {
|
|
1787
2150
|
codexDb = new BunDatabase(dbPath, { readonly: true });
|
|
1788
2151
|
const threads = codexDb.prepare(buildThreadQuery(codexDb)).all();
|
|
@@ -1797,7 +2160,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
1797
2160
|
const sessionId = `codex-${thread.id}`;
|
|
1798
2161
|
const startedAt = thread.created_at ? new Date(thread.created_at * 1000).toISOString() : new Date().toISOString();
|
|
1799
2162
|
const endedAt = thread.updated_at ? new Date(thread.updated_at * 1000).toISOString() : null;
|
|
1800
|
-
upsertSession(db, {
|
|
2163
|
+
upsertSession(db, withAccount({
|
|
1801
2164
|
id: sessionId,
|
|
1802
2165
|
agent: "codex",
|
|
1803
2166
|
project_path: projectPath,
|
|
@@ -1808,9 +2171,10 @@ async function ingestCodex(db, verbose = false) {
|
|
|
1808
2171
|
total_tokens: 0,
|
|
1809
2172
|
request_count: 0,
|
|
1810
2173
|
machine_id: machineId
|
|
1811
|
-
});
|
|
2174
|
+
}, account));
|
|
1812
2175
|
const events = readTokenEvents(thread.rollout_path);
|
|
1813
2176
|
const tokenEvents = events.length > 0 ? events : fallbackEvents(thread.tokens_used);
|
|
2177
|
+
const ingestedTokens = tokenEvents.reduce((sum, event) => sum + tokenTotal(event.usage), 0);
|
|
1814
2178
|
db.prepare(`DELETE FROM requests WHERE session_id = ?`).run(sessionId);
|
|
1815
2179
|
tokenEvents.forEach((event, index) => {
|
|
1816
2180
|
const usage = event.usage;
|
|
@@ -1821,7 +2185,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
1821
2185
|
const costUsd = computeCostFromDb(db, model, inputTokens, outputTokens, cacheReadTokens, 0);
|
|
1822
2186
|
const timestamp = event.timestamp ?? (thread.created_at ? new Date(thread.created_at * 1000 + index).toISOString() : new Date().toISOString());
|
|
1823
2187
|
const requestId = `${sessionId}-${index}`;
|
|
1824
|
-
upsertRequest(db, {
|
|
2188
|
+
upsertRequest(db, withAccount({
|
|
1825
2189
|
id: requestId,
|
|
1826
2190
|
agent: "codex",
|
|
1827
2191
|
session_id: sessionId,
|
|
@@ -1836,14 +2200,14 @@ async function ingestCodex(db, verbose = false) {
|
|
|
1836
2200
|
timestamp,
|
|
1837
2201
|
source_request_id: requestId,
|
|
1838
2202
|
machine_id: machineId
|
|
1839
|
-
});
|
|
2203
|
+
}, account));
|
|
1840
2204
|
requests++;
|
|
1841
2205
|
});
|
|
1842
2206
|
rollupSession(db, sessionId);
|
|
1843
2207
|
setIngestState(db, "codex", thread.id, stateValue);
|
|
1844
2208
|
ingested++;
|
|
1845
2209
|
if (verbose)
|
|
1846
|
-
console.log(`Codex session ${thread.id}: ${
|
|
2210
|
+
console.log(`Codex session ${thread.id}: ${ingestedTokens} tokens on ${model}`);
|
|
1847
2211
|
}
|
|
1848
2212
|
} finally {
|
|
1849
2213
|
codexDb?.close();
|
|
@@ -1909,6 +2273,7 @@ async function ingestGemini(db, verbose) {
|
|
|
1909
2273
|
let totalSessions = 0;
|
|
1910
2274
|
let totalRequests = 0;
|
|
1911
2275
|
const touchedSessions = new Set;
|
|
2276
|
+
const account = await resolveAccountForAgent("gemini");
|
|
1912
2277
|
const projectDirs = listProjectDirs(tmpDir, historyDir);
|
|
1913
2278
|
for (const projectDir of projectDirs) {
|
|
1914
2279
|
const chatsDir = join5(projectDir, "chats");
|
|
@@ -1957,7 +2322,7 @@ async function ingestGemini(db, verbose) {
|
|
|
1957
2322
|
request_count: 0,
|
|
1958
2323
|
machine_id: machineId
|
|
1959
2324
|
};
|
|
1960
|
-
upsertSession(db, session);
|
|
2325
|
+
upsertSession(db, withAccount(session, account));
|
|
1961
2326
|
totalSessions++;
|
|
1962
2327
|
}
|
|
1963
2328
|
touchedSessions.add(sessionId);
|
|
@@ -1981,7 +2346,7 @@ async function ingestGemini(db, verbose) {
|
|
|
1981
2346
|
const costUsd = numberField(message.costUsd, message.cost_usd) || computedCost;
|
|
1982
2347
|
const timestamp = message.timestamp ?? chatData.lastUpdated ?? startTime;
|
|
1983
2348
|
const requestId = `gemini-${sessionId}-${message.id ?? index}`;
|
|
1984
|
-
upsertRequest(db, {
|
|
2349
|
+
upsertRequest(db, withAccount({
|
|
1985
2350
|
id: requestId,
|
|
1986
2351
|
agent: "gemini",
|
|
1987
2352
|
session_id: sessionId,
|
|
@@ -1996,7 +2361,7 @@ async function ingestGemini(db, verbose) {
|
|
|
1996
2361
|
timestamp,
|
|
1997
2362
|
source_request_id: message.id ?? requestId,
|
|
1998
2363
|
machine_id: machineId
|
|
1999
|
-
});
|
|
2364
|
+
}, account));
|
|
2000
2365
|
totalRequests++;
|
|
2001
2366
|
}
|
|
2002
2367
|
setIngestState(db, "gemini", stateKey, fileMtime);
|
|
@@ -2032,6 +2397,8 @@ export {
|
|
|
2032
2397
|
queryModelBreakdown,
|
|
2033
2398
|
queryDailyBreakdown,
|
|
2034
2399
|
queryBillingSummary,
|
|
2400
|
+
queryAgentBreakdown,
|
|
2401
|
+
queryAccountBreakdown,
|
|
2035
2402
|
openDatabase,
|
|
2036
2403
|
normalizeModelName,
|
|
2037
2404
|
listSubscriptions,
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAY7D,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAA;AA+D9D,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,KAAK,EAChB,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAyIhE"}
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AA6C7D,iBAAS,cAAc,IAAI,MAAM,CAUhC;AAoFD,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA4FhH;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/ingest/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAsC7D,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/ingest/cursor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AAsC7D,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAqGlH"}
|