@hasna/economy 0.5.4 → 0.5.6
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/CHANGELOG.md +18 -0
- package/README.md +3 -1
- package/dist/chunks/{index-n1wwqxfe.js → index-m12xttw1.js} +3 -1
- package/dist/chunks/{index-9arv0b1j.js → index-qvcafabj.js} +63 -66
- package/dist/chunks/{index-nheq2nrz.js → index-zqsx461z.js} +1 -1
- package/dist/chunks/{index-ct3zdefz.js → index-zs5dba3t.js} +1 -1
- package/dist/chunks/{serve-ra46ms69.js → serve-ept6cfbe.js} +2 -2
- package/dist/chunks/{tui-a1tvcw2j.js → tui-4bh067a3.js} +3 -3
- package/dist/chunks/{watch-rvd3dn6r.js → watch-227kxmra.js} +3 -3
- package/dist/cli/index.js +10 -10
- package/dist/index.js +3 -1
- package/dist/ingest/claude.d.ts.map +1 -1
- package/dist/ingest/codex.d.ts.map +1 -1
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/mcp/index.js +65 -66
- package/dist/otel/index.js +34 -39
- package/dist/server/index.js +119 -71
- package/dist/server/legacy-preservation.d.ts.map +1 -1
- package/dist/server/service-worker.js +65 -66
- package/native/README.md +131 -0
- package/native/Tools/pair-qr.py +131 -0
- package/native/Tools/pair-qr.swift +223 -0
- package/package.json +3 -1
package/dist/server/index.js
CHANGED
|
@@ -4909,6 +4909,48 @@ function assertLegacyPlanCurrent(expected, current) {
|
|
|
4909
4909
|
if (!same(state(expected), state(current)))
|
|
4910
4910
|
fail("Legacy plan is stale or belongs to a different store or schema");
|
|
4911
4911
|
}
|
|
4912
|
+
async function originalPages(load, count3) {
|
|
4913
|
+
const originals = [];
|
|
4914
|
+
let after = null;
|
|
4915
|
+
for (;; ) {
|
|
4916
|
+
const page = await load(after);
|
|
4917
|
+
if (!Array.isArray(page) || page.length > ORIGINAL_PAGE_ROWS)
|
|
4918
|
+
fail("Invalid original transfer page");
|
|
4919
|
+
for (const value of page) {
|
|
4920
|
+
const row = record(value);
|
|
4921
|
+
fields(row, ["id", "original"]);
|
|
4922
|
+
if (typeof row.original !== "string")
|
|
4923
|
+
fail("Invalid original transfer row");
|
|
4924
|
+
const id = identifier3(row.id);
|
|
4925
|
+
if (after !== null && cOrder(after, id) >= 0)
|
|
4926
|
+
fail("Original transfer cursor did not advance");
|
|
4927
|
+
after = id;
|
|
4928
|
+
originals.push({ id, original: row.original });
|
|
4929
|
+
if (originals.length > count3)
|
|
4930
|
+
fail("Original transfer exceeds the complete population");
|
|
4931
|
+
}
|
|
4932
|
+
if (page.length < ORIGINAL_PAGE_ROWS) {
|
|
4933
|
+
if (originals.length !== count3)
|
|
4934
|
+
fail("Original transfer omitted part of the complete population");
|
|
4935
|
+
return originals;
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
function* restoreBatches(originals) {
|
|
4940
|
+
let rows = [], bytes = 2;
|
|
4941
|
+
for (const row of originals) {
|
|
4942
|
+
const size = Buffer.byteLength(row.original);
|
|
4943
|
+
if (rows.length && (rows.length === ORIGINAL_PAGE_ROWS || bytes + 1 + size > RESTORE_BATCH_BYTES)) {
|
|
4944
|
+
yield "[" + rows.join(",") + "]";
|
|
4945
|
+
rows = [];
|
|
4946
|
+
bytes = 2;
|
|
4947
|
+
}
|
|
4948
|
+
bytes += size + (rows.length ? 1 : 0);
|
|
4949
|
+
rows.push(row.original);
|
|
4950
|
+
}
|
|
4951
|
+
if (rows.length)
|
|
4952
|
+
yield "[" + rows.join(",") + "]";
|
|
4953
|
+
}
|
|
4912
4954
|
function parseLegacyCapsule(value) {
|
|
4913
4955
|
const c = record(value);
|
|
4914
4956
|
const mode = legacyMode("capsule", c.schema);
|
|
@@ -4981,7 +5023,12 @@ async function preserveLegacyOriginals(client, input) {
|
|
|
4981
5023
|
(SELECT COALESCE(SUM(octet_length(row_to_json(sessions)::text)),0) FROM sessions WHERE id=ANY($1::text[]))::text AS session_bytes`, [ids])).rows[0];
|
|
4982
5024
|
if (!sizes || !/^[0-9]+$/.test(sizes.request_bytes) || !/^[0-9]+$/.test(sizes.session_bytes) || BigInt(sizes.request_bytes) + BigInt(sizes.session_bytes) > BigInt(mode.originalBytes))
|
|
4983
5025
|
fail(`Preservation exceeds ${mode.originalBytes / 1024 / 1024} MiB of original row text; complete sessions cannot be truncated`);
|
|
4984
|
-
const requests =
|
|
5026
|
+
const requests = [];
|
|
5027
|
+
for (const session of current.sessions) {
|
|
5028
|
+
requests.push(...await originalPages(async (after) => (await client.query(`SELECT id,row_to_json(requests)::text AS original FROM requests
|
|
5029
|
+
WHERE session_id=$1::text AND ($2::text IS NULL OR id COLLATE "C" > $2::text COLLATE "C")
|
|
5030
|
+
ORDER BY id COLLATE "C" LIMIT ${ORIGINAL_PAGE_ROWS}`, [session.id, after])).rows, session.request_count));
|
|
5031
|
+
}
|
|
4985
5032
|
const sessions = (await client.query(`SELECT id,row_to_json(sessions)::text AS original FROM sessions WHERE id=ANY($1::text[]) ORDER BY id COLLATE "C" LIMIT ${mode.sessions + 1}`, [ids])).rows;
|
|
4986
5033
|
const body = { schema: mode.capsule, plan: expected, captured_at: current.snapshot.at, requests, sessions };
|
|
4987
5034
|
return parseLegacyCapsule({ ...body, capsule_sha256: sha2(JSON.stringify(body)) });
|
|
@@ -5114,9 +5161,10 @@ async function rehearseLegacyRestore(client, input, scope = "transaction") {
|
|
|
5114
5161
|
if ((await client.query("SELECT current_setting('transaction_read_only') AS read_only")).rows[0]?.read_only !== "on")
|
|
5115
5162
|
fail("Restore reconstruction requires a read-only transaction");
|
|
5116
5163
|
for (const { source, temp, originals } of restoreTables) {
|
|
5117
|
-
const payload
|
|
5118
|
-
|
|
5119
|
-
|
|
5164
|
+
for (const payload of restoreBatches(originals)) {
|
|
5165
|
+
await client.query("INSERT INTO pg_temp." + temp + " SELECT * FROM json_populate_recordset(NULL::" + source + ",$1::json)", [payload]);
|
|
5166
|
+
}
|
|
5167
|
+
const restored = await originalPages(async (after) => (await client.query("SELECT id,row_to_json(t)::text AS original FROM pg_temp." + temp + ' t WHERE ($1::text IS NULL OR id COLLATE "C" > $1::text COLLATE "C") ORDER BY id COLLATE "C" LIMIT ' + ORIGINAL_PAGE_ROWS, [after])).rows, originals.length);
|
|
5120
5168
|
const expectedRows = [...originals].sort((a, b) => cOrder(a.id, b.id));
|
|
5121
5169
|
if (!same(restored, expectedRows))
|
|
5122
5170
|
fail("Restored original bytes differ from preservation");
|
|
@@ -5170,11 +5218,12 @@ var MAX_BYTES, sha2 = (s) => createHash7("sha256").update(s).digest("hex"), fail
|
|
|
5170
5218
|
}, record = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : fail("Expected a JSON object"), hash = (v) => typeof v === "string" && /^[a-f0-9]{64}$/.test(v) ? v : fail("Expected a lowercase SHA-256 digest"), identifier3 = (v) => typeof v === "string" && v.length > 0 && v.length <= 1024 && !v.includes("\x00") ? v : fail("Expected a nonempty identifier of at most 1024 characters without NUL"), fields = (o, names) => {
|
|
5171
5219
|
if (Object.keys(o).sort().join(",") !== [...names].sort().join(","))
|
|
5172
5220
|
fail("Unexpected or missing preservation fields");
|
|
5173
|
-
}, cOrder = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)), same = (a, b) => JSON.stringify(a) === JSON.stringify(b), quote3 = (s) => '"' + s.replaceAll('"', '""') + '"';
|
|
5221
|
+
}, cOrder = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)), same = (a, b) => JSON.stringify(a) === JSON.stringify(b), quote3 = (s) => '"' + s.replaceAll('"', '""') + '"', ORIGINAL_PAGE_ROWS = 1000, RESTORE_BATCH_BYTES;
|
|
5174
5222
|
var init_legacy_preservation = __esm(() => {
|
|
5175
5223
|
init_legacy_plan();
|
|
5176
5224
|
init_legacy_limits();
|
|
5177
5225
|
MAX_BYTES = LEGACY_SINGLE_SESSION.capsuleBytes;
|
|
5226
|
+
RESTORE_BATCH_BYTES = 1024 * 1024;
|
|
5178
5227
|
});
|
|
5179
5228
|
|
|
5180
5229
|
// src/server/legacy-operations.ts
|
|
@@ -5529,7 +5578,7 @@ function isAuthorizedRequest(req, path) {
|
|
|
5529
5578
|
// package.json
|
|
5530
5579
|
var package_default = {
|
|
5531
5580
|
name: "@hasna/economy",
|
|
5532
|
-
version: "0.5.
|
|
5581
|
+
version: "0.5.6",
|
|
5533
5582
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
5534
5583
|
repository: {
|
|
5535
5584
|
type: "git",
|
|
@@ -5562,6 +5611,8 @@ var package_default = {
|
|
|
5562
5611
|
files: [
|
|
5563
5612
|
"dist",
|
|
5564
5613
|
"docs",
|
|
5614
|
+
"native/Tools/pair-qr.py",
|
|
5615
|
+
"native/Tools/pair-qr.swift",
|
|
5565
5616
|
"postinstall.js",
|
|
5566
5617
|
"LICENSE",
|
|
5567
5618
|
"README.md",
|
|
@@ -8812,8 +8863,8 @@ function sourceTimeMillis(value) {
|
|
|
8812
8863
|
init_database();
|
|
8813
8864
|
init_pricing();
|
|
8814
8865
|
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
8815
|
-
import { homedir as
|
|
8816
|
-
import { join as
|
|
8866
|
+
import { homedir as homedir4 } from "os";
|
|
8867
|
+
import { join as join6, basename } from "path";
|
|
8817
8868
|
|
|
8818
8869
|
// src/lib/accounts-store.ts
|
|
8819
8870
|
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
@@ -9436,12 +9487,41 @@ function withAccount(record, account) {
|
|
|
9436
9487
|
};
|
|
9437
9488
|
}
|
|
9438
9489
|
|
|
9490
|
+
// src/lib/paths.ts
|
|
9491
|
+
import { homedir as homedir3 } from "os";
|
|
9492
|
+
import { join as join5 } from "path";
|
|
9493
|
+
function getHomeDir2() {
|
|
9494
|
+
return process.env["USERPROFILE"] ?? process.env["HOME"] ?? homedir3();
|
|
9495
|
+
}
|
|
9496
|
+
function agentPaths() {
|
|
9497
|
+
const home = getHomeDir2();
|
|
9498
|
+
const claudeHome = process.env["CLAUDE_CONFIG_DIR"] || join5(home, ".claude");
|
|
9499
|
+
const codexHome = process.env["CODEX_HOME"] || join5(home, ".codex");
|
|
9500
|
+
return {
|
|
9501
|
+
claudeProjects: join5(claudeHome, "projects"),
|
|
9502
|
+
claudeCredentials: join5(claudeHome, ".credentials.json"),
|
|
9503
|
+
takumiProjects: join5(home, ".takumi", "projects"),
|
|
9504
|
+
codexDir: codexHome,
|
|
9505
|
+
codexDb: join5(codexHome, "state_5.sqlite"),
|
|
9506
|
+
codexAuth: join5(codexHome, "auth.json"),
|
|
9507
|
+
codexConfig: join5(codexHome, "config.toml"),
|
|
9508
|
+
geminiTmp: join5(home, ".gemini", "tmp"),
|
|
9509
|
+
geminiHistory: join5(home, ".gemini", "history"),
|
|
9510
|
+
opencodeMessages: join5(home, ".local", "share", "opencode", "storage", "message"),
|
|
9511
|
+
piSessions: join5(home, ".pi", "agent", "sessions"),
|
|
9512
|
+
hermesDir: join5(home, ".hermes"),
|
|
9513
|
+
hermesDb: join5(home, ".hermes", "state.db")
|
|
9514
|
+
};
|
|
9515
|
+
}
|
|
9516
|
+
|
|
9439
9517
|
// src/ingest/claude.ts
|
|
9440
9518
|
function autoDetectProject(cwd, projects) {
|
|
9441
9519
|
return projects.find((p) => cwd === p.path || cwd.startsWith(p.path + "/"));
|
|
9442
9520
|
}
|
|
9443
|
-
var
|
|
9444
|
-
|
|
9521
|
+
var TAKUMI_PROJECTS_DIR = process.env["HASNA_ECONOMY_TAKUMI_PROJECTS_DIR"] ?? join6(homedir4(), ".takumi", "projects");
|
|
9522
|
+
function claudeProjectsDir() {
|
|
9523
|
+
return process.env["HASNA_ECONOMY_CLAUDE_PROJECTS_DIR"] ?? agentPaths().claudeProjects;
|
|
9524
|
+
}
|
|
9445
9525
|
function dirNameToPath(dirName) {
|
|
9446
9526
|
return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
|
|
9447
9527
|
}
|
|
@@ -9451,9 +9531,9 @@ function collectJsonlFiles(projectDir) {
|
|
|
9451
9531
|
try {
|
|
9452
9532
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
9453
9533
|
if (entry.isDirectory())
|
|
9454
|
-
walk(
|
|
9534
|
+
walk(join6(dir, entry.name));
|
|
9455
9535
|
else if (entry.name.endsWith(".jsonl"))
|
|
9456
|
-
files.push(
|
|
9536
|
+
files.push(join6(dir, entry.name));
|
|
9457
9537
|
}
|
|
9458
9538
|
} catch {
|
|
9459
9539
|
collectionProblem("failed", "source_unreadable");
|
|
@@ -9462,7 +9542,7 @@ function collectJsonlFiles(projectDir) {
|
|
|
9462
9542
|
walk(projectDir);
|
|
9463
9543
|
return files;
|
|
9464
9544
|
}
|
|
9465
|
-
async function ingestClaude(db, verbose = false, projectsDir =
|
|
9545
|
+
async function ingestClaude(db, verbose = false, projectsDir = claudeProjectsDir()) {
|
|
9466
9546
|
return ingestJsonlProjects(db, projectsDir, "claude", verbose);
|
|
9467
9547
|
}
|
|
9468
9548
|
async function ingestTakumi(db, verbose = false, projectsDir = TAKUMI_PROJECTS_DIR) {
|
|
@@ -9484,7 +9564,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
9484
9564
|
const ingestState = loadIngestState(db, agentName);
|
|
9485
9565
|
const projectDirs = readdirSync2(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
9486
9566
|
for (const projectDirEntry of projectDirs) {
|
|
9487
|
-
const projectDirPath =
|
|
9567
|
+
const projectDirPath = join6(projectsDir, projectDirEntry.name);
|
|
9488
9568
|
const projectPath = dirNameToPath(projectDirEntry.name);
|
|
9489
9569
|
const jsonlFiles = collectJsonlFiles(projectDirPath);
|
|
9490
9570
|
for (const filePath of jsonlFiles) {
|
|
@@ -9635,24 +9715,19 @@ init_database();
|
|
|
9635
9715
|
init_pricing();
|
|
9636
9716
|
import { existsSync as existsSync5, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
9637
9717
|
import { createHash as createHash4 } from "crypto";
|
|
9638
|
-
import {
|
|
9639
|
-
import { join as join6, basename as basename2 } from "path";
|
|
9640
|
-
var DEFAULT_CODEX_DB_PATH = join6(homedir4(), ".codex", "state_5.sqlite");
|
|
9641
|
-
var DEFAULT_CODEX_CONFIG_PATH = join6(homedir4(), ".codex", "config.toml");
|
|
9642
|
-
var DEFAULT_CODEWITH_DB_PATH = join6(homedir4(), ".codewith", "state_5.sqlite");
|
|
9643
|
-
var DEFAULT_CODEWITH_CONFIG_PATH = join6(homedir4(), ".codewith", "config.toml");
|
|
9718
|
+
import { join as join7, basename as basename2 } from "path";
|
|
9644
9719
|
var CODEX_INGEST_VERSION = "rollout-events-v4";
|
|
9645
9720
|
function codexDbPath() {
|
|
9646
|
-
return process.env["HASNA_ECONOMY_CODEX_DB_PATH"] ??
|
|
9721
|
+
return process.env["HASNA_ECONOMY_CODEX_DB_PATH"] ?? agentPaths().codexDb;
|
|
9647
9722
|
}
|
|
9648
9723
|
function codexConfigPath() {
|
|
9649
|
-
return process.env["HASNA_ECONOMY_CODEX_CONFIG_PATH"] ??
|
|
9724
|
+
return process.env["HASNA_ECONOMY_CODEX_CONFIG_PATH"] ?? agentPaths().codexConfig;
|
|
9650
9725
|
}
|
|
9651
9726
|
function codewithDbPath() {
|
|
9652
|
-
return process.env["HASNA_ECONOMY_CODEWITH_DB_PATH"] ??
|
|
9727
|
+
return process.env["HASNA_ECONOMY_CODEWITH_DB_PATH"] ?? join7(getHomeDir2(), ".codewith", "state_5.sqlite");
|
|
9653
9728
|
}
|
|
9654
9729
|
function codewithConfigPath() {
|
|
9655
|
-
return process.env["HASNA_ECONOMY_CODEWITH_CONFIG_PATH"] ??
|
|
9730
|
+
return process.env["HASNA_ECONOMY_CODEWITH_CONFIG_PATH"] ?? join7(getHomeDir2(), ".codewith", "config.toml");
|
|
9656
9731
|
}
|
|
9657
9732
|
function codexSources() {
|
|
9658
9733
|
const explicitCodexPath = process.env["HASNA_ECONOMY_CODEX_DB_PATH"];
|
|
@@ -9664,7 +9739,7 @@ function codexSources() {
|
|
|
9664
9739
|
sessionPrefix: "codex",
|
|
9665
9740
|
stateSource: "codex"
|
|
9666
9741
|
}];
|
|
9667
|
-
if (!explicitCodexPath || explicitCodewithPath) {
|
|
9742
|
+
if (!explicitCodexPath && !process.env["CODEX_HOME"] || explicitCodewithPath) {
|
|
9668
9743
|
sources.push({
|
|
9669
9744
|
label: "Codewith",
|
|
9670
9745
|
dbPath: codewithDbPath(),
|
|
@@ -9904,9 +9979,9 @@ init_database();
|
|
|
9904
9979
|
init_pricing();
|
|
9905
9980
|
import { readdirSync as readdirSync3, readFileSync as readFileSync4, existsSync as existsSync6, statSync as statSync4 } from "fs";
|
|
9906
9981
|
import { homedir as homedir5 } from "os";
|
|
9907
|
-
import { join as
|
|
9908
|
-
var DEFAULT_GEMINI_TMP_DIR =
|
|
9909
|
-
var DEFAULT_GEMINI_HISTORY_DIR =
|
|
9982
|
+
import { join as join8, basename as basename3 } from "path";
|
|
9983
|
+
var DEFAULT_GEMINI_TMP_DIR = join8(homedir5(), ".gemini", "tmp");
|
|
9984
|
+
var DEFAULT_GEMINI_HISTORY_DIR = join8(homedir5(), ".gemini", "history");
|
|
9910
9985
|
function geminiTmpDir() {
|
|
9911
9986
|
return process.env["HASNA_ECONOMY_GEMINI_TMP_DIR"] ?? DEFAULT_GEMINI_TMP_DIR;
|
|
9912
9987
|
}
|
|
@@ -9928,7 +10003,7 @@ function listProjectDirs(...roots) {
|
|
|
9928
10003
|
try {
|
|
9929
10004
|
for (const entry of readdirSync3(root, { withFileTypes: true })) {
|
|
9930
10005
|
if (entry.isDirectory())
|
|
9931
|
-
dirs.add(
|
|
10006
|
+
dirs.add(join8(root, entry.name));
|
|
9932
10007
|
}
|
|
9933
10008
|
} catch {
|
|
9934
10009
|
collectionProblem("failed", "source_unreadable");
|
|
@@ -9941,7 +10016,7 @@ function projectRoot(projectDir, chatData) {
|
|
|
9941
10016
|
return chatData.projectPath;
|
|
9942
10017
|
if (chatData.project_path)
|
|
9943
10018
|
return chatData.project_path;
|
|
9944
|
-
const rootFile =
|
|
10019
|
+
const rootFile = join8(projectDir, ".project_root");
|
|
9945
10020
|
try {
|
|
9946
10021
|
if (existsSync6(rootFile))
|
|
9947
10022
|
return readFileSync4(rootFile, "utf-8").trim();
|
|
@@ -9966,12 +10041,12 @@ async function ingestGemini(db, verbose) {
|
|
|
9966
10041
|
const account = await resolveAccountForAgent("gemini");
|
|
9967
10042
|
const projectDirs = listProjectDirs(tmpDir, historyDir);
|
|
9968
10043
|
for (const projectDir of projectDirs) {
|
|
9969
|
-
const chatsDir =
|
|
10044
|
+
const chatsDir = join8(projectDir, "chats");
|
|
9970
10045
|
if (!existsSync6(chatsDir))
|
|
9971
10046
|
continue;
|
|
9972
10047
|
let chatFiles = [];
|
|
9973
10048
|
try {
|
|
9974
|
-
chatFiles = readdirSync3(chatsDir).filter((f) => f.endsWith(".json")).map((f) =>
|
|
10049
|
+
chatFiles = readdirSync3(chatsDir).filter((f) => f.endsWith(".json")).map((f) => join8(chatsDir, f));
|
|
9975
10050
|
} catch {
|
|
9976
10051
|
collectionProblem("failed", "source_unreadable");
|
|
9977
10052
|
continue;
|
|
@@ -10083,13 +10158,13 @@ init_database();
|
|
|
10083
10158
|
init_pricing();
|
|
10084
10159
|
import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
|
|
10085
10160
|
import { homedir as homedir6 } from "os";
|
|
10086
|
-
import { join as
|
|
10087
|
-
var OPENCODE_STORAGE =
|
|
10161
|
+
import { join as join9 } from "path";
|
|
10162
|
+
var OPENCODE_STORAGE = join9(homedir6(), ".local", "share", "opencode", "storage");
|
|
10088
10163
|
function walkJsonFiles(dir, acc = []) {
|
|
10089
10164
|
if (!existsSync7(dir))
|
|
10090
10165
|
return acc;
|
|
10091
10166
|
for (const entry of readdirSync4(dir, { withFileTypes: true })) {
|
|
10092
|
-
const p =
|
|
10167
|
+
const p = join9(dir, entry.name);
|
|
10093
10168
|
if (entry.isDirectory())
|
|
10094
10169
|
walkJsonFiles(p, acc);
|
|
10095
10170
|
else if (entry.name.endsWith(".json"))
|
|
@@ -10109,7 +10184,7 @@ function parseSessionIdFromPath(filePath) {
|
|
|
10109
10184
|
return null;
|
|
10110
10185
|
}
|
|
10111
10186
|
async function ingestOpenCode(db, verbose = false, sourceDir = OPENCODE_STORAGE) {
|
|
10112
|
-
const messageDir =
|
|
10187
|
+
const messageDir = join9(sourceDir, "message");
|
|
10113
10188
|
if (!existsSync7(messageDir))
|
|
10114
10189
|
collectionProblem("missing", "source_missing");
|
|
10115
10190
|
const files = walkJsonFiles(messageDir);
|
|
@@ -10304,13 +10379,13 @@ async function ingestCursor(db, verbose = false) {
|
|
|
10304
10379
|
init_database();
|
|
10305
10380
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync6 } from "fs";
|
|
10306
10381
|
import { homedir as homedir7 } from "os";
|
|
10307
|
-
import { join as
|
|
10308
|
-
var PI_SESSION_DIR = process.env["PI_CODING_AGENT_SESSION_DIR"] ??
|
|
10382
|
+
import { join as join10 } from "path";
|
|
10383
|
+
var PI_SESSION_DIR = process.env["PI_CODING_AGENT_SESSION_DIR"] ?? join10(homedir7(), ".pi", "agent", "sessions");
|
|
10309
10384
|
function walkSessions(dir, acc = []) {
|
|
10310
10385
|
if (!existsSync8(dir))
|
|
10311
10386
|
return acc;
|
|
10312
10387
|
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
10313
|
-
const p =
|
|
10388
|
+
const p = join10(dir, entry.name);
|
|
10314
10389
|
if (entry.isDirectory())
|
|
10315
10390
|
walkSessions(p, acc);
|
|
10316
10391
|
else if (entry.name.endsWith(".json"))
|
|
@@ -10411,8 +10486,8 @@ async function ingestPi(db, verbose = false, sourceDir = PI_SESSION_DIR) {
|
|
|
10411
10486
|
init_database();
|
|
10412
10487
|
import { existsSync as existsSync9, statSync as statSync7 } from "fs";
|
|
10413
10488
|
import { homedir as homedir8 } from "os";
|
|
10414
|
-
import { join as
|
|
10415
|
-
var HERMES_DB =
|
|
10489
|
+
import { join as join11 } from "path";
|
|
10490
|
+
var HERMES_DB = join11(homedir8(), ".hermes", "state.db");
|
|
10416
10491
|
async function ingestHermes(db, verbose = false, sourcePath = HERMES_DB) {
|
|
10417
10492
|
if (!existsSync9(sourcePath)) {
|
|
10418
10493
|
collectionProblem("missing", "source_missing");
|
|
@@ -10482,7 +10557,7 @@ init_database();
|
|
|
10482
10557
|
init_pricing();
|
|
10483
10558
|
import { existsSync as existsSync10 } from "fs";
|
|
10484
10559
|
import { homedir as homedir9 } from "os";
|
|
10485
|
-
import { join as
|
|
10560
|
+
import { join as join12 } from "path";
|
|
10486
10561
|
import { homedir as pathsResolverHomedir2 } from "os";
|
|
10487
10562
|
import { join as pathsResolverJoin2 } from "path";
|
|
10488
10563
|
var PATHS_RESOLVER_KIND_ENV2 = {
|
|
@@ -10549,8 +10624,8 @@ function defaultLoopsDbPath() {
|
|
|
10549
10624
|
app: "loops",
|
|
10550
10625
|
home: process.env["HOME"] || process.env["USERPROFILE"] || undefined
|
|
10551
10626
|
});
|
|
10552
|
-
const legacy =
|
|
10553
|
-
return existsSync10(
|
|
10627
|
+
const legacy = join12(process.env["HOME"] || process.env["USERPROFILE"] || homedir9(), ".hasna", "loops", "loops.db");
|
|
10628
|
+
return existsSync10(join12(resolved, "loops.db")) ? join12(resolved, "loops.db") : legacy;
|
|
10554
10629
|
}
|
|
10555
10630
|
function loopsDbPath() {
|
|
10556
10631
|
return process.env["HASNA_ECONOMY_LOOPS_DB_PATH"] ?? defaultLoopsDbPath();
|
|
@@ -10734,33 +10809,6 @@ async function ingestLoops(db, verbose = false) {
|
|
|
10734
10809
|
|
|
10735
10810
|
// src/ingest/claude-quota.ts
|
|
10736
10811
|
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
10737
|
-
|
|
10738
|
-
// src/lib/paths.ts
|
|
10739
|
-
import { homedir as homedir10 } from "os";
|
|
10740
|
-
import { join as join12 } from "path";
|
|
10741
|
-
function getHomeDir2() {
|
|
10742
|
-
return process.env["USERPROFILE"] ?? process.env["HOME"] ?? homedir10();
|
|
10743
|
-
}
|
|
10744
|
-
function agentPaths() {
|
|
10745
|
-
const home = getHomeDir2();
|
|
10746
|
-
return {
|
|
10747
|
-
claudeProjects: join12(home, ".claude", "projects"),
|
|
10748
|
-
claudeCredentials: join12(home, ".claude", ".credentials.json"),
|
|
10749
|
-
takumiProjects: join12(home, ".takumi", "projects"),
|
|
10750
|
-
codexDir: join12(home, ".codex"),
|
|
10751
|
-
codexDb: join12(home, ".codex", "state_5.sqlite"),
|
|
10752
|
-
codexAuth: join12(home, ".codex", "auth.json"),
|
|
10753
|
-
codexConfig: join12(home, ".codex", "config.toml"),
|
|
10754
|
-
geminiTmp: join12(home, ".gemini", "tmp"),
|
|
10755
|
-
geminiHistory: join12(home, ".gemini", "history"),
|
|
10756
|
-
opencodeMessages: join12(home, ".local", "share", "opencode", "storage", "message"),
|
|
10757
|
-
piSessions: join12(home, ".pi", "agent", "sessions"),
|
|
10758
|
-
hermesDir: join12(home, ".hermes"),
|
|
10759
|
-
hermesDb: join12(home, ".hermes", "state.db")
|
|
10760
|
-
};
|
|
10761
|
-
}
|
|
10762
|
-
|
|
10763
|
-
// src/ingest/claude-quota.ts
|
|
10764
10812
|
var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
10765
10813
|
var OAUTH_BETA = "oauth-2025-04-20";
|
|
10766
10814
|
function readClaudeToken() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy-preservation.d.ts","sourceRoot":"","sources":["../../src/server/legacy-preservation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgD,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACnH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAc,MAAM,oBAAoB,CAAA;AAevF,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CA8C1D;AAOD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAEvF;AAED,UAAU,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;
|
|
1
|
+
{"version":3,"file":"legacy-preservation.d.ts","sourceRoot":"","sources":["../../src/server/legacy-preservation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgD,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACnH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAc,MAAM,oBAAoB,CAAA;AAevF,2FAA2F;AAC3F,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CA8C1D;AAOD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAEvF;AAED,UAAU,QAAQ;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AA6CnD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,eAAe,CAAC,OAAO,GAAG,OAAO,qBAAqB,CAAC,OAAO,CAAA;IAC7E,IAAI,EAAE,UAAU,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,QAAQ,EAAE,CAAA;IACpB,QAAQ,EAAE,QAAQ,EAAE,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CA4ChE;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAwB1G;AAmBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAU,GAAG,OAAO,CAS5E;AAED;sFACsF;AACtF,wBAAgB,kBAAkB,CAAC,IAAI,EAAC,MAAM,EAAC,KAAK,EAAC,OAAO;;;;;;;;;;;EAwB3D;AAED;;kFAEkF;AAClF,wBAAsB,qBAAqB,CAAC,MAAM,EAAC,YAAY,EAAC,KAAK,EAAC,OAAO,EAAC,KAAK,GAAC,aAAa,GAAC,WAAyB;;;;;;;;;;GA2D1H;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAC,MAAM,EAAC,IAAI,EAAC,MAAM,EAAE,GAAG;IAAC,KAAK,EAAC,MAAM,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAA;CAAC,CAM1G;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAC,MAAM,EAAC,OAAO,EAAC;IAAC,KAAK,EAAC,MAAM,CAAC;IAAA,MAAM,CAAC,EAAC,MAAM,CAAA;CAAC,iBAgB/F"}
|