@hasna/economy 0.2.11 → 0.2.13
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/index.js +367 -32
- package/dist/db/database.d.ts +10 -1
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/index.js +81 -26
- package/dist/ingest/claude.d.ts +5 -0
- package/dist/ingest/claude.d.ts.map +1 -1
- package/dist/ingest/codex.d.ts.map +1 -1
- package/dist/ingest/gemini.d.ts.map +1 -1
- package/dist/mcp/index.js +207 -39
- package/dist/server/index.js +90 -28
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/db/database.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SqliteAdapter as Database } from '@hasna/cloud';
|
|
2
2
|
import type { EconomyRequest, EconomySession, EconomyProject, Budget, BudgetStatus, CostSummary, ModelBreakdown, ProjectBreakdown, Period, SessionFilter } from '../types/index.js';
|
|
3
|
+
export declare function getMachineId(): string;
|
|
3
4
|
export declare function getDataDir(): string;
|
|
4
5
|
export declare function getDbPath(): string;
|
|
5
6
|
export declare function openDatabase(dbPath?: string, skipSeed?: boolean): Database;
|
|
@@ -8,7 +9,7 @@ export declare function upsertSession(db: Database, session: EconomySession): vo
|
|
|
8
9
|
export declare function rollupSession(db: Database, sessionId: string): void;
|
|
9
10
|
export declare function querySessions(db: Database, filter?: SessionFilter): EconomySession[];
|
|
10
11
|
export declare function queryTopSessions(db: Database, n?: number, agent?: string): EconomySession[];
|
|
11
|
-
export declare function querySummary(db: Database, period: Period): CostSummary;
|
|
12
|
+
export declare function querySummary(db: Database, period: Period, machine?: string): CostSummary;
|
|
12
13
|
export declare function queryModelBreakdown(db: Database): ModelBreakdown[];
|
|
13
14
|
export declare function queryProjectBreakdown(db: Database): ProjectBreakdown[];
|
|
14
15
|
export declare function queryDailyBreakdown(db: Database, days?: number): Array<{
|
|
@@ -47,6 +48,14 @@ export declare function getGoalStatuses(db: Database): GoalStatus[];
|
|
|
47
48
|
export declare function getIngestState(db: Database, source: string, key: string): string | null;
|
|
48
49
|
export declare function setIngestState(db: Database, source: string, key: string, value: string): void;
|
|
49
50
|
export declare function queryRequestsSince(db: Database, since: string): EconomyRequest[];
|
|
51
|
+
export interface MachineInfo {
|
|
52
|
+
machine_id: string;
|
|
53
|
+
sessions: number;
|
|
54
|
+
requests: number;
|
|
55
|
+
total_cost_usd: number;
|
|
56
|
+
last_active: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function listMachines(db: Database): MachineInfo[];
|
|
50
59
|
export interface DbModelPricing {
|
|
51
60
|
model: string;
|
|
52
61
|
input_per_1m: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-migrations.d.ts","sourceRoot":"","sources":["../../src/db/pg-migrations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pg-migrations.d.ts","sourceRoot":"","sources":["../../src/db/pg-migrations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,aAAa,EAAE,MAAM,EAuGjC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -107,8 +107,17 @@ var init_pricing = __esm(() => {
|
|
|
107
107
|
// src/db/database.ts
|
|
108
108
|
import { SqliteAdapter as Database } from "@hasna/cloud";
|
|
109
109
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
|
|
110
|
+
import { hostname } from "os";
|
|
110
111
|
import { homedir } from "os";
|
|
111
112
|
import { join } from "path";
|
|
113
|
+
function getMachineId() {
|
|
114
|
+
if (process.env["ECONOMY_MACHINE_ID"])
|
|
115
|
+
return process.env["ECONOMY_MACHINE_ID"];
|
|
116
|
+
const h = hostname().toLowerCase();
|
|
117
|
+
if (h.startsWith("spark") || h.startsWith("apple"))
|
|
118
|
+
return h.split(".")[0];
|
|
119
|
+
return h.split(".")[0];
|
|
120
|
+
}
|
|
112
121
|
function getDataDir() {
|
|
113
122
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
114
123
|
const newDir = join(home, ".hasna", "economy");
|
|
@@ -141,6 +150,7 @@ function openDatabase(dbPath, skipSeed = false) {
|
|
|
141
150
|
}
|
|
142
151
|
const db = new Database(path);
|
|
143
152
|
db.exec("PRAGMA journal_mode = WAL");
|
|
153
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
144
154
|
db.exec("PRAGMA foreign_keys = ON");
|
|
145
155
|
initSchema(db);
|
|
146
156
|
if (!skipSeed) {
|
|
@@ -162,7 +172,8 @@ function initSchema(db) {
|
|
|
162
172
|
cost_usd REAL NOT NULL DEFAULT 0,
|
|
163
173
|
duration_ms INTEGER DEFAULT 0,
|
|
164
174
|
timestamp TEXT NOT NULL,
|
|
165
|
-
source_request_id TEXT
|
|
175
|
+
source_request_id TEXT,
|
|
176
|
+
machine_id TEXT DEFAULT ''
|
|
166
177
|
);
|
|
167
178
|
|
|
168
179
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
@@ -174,7 +185,8 @@ function initSchema(db) {
|
|
|
174
185
|
ended_at TEXT,
|
|
175
186
|
total_cost_usd REAL DEFAULT 0,
|
|
176
187
|
total_tokens INTEGER DEFAULT 0,
|
|
177
|
-
request_count INTEGER DEFAULT 0
|
|
188
|
+
request_count INTEGER DEFAULT 0,
|
|
189
|
+
machine_id TEXT DEFAULT ''
|
|
178
190
|
);
|
|
179
191
|
|
|
180
192
|
CREATE TABLE IF NOT EXISTS projects (
|
|
@@ -240,6 +252,15 @@ function initSchema(db) {
|
|
|
240
252
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
241
253
|
);
|
|
242
254
|
`);
|
|
255
|
+
const cols = db.prepare(`PRAGMA table_info(requests)`).all();
|
|
256
|
+
if (!cols.some((c) => c.name === "machine_id")) {
|
|
257
|
+
db.exec(`ALTER TABLE requests ADD COLUMN machine_id TEXT DEFAULT ''`);
|
|
258
|
+
db.exec(`ALTER TABLE sessions ADD COLUMN machine_id TEXT DEFAULT ''`);
|
|
259
|
+
}
|
|
260
|
+
db.exec(`
|
|
261
|
+
CREATE INDEX IF NOT EXISTS idx_requests_machine ON requests(machine_id);
|
|
262
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_machine ON sessions(machine_id);
|
|
263
|
+
`);
|
|
243
264
|
}
|
|
244
265
|
function periodWhere(period) {
|
|
245
266
|
switch (period) {
|
|
@@ -278,17 +299,17 @@ function upsertRequest(db, req) {
|
|
|
278
299
|
INSERT OR REPLACE INTO requests
|
|
279
300
|
(id, agent, session_id, model, input_tokens, output_tokens,
|
|
280
301
|
cache_read_tokens, cache_create_tokens, cost_usd, duration_ms,
|
|
281
|
-
timestamp, source_request_id)
|
|
282
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
283
|
-
`).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.cost_usd, req.duration_ms, req.timestamp, req.source_request_id);
|
|
302
|
+
timestamp, source_request_id, machine_id)
|
|
303
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
304
|
+
`).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.cost_usd, req.duration_ms, req.timestamp, req.source_request_id, req.machine_id ?? "");
|
|
284
305
|
}
|
|
285
306
|
function upsertSession(db, session) {
|
|
286
307
|
db.prepare(`
|
|
287
308
|
INSERT OR REPLACE INTO sessions
|
|
288
309
|
(id, agent, project_path, project_name, started_at, ended_at,
|
|
289
|
-
total_cost_usd, total_tokens, request_count)
|
|
290
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
291
|
-
`).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);
|
|
310
|
+
total_cost_usd, total_tokens, request_count, machine_id)
|
|
311
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
312
|
+
`).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 ?? "");
|
|
292
313
|
}
|
|
293
314
|
function rollupSession(db, sessionId) {
|
|
294
315
|
db.prepare(`
|
|
@@ -318,6 +339,10 @@ function querySessions(db, filter = {}) {
|
|
|
318
339
|
conditions.push("started_at >= ?");
|
|
319
340
|
params.push(filter.since);
|
|
320
341
|
}
|
|
342
|
+
if (filter.machine) {
|
|
343
|
+
conditions.push("machine_id = ?");
|
|
344
|
+
params.push(filter.machine);
|
|
345
|
+
}
|
|
321
346
|
if (filter.search) {
|
|
322
347
|
const q = `%${filter.search}%`;
|
|
323
348
|
conditions.push("(project_name LIKE ? OR agent LIKE ? OR id LIKE ?)");
|
|
@@ -336,24 +361,25 @@ function queryTopSessions(db, n = 10, agent) {
|
|
|
336
361
|
}
|
|
337
362
|
return db.prepare(`SELECT * FROM sessions ORDER BY total_cost_usd DESC LIMIT ?`).all(n);
|
|
338
363
|
}
|
|
339
|
-
function querySummary(db, period) {
|
|
364
|
+
function querySummary(db, period, machine) {
|
|
340
365
|
const rWhere = periodWhere(period);
|
|
341
366
|
const sWhere = sessionPeriodWhere(period);
|
|
367
|
+
const machineClause = machine ? ` AND machine_id = '${machine.replace(/'/g, "''")}'` : "";
|
|
342
368
|
const r = db.prepare(`
|
|
343
369
|
SELECT COALESCE(SUM(cost_usd), 0) as total_usd,
|
|
344
370
|
COUNT(*) as requests,
|
|
345
371
|
COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as tokens
|
|
346
|
-
FROM requests WHERE ${rWhere}
|
|
372
|
+
FROM requests WHERE ${rWhere}${machineClause}
|
|
347
373
|
`).get();
|
|
348
374
|
const codexTotals = db.prepare(`
|
|
349
375
|
SELECT COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
350
376
|
COALESCE(SUM(total_tokens), 0) as tokens,
|
|
351
377
|
COUNT(*) as sessions
|
|
352
378
|
FROM sessions
|
|
353
|
-
WHERE ${sWhere}
|
|
379
|
+
WHERE ${sWhere}${machineClause}
|
|
354
380
|
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
355
381
|
`).get();
|
|
356
|
-
const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}`).get();
|
|
382
|
+
const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}${machineClause}`).get();
|
|
357
383
|
return {
|
|
358
384
|
total_usd: r.total_usd + codexTotals.cost_usd,
|
|
359
385
|
requests: r.requests,
|
|
@@ -507,6 +533,20 @@ function setIngestState(db, source, key, value) {
|
|
|
507
533
|
function queryRequestsSince(db, since) {
|
|
508
534
|
return db.prepare(`SELECT * FROM requests WHERE timestamp > ? ORDER BY timestamp ASC`).all(since);
|
|
509
535
|
}
|
|
536
|
+
function listMachines(db) {
|
|
537
|
+
return db.prepare(`
|
|
538
|
+
SELECT
|
|
539
|
+
s.machine_id,
|
|
540
|
+
COUNT(DISTINCT s.id) as sessions,
|
|
541
|
+
COALESCE((SELECT COUNT(*) FROM requests r WHERE r.machine_id = s.machine_id), 0) as requests,
|
|
542
|
+
COALESCE(SUM(s.total_cost_usd), 0) as total_cost_usd,
|
|
543
|
+
MAX(s.started_at) as last_active
|
|
544
|
+
FROM sessions s
|
|
545
|
+
WHERE s.machine_id != ''
|
|
546
|
+
GROUP BY s.machine_id
|
|
547
|
+
ORDER BY total_cost_usd DESC
|
|
548
|
+
`).all();
|
|
549
|
+
}
|
|
510
550
|
function upsertModelPricing(db, p) {
|
|
511
551
|
db.prepare(`
|
|
512
552
|
INSERT OR REPLACE INTO model_pricing
|
|
@@ -769,7 +809,8 @@ import { join as join3, basename } from "path";
|
|
|
769
809
|
function autoDetectProject(cwd, projects) {
|
|
770
810
|
return projects.find((p) => cwd === p.path || cwd.startsWith(p.path + "/"));
|
|
771
811
|
}
|
|
772
|
-
var
|
|
812
|
+
var CLAUDE_PROJECTS_DIR = join3(homedir2(), ".claude", "projects");
|
|
813
|
+
var TAKUMI_PROJECTS_DIR = join3(homedir2(), ".takumi", "projects");
|
|
773
814
|
function dirNameToPath(dirName) {
|
|
774
815
|
return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
|
|
775
816
|
}
|
|
@@ -789,29 +830,36 @@ function collectJsonlFiles(projectDir) {
|
|
|
789
830
|
return files;
|
|
790
831
|
}
|
|
791
832
|
async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
792
|
-
|
|
833
|
+
return ingestJsonlProjects(db, CLAUDE_PROJECTS_DIR, "claude", verbose);
|
|
834
|
+
}
|
|
835
|
+
async function ingestTakumi(db, verbose = false) {
|
|
836
|
+
return ingestJsonlProjects(db, TAKUMI_PROJECTS_DIR, "takumi", verbose);
|
|
837
|
+
}
|
|
838
|
+
async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false) {
|
|
839
|
+
if (!existsSync3(projectsDir)) {
|
|
793
840
|
if (verbose)
|
|
794
|
-
console.log(
|
|
841
|
+
console.log(`${agentName} projects dir not found:`, projectsDir);
|
|
795
842
|
return { files: 0, requests: 0, sessions: 0 };
|
|
796
843
|
}
|
|
844
|
+
const machineId = getMachineId();
|
|
797
845
|
let totalFiles = 0;
|
|
798
846
|
let totalRequests = 0;
|
|
799
847
|
const touchedSessions = new Set;
|
|
800
848
|
const registeredProjects = db.prepare(`SELECT path, name FROM projects ORDER BY LENGTH(path) DESC`).all();
|
|
801
|
-
const projectDirs = readdirSync2(
|
|
849
|
+
const projectDirs = readdirSync2(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
802
850
|
for (const projectDirEntry of projectDirs) {
|
|
803
|
-
const projectDirPath = join3(
|
|
851
|
+
const projectDirPath = join3(projectsDir, projectDirEntry.name);
|
|
804
852
|
const projectPath = dirNameToPath(projectDirEntry.name);
|
|
805
853
|
const jsonlFiles = collectJsonlFiles(projectDirPath);
|
|
806
854
|
for (const filePath of jsonlFiles) {
|
|
807
|
-
const stateKey = filePath.replace(
|
|
855
|
+
const stateKey = filePath.replace(projectsDir, "");
|
|
808
856
|
let fileMtime = "0";
|
|
809
857
|
try {
|
|
810
858
|
fileMtime = statSync2(filePath).mtimeMs.toString();
|
|
811
859
|
} catch {
|
|
812
860
|
continue;
|
|
813
861
|
}
|
|
814
|
-
const processed = getIngestState(db,
|
|
862
|
+
const processed = getIngestState(db, agentName, stateKey);
|
|
815
863
|
if (processed === fileMtime)
|
|
816
864
|
continue;
|
|
817
865
|
let lines;
|
|
@@ -852,10 +900,10 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
|
852
900
|
if (inputTokens + outputTokens + cacheWriteTokens === 0)
|
|
853
901
|
continue;
|
|
854
902
|
const costUsd = computeCostFromDb(db, model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens);
|
|
855
|
-
const reqId =
|
|
903
|
+
const reqId = `${agentName}-${sessionId}-${timestamp}`;
|
|
856
904
|
upsertRequest(db, {
|
|
857
905
|
id: reqId,
|
|
858
|
-
agent:
|
|
906
|
+
agent: agentName,
|
|
859
907
|
session_id: sessionId,
|
|
860
908
|
model,
|
|
861
909
|
input_tokens: inputTokens,
|
|
@@ -865,7 +913,8 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
|
865
913
|
cost_usd: costUsd,
|
|
866
914
|
duration_ms: 0,
|
|
867
915
|
timestamp,
|
|
868
|
-
source_request_id: reqId
|
|
916
|
+
source_request_id: reqId,
|
|
917
|
+
machine_id: machineId
|
|
869
918
|
});
|
|
870
919
|
if (!touchedSessions.has(sessionId)) {
|
|
871
920
|
const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
|
|
@@ -874,14 +923,15 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
|
874
923
|
const detectedProject = autoDetectProject(effectiveCwd, registeredProjects);
|
|
875
924
|
const session = {
|
|
876
925
|
id: sessionId,
|
|
877
|
-
agent:
|
|
926
|
+
agent: agentName,
|
|
878
927
|
project_path: detectedProject ? detectedProject.path : effectiveCwd,
|
|
879
928
|
project_name: detectedProject ? detectedProject.name : "",
|
|
880
929
|
started_at: timestamp,
|
|
881
930
|
ended_at: null,
|
|
882
931
|
total_cost_usd: 0,
|
|
883
932
|
total_tokens: 0,
|
|
884
|
-
request_count: 0
|
|
933
|
+
request_count: 0,
|
|
934
|
+
machine_id: machineId
|
|
885
935
|
};
|
|
886
936
|
upsertSession(db, session);
|
|
887
937
|
}
|
|
@@ -889,7 +939,7 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
|
|
|
889
939
|
}
|
|
890
940
|
totalRequests++;
|
|
891
941
|
}
|
|
892
|
-
setIngestState(db,
|
|
942
|
+
setIngestState(db, agentName, stateKey, fileMtime);
|
|
893
943
|
totalFiles++;
|
|
894
944
|
}
|
|
895
945
|
}
|
|
@@ -923,6 +973,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
923
973
|
console.log("Codex DB not found:", CODEX_DB_PATH);
|
|
924
974
|
return { sessions: 0 };
|
|
925
975
|
}
|
|
976
|
+
const machineId = getMachineId();
|
|
926
977
|
let codexDb = null;
|
|
927
978
|
let ingested = 0;
|
|
928
979
|
try {
|
|
@@ -947,7 +998,8 @@ async function ingestCodex(db, verbose = false) {
|
|
|
947
998
|
ended_at: endedAt,
|
|
948
999
|
total_cost_usd: costUsd,
|
|
949
1000
|
total_tokens: thread.tokens_used,
|
|
950
|
-
request_count: 1
|
|
1001
|
+
request_count: 1,
|
|
1002
|
+
machine_id: machineId
|
|
951
1003
|
});
|
|
952
1004
|
setIngestState(db, "codex", stateKey, "done");
|
|
953
1005
|
ingested++;
|
|
@@ -982,14 +1034,17 @@ export {
|
|
|
982
1034
|
normalizeModelName,
|
|
983
1035
|
listProjects,
|
|
984
1036
|
listModelPricing,
|
|
1037
|
+
listMachines,
|
|
985
1038
|
listGoals,
|
|
986
1039
|
listBudgets,
|
|
1040
|
+
ingestTakumi,
|
|
987
1041
|
ingestCodex,
|
|
988
1042
|
ingestClaude,
|
|
989
1043
|
getProject,
|
|
990
1044
|
getPricingFromDb,
|
|
991
1045
|
getPricing,
|
|
992
1046
|
getModelPricing,
|
|
1047
|
+
getMachineId,
|
|
993
1048
|
getIngestState,
|
|
994
1049
|
getGoalStatuses,
|
|
995
1050
|
getDbPath,
|
package/dist/ingest/claude.d.ts
CHANGED
|
@@ -4,4 +4,9 @@ export declare function ingestClaude(db: Database, verbose?: boolean, _telemetry
|
|
|
4
4
|
requests: number;
|
|
5
5
|
sessions: number;
|
|
6
6
|
}>;
|
|
7
|
+
export declare function ingestTakumi(db: Database, verbose?: boolean): Promise<{
|
|
8
|
+
files: number;
|
|
9
|
+
requests: number;
|
|
10
|
+
sessions: number;
|
|
11
|
+
}>;
|
|
7
12
|
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -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;AA4D7D,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,CAEhE;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE"}
|
|
@@ -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;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,
|
|
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,CA2D9F;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,CA6EjG"}
|