@hasna/economy 0.3.26 → 0.3.27
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 +9 -0
- package/dist/cli/index.js +130 -27
- package/dist/index.js +103 -5
- package/dist/lib/package-metadata.d.ts.map +1 -1
- package/dist/mcp/index.js +119 -21
- package/dist/otel/index.js +103 -5
- package/dist/server/index.js +107 -9
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -2374,21 +2374,124 @@ var init_database = __esm(() => {
|
|
|
2374
2374
|
init_sqlite_adapter();
|
|
2375
2375
|
});
|
|
2376
2376
|
|
|
2377
|
+
// package.json
|
|
2378
|
+
var package_default;
|
|
2379
|
+
var init_package = __esm(() => {
|
|
2380
|
+
package_default = {
|
|
2381
|
+
name: "@hasna/economy",
|
|
2382
|
+
version: "0.3.27",
|
|
2383
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
2384
|
+
repository: {
|
|
2385
|
+
type: "git",
|
|
2386
|
+
url: "git+https://github.com/hasna/economy.git"
|
|
2387
|
+
},
|
|
2388
|
+
bugs: {
|
|
2389
|
+
url: "https://github.com/hasna/economy/issues"
|
|
2390
|
+
},
|
|
2391
|
+
homepage: "https://github.com/hasna/economy#readme",
|
|
2392
|
+
type: "module",
|
|
2393
|
+
main: "dist/index.js",
|
|
2394
|
+
types: "dist/index.d.ts",
|
|
2395
|
+
bin: {
|
|
2396
|
+
economy: "dist/cli/index.js",
|
|
2397
|
+
"economy-mcp": "dist/mcp/index.js",
|
|
2398
|
+
"economy-serve": "dist/server/index.js",
|
|
2399
|
+
"economy-otel": "dist/otel/index.js"
|
|
2400
|
+
},
|
|
2401
|
+
exports: {
|
|
2402
|
+
".": {
|
|
2403
|
+
types: "./dist/index.d.ts",
|
|
2404
|
+
import: "./dist/index.js"
|
|
2405
|
+
},
|
|
2406
|
+
"./sdk": {
|
|
2407
|
+
types: "./dist/index.d.ts",
|
|
2408
|
+
import: "./dist/index.js"
|
|
2409
|
+
}
|
|
2410
|
+
},
|
|
2411
|
+
files: [
|
|
2412
|
+
"dist",
|
|
2413
|
+
"docs",
|
|
2414
|
+
"dashboard/dist",
|
|
2415
|
+
"LICENSE",
|
|
2416
|
+
"README.md",
|
|
2417
|
+
"CHANGELOG.md",
|
|
2418
|
+
"SECURITY.md",
|
|
2419
|
+
"CONTRIBUTING.md",
|
|
2420
|
+
"CODE_OF_CONDUCT.md"
|
|
2421
|
+
],
|
|
2422
|
+
scripts: {
|
|
2423
|
+
build: "cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
2424
|
+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
2425
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
2426
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
2427
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
2428
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
2429
|
+
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
2430
|
+
prepack: "bun run build && bun run artifact-scan",
|
|
2431
|
+
typecheck: "tsc --noEmit",
|
|
2432
|
+
test: "bun test",
|
|
2433
|
+
"dev:cli": "bun run src/cli/index.ts",
|
|
2434
|
+
"dev:mcp": "bun run src/mcp/index.ts",
|
|
2435
|
+
"dev:serve": "bun run src/server/index.ts",
|
|
2436
|
+
"dev:otel": "bun run src/otel/index.ts",
|
|
2437
|
+
postinstall: "mkdir -p $HOME/.hasna/economy/training 2>/dev/null || true"
|
|
2438
|
+
},
|
|
2439
|
+
keywords: [
|
|
2440
|
+
"economy",
|
|
2441
|
+
"cost",
|
|
2442
|
+
"ai",
|
|
2443
|
+
"claude",
|
|
2444
|
+
"codex",
|
|
2445
|
+
"gemini",
|
|
2446
|
+
"mcp",
|
|
2447
|
+
"cli",
|
|
2448
|
+
"budget",
|
|
2449
|
+
"tracking"
|
|
2450
|
+
],
|
|
2451
|
+
author: "hasna",
|
|
2452
|
+
license: "Apache-2.0",
|
|
2453
|
+
publishConfig: {
|
|
2454
|
+
registry: "https://registry.npmjs.org",
|
|
2455
|
+
access: "public"
|
|
2456
|
+
},
|
|
2457
|
+
dependencies: {
|
|
2458
|
+
"@hasna/accounts": "0.2.23",
|
|
2459
|
+
"@hasna/agent-registry": "^0.1.0",
|
|
2460
|
+
"@hasna/contracts": "0.13.4",
|
|
2461
|
+
"@hasna/events": "^0.1.16",
|
|
2462
|
+
"@hasna/mcp-harness": "^0.1.0",
|
|
2463
|
+
"@hasna/projects": "1.0.0",
|
|
2464
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
2465
|
+
chalk: "^5.4.1",
|
|
2466
|
+
commander: "^13.1.0",
|
|
2467
|
+
pg: "8.13.1",
|
|
2468
|
+
zod: "^3.24.2"
|
|
2469
|
+
},
|
|
2470
|
+
devDependencies: {
|
|
2471
|
+
"@types/bun": "latest",
|
|
2472
|
+
"@types/pg": "^8.20.0",
|
|
2473
|
+
"bun-types": "latest",
|
|
2474
|
+
typescript: "^5.7.2"
|
|
2475
|
+
},
|
|
2476
|
+
trustedDependencies: [
|
|
2477
|
+
"@hasna/projects"
|
|
2478
|
+
]
|
|
2479
|
+
};
|
|
2480
|
+
});
|
|
2481
|
+
|
|
2377
2482
|
// src/lib/package-metadata.ts
|
|
2378
|
-
import { readFileSync } from "fs";
|
|
2379
2483
|
function getPackageMetadata() {
|
|
2380
2484
|
if (cachedMetadata)
|
|
2381
2485
|
return cachedMetadata;
|
|
2382
|
-
const raw = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
2383
|
-
const parsed = JSON.parse(raw);
|
|
2384
2486
|
cachedMetadata = {
|
|
2385
|
-
name:
|
|
2386
|
-
version:
|
|
2487
|
+
name: package_default.name ?? "@hasna/economy",
|
|
2488
|
+
version: package_default.version ?? "0.0.0"
|
|
2387
2489
|
};
|
|
2388
2490
|
return cachedMetadata;
|
|
2389
2491
|
}
|
|
2390
2492
|
var cachedMetadata = null, packageMetadata;
|
|
2391
2493
|
var init_package_metadata = __esm(() => {
|
|
2494
|
+
init_package();
|
|
2392
2495
|
packageMetadata = getPackageMetadata();
|
|
2393
2496
|
});
|
|
2394
2497
|
|
|
@@ -4128,7 +4231,7 @@ var init_accounts = __esm(() => {
|
|
|
4128
4231
|
});
|
|
4129
4232
|
|
|
4130
4233
|
// src/ingest/claude.ts
|
|
4131
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
4234
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync4, statSync as statSync2 } from "fs";
|
|
4132
4235
|
import { homedir as homedir3 } from "os";
|
|
4133
4236
|
import { join as join6, basename } from "path";
|
|
4134
4237
|
function autoDetectProject(cwd, projects) {
|
|
@@ -4188,7 +4291,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
4188
4291
|
continue;
|
|
4189
4292
|
let lines;
|
|
4190
4293
|
try {
|
|
4191
|
-
lines =
|
|
4294
|
+
lines = readFileSync2(filePath, "utf-8").split(`
|
|
4192
4295
|
`).filter((l) => l.trim());
|
|
4193
4296
|
} catch {
|
|
4194
4297
|
continue;
|
|
@@ -4314,7 +4417,7 @@ var init_claude = __esm(() => {
|
|
|
4314
4417
|
});
|
|
4315
4418
|
|
|
4316
4419
|
// src/ingest/codex.ts
|
|
4317
|
-
import { existsSync as existsSync5, readFileSync as
|
|
4420
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
4318
4421
|
import { homedir as homedir4 } from "os";
|
|
4319
4422
|
import { join as join7, basename as basename2 } from "path";
|
|
4320
4423
|
import { Database as BunDatabase } from "bun:sqlite";
|
|
@@ -4361,7 +4464,7 @@ function readCodexModel(configPath = codexConfigPath()) {
|
|
|
4361
4464
|
if (!existsSync5(configPath))
|
|
4362
4465
|
return "gpt-5-codex";
|
|
4363
4466
|
try {
|
|
4364
|
-
const content =
|
|
4467
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
4365
4468
|
const match = content.match(/^model\s*=\s*"([^"]+)"/m);
|
|
4366
4469
|
return match?.[1] ?? "gpt-5-codex";
|
|
4367
4470
|
} catch {
|
|
@@ -4404,7 +4507,7 @@ function readTokenEvents(rolloutPath) {
|
|
|
4404
4507
|
const fallbackUsages = new Map;
|
|
4405
4508
|
let fallbackTimestamp;
|
|
4406
4509
|
let aggregate = null;
|
|
4407
|
-
for (const line of
|
|
4510
|
+
for (const line of readFileSync3(rolloutPath, "utf-8").split(`
|
|
4408
4511
|
`)) {
|
|
4409
4512
|
if (!line.trim())
|
|
4410
4513
|
continue;
|
|
@@ -4569,7 +4672,7 @@ var init_codex = __esm(() => {
|
|
|
4569
4672
|
});
|
|
4570
4673
|
|
|
4571
4674
|
// src/ingest/gemini.ts
|
|
4572
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
4675
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync4, existsSync as existsSync6, statSync as statSync3 } from "fs";
|
|
4573
4676
|
import { homedir as homedir5 } from "os";
|
|
4574
4677
|
import { join as join8, basename as basename3 } from "path";
|
|
4575
4678
|
function geminiTmpDir() {
|
|
@@ -4607,7 +4710,7 @@ function projectRoot(projectDir, chatData) {
|
|
|
4607
4710
|
const rootFile = join8(projectDir, ".project_root");
|
|
4608
4711
|
try {
|
|
4609
4712
|
if (existsSync6(rootFile))
|
|
4610
|
-
return
|
|
4713
|
+
return readFileSync4(rootFile, "utf-8").trim();
|
|
4611
4714
|
} catch {}
|
|
4612
4715
|
return "";
|
|
4613
4716
|
}
|
|
@@ -4648,7 +4751,7 @@ async function ingestGemini(db, verbose) {
|
|
|
4648
4751
|
continue;
|
|
4649
4752
|
let chatData;
|
|
4650
4753
|
try {
|
|
4651
|
-
chatData = JSON.parse(
|
|
4754
|
+
chatData = JSON.parse(readFileSync4(filePath, "utf-8"));
|
|
4652
4755
|
} catch {
|
|
4653
4756
|
continue;
|
|
4654
4757
|
}
|
|
@@ -4732,7 +4835,7 @@ var init_gemini = __esm(() => {
|
|
|
4732
4835
|
});
|
|
4733
4836
|
|
|
4734
4837
|
// src/ingest/opencode.ts
|
|
4735
|
-
import { existsSync as existsSync7, readFileSync as
|
|
4838
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
4736
4839
|
import { homedir as homedir6 } from "os";
|
|
4737
4840
|
import { join as join9 } from "path";
|
|
4738
4841
|
function walkJsonFiles(dir, acc = []) {
|
|
@@ -4774,7 +4877,7 @@ async function ingestOpenCode(db, verbose = false) {
|
|
|
4774
4877
|
continue;
|
|
4775
4878
|
let parsed;
|
|
4776
4879
|
try {
|
|
4777
|
-
parsed = JSON.parse(
|
|
4880
|
+
parsed = JSON.parse(readFileSync5(file, "utf-8"));
|
|
4778
4881
|
} catch {
|
|
4779
4882
|
continue;
|
|
4780
4883
|
}
|
|
@@ -4970,7 +5073,7 @@ var init_cursor = __esm(() => {
|
|
|
4970
5073
|
});
|
|
4971
5074
|
|
|
4972
5075
|
// src/ingest/pi.ts
|
|
4973
|
-
import { existsSync as existsSync8, readFileSync as
|
|
5076
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
4974
5077
|
import { homedir as homedir7 } from "os";
|
|
4975
5078
|
import { join as join10 } from "path";
|
|
4976
5079
|
function walkSessions(dir, acc = []) {
|
|
@@ -4999,7 +5102,7 @@ async function ingestPi(db, verbose = false) {
|
|
|
4999
5102
|
continue;
|
|
5000
5103
|
let data;
|
|
5001
5104
|
try {
|
|
5002
|
-
data = JSON.parse(
|
|
5105
|
+
data = JSON.parse(readFileSync6(file, "utf-8"));
|
|
5003
5106
|
} catch {
|
|
5004
5107
|
continue;
|
|
5005
5108
|
}
|
|
@@ -5352,7 +5455,7 @@ var init_loops = __esm(() => {
|
|
|
5352
5455
|
});
|
|
5353
5456
|
|
|
5354
5457
|
// src/ingest/claude-quota.ts
|
|
5355
|
-
import { existsSync as existsSync11, readFileSync as
|
|
5458
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
5356
5459
|
function readClaudeToken() {
|
|
5357
5460
|
const fromEnv = process.env["CLAUDE_OAUTH_TOKEN"] ?? process.env["ANTHROPIC_OAUTH_TOKEN"];
|
|
5358
5461
|
if (fromEnv)
|
|
@@ -5360,7 +5463,7 @@ function readClaudeToken() {
|
|
|
5360
5463
|
if (!existsSync11(CREDENTIALS_PATH))
|
|
5361
5464
|
return null;
|
|
5362
5465
|
try {
|
|
5363
|
-
const creds = JSON.parse(
|
|
5466
|
+
const creds = JSON.parse(readFileSync7(CREDENTIALS_PATH, "utf-8"));
|
|
5364
5467
|
const oauth = creds.claudeAiOauth;
|
|
5365
5468
|
if (!oauth?.accessToken)
|
|
5366
5469
|
return null;
|
|
@@ -5501,7 +5604,7 @@ var init_claude_quota = __esm(() => {
|
|
|
5501
5604
|
});
|
|
5502
5605
|
|
|
5503
5606
|
// src/ingest/codex-quota.ts
|
|
5504
|
-
import { existsSync as existsSync12, readFileSync as
|
|
5607
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
|
|
5505
5608
|
function readCodexAuth() {
|
|
5506
5609
|
const fromEnv = process.env["CODEX_OAUTH_TOKEN"];
|
|
5507
5610
|
if (fromEnv)
|
|
@@ -5510,7 +5613,7 @@ function readCodexAuth() {
|
|
|
5510
5613
|
if (!existsSync12(authPath))
|
|
5511
5614
|
return null;
|
|
5512
5615
|
try {
|
|
5513
|
-
const auth = JSON.parse(
|
|
5616
|
+
const auth = JSON.parse(readFileSync8(authPath, "utf-8"));
|
|
5514
5617
|
const token = auth.tokens?.access_token;
|
|
5515
5618
|
if (!token)
|
|
5516
5619
|
return null;
|
|
@@ -5695,7 +5798,7 @@ __export(exports_billing, {
|
|
|
5695
5798
|
syncGeminiBilling: () => syncGeminiBilling,
|
|
5696
5799
|
syncAnthropicBilling: () => syncAnthropicBilling
|
|
5697
5800
|
});
|
|
5698
|
-
import { readFileSync as
|
|
5801
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
5699
5802
|
function getAnthropicAdminKey() {
|
|
5700
5803
|
return process.env["HASNAXYZ_ANTHROPIC_LIVE_ADMIN_API_KEY"] ?? process.env["ANTHROPIC_ADMIN_API_KEY"] ?? null;
|
|
5701
5804
|
}
|
|
@@ -5922,7 +6025,7 @@ async function syncGeminiBilling(db, opts = {}) {
|
|
|
5922
6025
|
const start = opts.fromDate ? new Date(opts.fromDate) : new Date(end.getTime() - days * 24 * 3600000);
|
|
5923
6026
|
const fromDateStr = toISODate(start);
|
|
5924
6027
|
const toDateStr = toISODate(end);
|
|
5925
|
-
const rows = parseBillingRows(
|
|
6028
|
+
const rows = parseBillingRows(readFileSync9(exportPath, "utf-8"));
|
|
5926
6029
|
clearBillingRange(db, "gemini", fromDateStr, toDateStr);
|
|
5927
6030
|
const updatedAt = new Date().toISOString();
|
|
5928
6031
|
let totalUsd = 0;
|
|
@@ -5993,7 +6096,7 @@ __export(exports_config, {
|
|
|
5993
6096
|
loadConfig: () => loadConfig2,
|
|
5994
6097
|
getConfigValue: () => getConfigValue
|
|
5995
6098
|
});
|
|
5996
|
-
import { existsSync as existsSync13, readFileSync as
|
|
6099
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
5997
6100
|
import { dirname as dirname2, join as join14 } from "path";
|
|
5998
6101
|
function getConfigPath() {
|
|
5999
6102
|
return process.env["HASNA_ECONOMY_CONFIG_PATH"] ?? join14(getDataDir(), "config.json");
|
|
@@ -6002,7 +6105,7 @@ function loadConfig2() {
|
|
|
6002
6105
|
try {
|
|
6003
6106
|
const configPath = getConfigPath();
|
|
6004
6107
|
if (existsSync13(configPath)) {
|
|
6005
|
-
const raw =
|
|
6108
|
+
const raw = readFileSync10(configPath, "utf-8");
|
|
6006
6109
|
return { ...DEFAULTS, ...JSON.parse(raw) };
|
|
6007
6110
|
}
|
|
6008
6111
|
} catch {}
|
|
@@ -9207,7 +9310,7 @@ ${goals.map((g) => `- ${g.period} goal (${g.project_path ?? g.agent ?? "global"}
|
|
|
9207
9310
|
|
|
9208
9311
|
// src/lib/model-config.ts
|
|
9209
9312
|
init_database();
|
|
9210
|
-
import { existsSync as existsSync2, readFileSync
|
|
9313
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
9211
9314
|
import { dirname, join as join2 } from "path";
|
|
9212
9315
|
var DEFAULT_MODEL = "gpt-4o-mini";
|
|
9213
9316
|
function getModelConfigPath() {
|
|
@@ -9217,7 +9320,7 @@ function loadConfig() {
|
|
|
9217
9320
|
try {
|
|
9218
9321
|
const configPath = getModelConfigPath();
|
|
9219
9322
|
if (existsSync2(configPath)) {
|
|
9220
|
-
return JSON.parse(
|
|
9323
|
+
return JSON.parse(readFileSync(configPath, "utf-8"));
|
|
9221
9324
|
}
|
|
9222
9325
|
} catch {}
|
|
9223
9326
|
return {};
|
package/dist/index.js
CHANGED
|
@@ -1990,18 +1990,116 @@ function isAgent(value) {
|
|
|
1990
1990
|
init_database();
|
|
1991
1991
|
init_pricing();
|
|
1992
1992
|
import { randomUUID } from "crypto";
|
|
1993
|
+
// package.json
|
|
1994
|
+
var package_default = {
|
|
1995
|
+
name: "@hasna/economy",
|
|
1996
|
+
version: "0.3.27",
|
|
1997
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
1998
|
+
repository: {
|
|
1999
|
+
type: "git",
|
|
2000
|
+
url: "git+https://github.com/hasna/economy.git"
|
|
2001
|
+
},
|
|
2002
|
+
bugs: {
|
|
2003
|
+
url: "https://github.com/hasna/economy/issues"
|
|
2004
|
+
},
|
|
2005
|
+
homepage: "https://github.com/hasna/economy#readme",
|
|
2006
|
+
type: "module",
|
|
2007
|
+
main: "dist/index.js",
|
|
2008
|
+
types: "dist/index.d.ts",
|
|
2009
|
+
bin: {
|
|
2010
|
+
economy: "dist/cli/index.js",
|
|
2011
|
+
"economy-mcp": "dist/mcp/index.js",
|
|
2012
|
+
"economy-serve": "dist/server/index.js",
|
|
2013
|
+
"economy-otel": "dist/otel/index.js"
|
|
2014
|
+
},
|
|
2015
|
+
exports: {
|
|
2016
|
+
".": {
|
|
2017
|
+
types: "./dist/index.d.ts",
|
|
2018
|
+
import: "./dist/index.js"
|
|
2019
|
+
},
|
|
2020
|
+
"./sdk": {
|
|
2021
|
+
types: "./dist/index.d.ts",
|
|
2022
|
+
import: "./dist/index.js"
|
|
2023
|
+
}
|
|
2024
|
+
},
|
|
2025
|
+
files: [
|
|
2026
|
+
"dist",
|
|
2027
|
+
"docs",
|
|
2028
|
+
"dashboard/dist",
|
|
2029
|
+
"LICENSE",
|
|
2030
|
+
"README.md",
|
|
2031
|
+
"CHANGELOG.md",
|
|
2032
|
+
"SECURITY.md",
|
|
2033
|
+
"CONTRIBUTING.md",
|
|
2034
|
+
"CODE_OF_CONDUCT.md"
|
|
2035
|
+
],
|
|
2036
|
+
scripts: {
|
|
2037
|
+
build: "cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
2038
|
+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
2039
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
2040
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
2041
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
2042
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
2043
|
+
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
2044
|
+
prepack: "bun run build && bun run artifact-scan",
|
|
2045
|
+
typecheck: "tsc --noEmit",
|
|
2046
|
+
test: "bun test",
|
|
2047
|
+
"dev:cli": "bun run src/cli/index.ts",
|
|
2048
|
+
"dev:mcp": "bun run src/mcp/index.ts",
|
|
2049
|
+
"dev:serve": "bun run src/server/index.ts",
|
|
2050
|
+
"dev:otel": "bun run src/otel/index.ts",
|
|
2051
|
+
postinstall: "mkdir -p $HOME/.hasna/economy/training 2>/dev/null || true"
|
|
2052
|
+
},
|
|
2053
|
+
keywords: [
|
|
2054
|
+
"economy",
|
|
2055
|
+
"cost",
|
|
2056
|
+
"ai",
|
|
2057
|
+
"claude",
|
|
2058
|
+
"codex",
|
|
2059
|
+
"gemini",
|
|
2060
|
+
"mcp",
|
|
2061
|
+
"cli",
|
|
2062
|
+
"budget",
|
|
2063
|
+
"tracking"
|
|
2064
|
+
],
|
|
2065
|
+
author: "hasna",
|
|
2066
|
+
license: "Apache-2.0",
|
|
2067
|
+
publishConfig: {
|
|
2068
|
+
registry: "https://registry.npmjs.org",
|
|
2069
|
+
access: "public"
|
|
2070
|
+
},
|
|
2071
|
+
dependencies: {
|
|
2072
|
+
"@hasna/accounts": "0.2.23",
|
|
2073
|
+
"@hasna/agent-registry": "^0.1.0",
|
|
2074
|
+
"@hasna/contracts": "0.13.4",
|
|
2075
|
+
"@hasna/events": "^0.1.16",
|
|
2076
|
+
"@hasna/mcp-harness": "^0.1.0",
|
|
2077
|
+
"@hasna/projects": "1.0.0",
|
|
2078
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
2079
|
+
chalk: "^5.4.1",
|
|
2080
|
+
commander: "^13.1.0",
|
|
2081
|
+
pg: "8.13.1",
|
|
2082
|
+
zod: "^3.24.2"
|
|
2083
|
+
},
|
|
2084
|
+
devDependencies: {
|
|
2085
|
+
"@types/bun": "latest",
|
|
2086
|
+
"@types/pg": "^8.20.0",
|
|
2087
|
+
"bun-types": "latest",
|
|
2088
|
+
typescript: "^5.7.2"
|
|
2089
|
+
},
|
|
2090
|
+
trustedDependencies: [
|
|
2091
|
+
"@hasna/projects"
|
|
2092
|
+
]
|
|
2093
|
+
};
|
|
1993
2094
|
|
|
1994
2095
|
// src/lib/package-metadata.ts
|
|
1995
|
-
import { readFileSync } from "fs";
|
|
1996
2096
|
var cachedMetadata = null;
|
|
1997
2097
|
function getPackageMetadata() {
|
|
1998
2098
|
if (cachedMetadata)
|
|
1999
2099
|
return cachedMetadata;
|
|
2000
|
-
const raw = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
2001
|
-
const parsed = JSON.parse(raw);
|
|
2002
2100
|
cachedMetadata = {
|
|
2003
|
-
name:
|
|
2004
|
-
version:
|
|
2101
|
+
name: package_default.name ?? "@hasna/economy",
|
|
2102
|
+
version: package_default.version ?? "0.0.0"
|
|
2005
2103
|
};
|
|
2006
2104
|
return cachedMetadata;
|
|
2007
2105
|
}
|
|
@@ -1 +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,
|
|
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,CASpD;AAED,eAAO,MAAM,eAAe,iBAAuB,CAAA"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -2082,18 +2082,116 @@ var init_database = __esm(() => {
|
|
|
2082
2082
|
|
|
2083
2083
|
// src/mcp/index.ts
|
|
2084
2084
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2085
|
+
// package.json
|
|
2086
|
+
var package_default = {
|
|
2087
|
+
name: "@hasna/economy",
|
|
2088
|
+
version: "0.3.27",
|
|
2089
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
2090
|
+
repository: {
|
|
2091
|
+
type: "git",
|
|
2092
|
+
url: "git+https://github.com/hasna/economy.git"
|
|
2093
|
+
},
|
|
2094
|
+
bugs: {
|
|
2095
|
+
url: "https://github.com/hasna/economy/issues"
|
|
2096
|
+
},
|
|
2097
|
+
homepage: "https://github.com/hasna/economy#readme",
|
|
2098
|
+
type: "module",
|
|
2099
|
+
main: "dist/index.js",
|
|
2100
|
+
types: "dist/index.d.ts",
|
|
2101
|
+
bin: {
|
|
2102
|
+
economy: "dist/cli/index.js",
|
|
2103
|
+
"economy-mcp": "dist/mcp/index.js",
|
|
2104
|
+
"economy-serve": "dist/server/index.js",
|
|
2105
|
+
"economy-otel": "dist/otel/index.js"
|
|
2106
|
+
},
|
|
2107
|
+
exports: {
|
|
2108
|
+
".": {
|
|
2109
|
+
types: "./dist/index.d.ts",
|
|
2110
|
+
import: "./dist/index.js"
|
|
2111
|
+
},
|
|
2112
|
+
"./sdk": {
|
|
2113
|
+
types: "./dist/index.d.ts",
|
|
2114
|
+
import: "./dist/index.js"
|
|
2115
|
+
}
|
|
2116
|
+
},
|
|
2117
|
+
files: [
|
|
2118
|
+
"dist",
|
|
2119
|
+
"docs",
|
|
2120
|
+
"dashboard/dist",
|
|
2121
|
+
"LICENSE",
|
|
2122
|
+
"README.md",
|
|
2123
|
+
"CHANGELOG.md",
|
|
2124
|
+
"SECURITY.md",
|
|
2125
|
+
"CONTRIBUTING.md",
|
|
2126
|
+
"CODE_OF_CONDUCT.md"
|
|
2127
|
+
],
|
|
2128
|
+
scripts: {
|
|
2129
|
+
build: "cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
2130
|
+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
2131
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
2132
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
2133
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
2134
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
2135
|
+
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
2136
|
+
prepack: "bun run build && bun run artifact-scan",
|
|
2137
|
+
typecheck: "tsc --noEmit",
|
|
2138
|
+
test: "bun test",
|
|
2139
|
+
"dev:cli": "bun run src/cli/index.ts",
|
|
2140
|
+
"dev:mcp": "bun run src/mcp/index.ts",
|
|
2141
|
+
"dev:serve": "bun run src/server/index.ts",
|
|
2142
|
+
"dev:otel": "bun run src/otel/index.ts",
|
|
2143
|
+
postinstall: "mkdir -p $HOME/.hasna/economy/training 2>/dev/null || true"
|
|
2144
|
+
},
|
|
2145
|
+
keywords: [
|
|
2146
|
+
"economy",
|
|
2147
|
+
"cost",
|
|
2148
|
+
"ai",
|
|
2149
|
+
"claude",
|
|
2150
|
+
"codex",
|
|
2151
|
+
"gemini",
|
|
2152
|
+
"mcp",
|
|
2153
|
+
"cli",
|
|
2154
|
+
"budget",
|
|
2155
|
+
"tracking"
|
|
2156
|
+
],
|
|
2157
|
+
author: "hasna",
|
|
2158
|
+
license: "Apache-2.0",
|
|
2159
|
+
publishConfig: {
|
|
2160
|
+
registry: "https://registry.npmjs.org",
|
|
2161
|
+
access: "public"
|
|
2162
|
+
},
|
|
2163
|
+
dependencies: {
|
|
2164
|
+
"@hasna/accounts": "0.2.23",
|
|
2165
|
+
"@hasna/agent-registry": "^0.1.0",
|
|
2166
|
+
"@hasna/contracts": "0.13.4",
|
|
2167
|
+
"@hasna/events": "^0.1.16",
|
|
2168
|
+
"@hasna/mcp-harness": "^0.1.0",
|
|
2169
|
+
"@hasna/projects": "1.0.0",
|
|
2170
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
2171
|
+
chalk: "^5.4.1",
|
|
2172
|
+
commander: "^13.1.0",
|
|
2173
|
+
pg: "8.13.1",
|
|
2174
|
+
zod: "^3.24.2"
|
|
2175
|
+
},
|
|
2176
|
+
devDependencies: {
|
|
2177
|
+
"@types/bun": "latest",
|
|
2178
|
+
"@types/pg": "^8.20.0",
|
|
2179
|
+
"bun-types": "latest",
|
|
2180
|
+
typescript: "^5.7.2"
|
|
2181
|
+
},
|
|
2182
|
+
trustedDependencies: [
|
|
2183
|
+
"@hasna/projects"
|
|
2184
|
+
]
|
|
2185
|
+
};
|
|
2085
2186
|
|
|
2086
2187
|
// src/lib/package-metadata.ts
|
|
2087
|
-
import { readFileSync } from "fs";
|
|
2088
2188
|
var cachedMetadata = null;
|
|
2089
2189
|
function getPackageMetadata() {
|
|
2090
2190
|
if (cachedMetadata)
|
|
2091
2191
|
return cachedMetadata;
|
|
2092
|
-
const raw = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
2093
|
-
const parsed = JSON.parse(raw);
|
|
2094
2192
|
cachedMetadata = {
|
|
2095
|
-
name:
|
|
2096
|
-
version:
|
|
2193
|
+
name: package_default.name ?? "@hasna/economy",
|
|
2194
|
+
version: package_default.version ?? "0.0.0"
|
|
2097
2195
|
};
|
|
2098
2196
|
return cachedMetadata;
|
|
2099
2197
|
}
|
|
@@ -2108,7 +2206,7 @@ import { z } from "zod";
|
|
|
2108
2206
|
// src/ingest/claude.ts
|
|
2109
2207
|
init_database();
|
|
2110
2208
|
init_pricing();
|
|
2111
|
-
import { readdirSync as readdirSync2, readFileSync
|
|
2209
|
+
import { readdirSync as readdirSync2, readFileSync, existsSync as existsSync2, statSync as statSync2 } from "fs";
|
|
2112
2210
|
import { homedir as homedir2 } from "os";
|
|
2113
2211
|
import { join as join2, basename } from "path";
|
|
2114
2212
|
|
|
@@ -2437,7 +2535,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
|
|
|
2437
2535
|
continue;
|
|
2438
2536
|
let lines;
|
|
2439
2537
|
try {
|
|
2440
|
-
lines =
|
|
2538
|
+
lines = readFileSync(filePath, "utf-8").split(`
|
|
2441
2539
|
`).filter((l) => l.trim());
|
|
2442
2540
|
} catch {
|
|
2443
2541
|
continue;
|
|
@@ -2557,7 +2655,7 @@ function supportsClaudeDataResidencyPricing(model) {
|
|
|
2557
2655
|
// src/ingest/codex.ts
|
|
2558
2656
|
init_database();
|
|
2559
2657
|
init_pricing();
|
|
2560
|
-
import { existsSync as existsSync3, readFileSync as
|
|
2658
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
2561
2659
|
import { homedir as homedir3 } from "os";
|
|
2562
2660
|
import { join as join3, basename as basename2 } from "path";
|
|
2563
2661
|
import { Database as BunDatabase } from "bun:sqlite";
|
|
@@ -2609,7 +2707,7 @@ function readCodexModel(configPath = codexConfigPath()) {
|
|
|
2609
2707
|
if (!existsSync3(configPath))
|
|
2610
2708
|
return "gpt-5-codex";
|
|
2611
2709
|
try {
|
|
2612
|
-
const content =
|
|
2710
|
+
const content = readFileSync2(configPath, "utf-8");
|
|
2613
2711
|
const match = content.match(/^model\s*=\s*"([^"]+)"/m);
|
|
2614
2712
|
return match?.[1] ?? "gpt-5-codex";
|
|
2615
2713
|
} catch {
|
|
@@ -2652,7 +2750,7 @@ function readTokenEvents(rolloutPath) {
|
|
|
2652
2750
|
const fallbackUsages = new Map;
|
|
2653
2751
|
let fallbackTimestamp;
|
|
2654
2752
|
let aggregate = null;
|
|
2655
|
-
for (const line of
|
|
2753
|
+
for (const line of readFileSync2(rolloutPath, "utf-8").split(`
|
|
2656
2754
|
`)) {
|
|
2657
2755
|
if (!line.trim())
|
|
2658
2756
|
continue;
|
|
@@ -2809,7 +2907,7 @@ async function ingestCodex(db, verbose = false) {
|
|
|
2809
2907
|
// src/ingest/gemini.ts
|
|
2810
2908
|
init_database();
|
|
2811
2909
|
init_pricing();
|
|
2812
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
2910
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync3, existsSync as existsSync4, statSync as statSync3 } from "fs";
|
|
2813
2911
|
import { homedir as homedir4 } from "os";
|
|
2814
2912
|
import { join as join4, basename as basename3 } from "path";
|
|
2815
2913
|
var DEFAULT_GEMINI_TMP_DIR = join4(homedir4(), ".gemini", "tmp");
|
|
@@ -2849,7 +2947,7 @@ function projectRoot(projectDir, chatData) {
|
|
|
2849
2947
|
const rootFile = join4(projectDir, ".project_root");
|
|
2850
2948
|
try {
|
|
2851
2949
|
if (existsSync4(rootFile))
|
|
2852
|
-
return
|
|
2950
|
+
return readFileSync3(rootFile, "utf-8").trim();
|
|
2853
2951
|
} catch {}
|
|
2854
2952
|
return "";
|
|
2855
2953
|
}
|
|
@@ -2890,7 +2988,7 @@ async function ingestGemini(db, verbose) {
|
|
|
2890
2988
|
continue;
|
|
2891
2989
|
let chatData;
|
|
2892
2990
|
try {
|
|
2893
|
-
chatData = JSON.parse(
|
|
2991
|
+
chatData = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
2894
2992
|
} catch {
|
|
2895
2993
|
continue;
|
|
2896
2994
|
}
|
|
@@ -2968,7 +3066,7 @@ async function ingestGemini(db, verbose) {
|
|
|
2968
3066
|
// src/ingest/opencode.ts
|
|
2969
3067
|
init_database();
|
|
2970
3068
|
init_pricing();
|
|
2971
|
-
import { existsSync as existsSync5, readFileSync as
|
|
3069
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync4, statSync as statSync4 } from "fs";
|
|
2972
3070
|
import { homedir as homedir5 } from "os";
|
|
2973
3071
|
import { join as join5 } from "path";
|
|
2974
3072
|
var OPENCODE_STORAGE = join5(homedir5(), ".local", "share", "opencode", "storage");
|
|
@@ -3011,7 +3109,7 @@ async function ingestOpenCode(db, verbose = false) {
|
|
|
3011
3109
|
continue;
|
|
3012
3110
|
let parsed;
|
|
3013
3111
|
try {
|
|
3014
|
-
parsed = JSON.parse(
|
|
3112
|
+
parsed = JSON.parse(readFileSync4(file, "utf-8"));
|
|
3015
3113
|
} catch {
|
|
3016
3114
|
continue;
|
|
3017
3115
|
}
|
|
@@ -3198,7 +3296,7 @@ async function ingestCursor(db, verbose = false) {
|
|
|
3198
3296
|
|
|
3199
3297
|
// src/ingest/pi.ts
|
|
3200
3298
|
init_database();
|
|
3201
|
-
import { existsSync as existsSync6, readFileSync as
|
|
3299
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync5, statSync as statSync5 } from "fs";
|
|
3202
3300
|
import { homedir as homedir6 } from "os";
|
|
3203
3301
|
import { join as join6 } from "path";
|
|
3204
3302
|
var PI_SESSION_DIR = process.env["PI_CODING_AGENT_SESSION_DIR"] ?? join6(homedir6(), ".pi", "agent", "sessions");
|
|
@@ -3228,7 +3326,7 @@ async function ingestPi(db, verbose = false) {
|
|
|
3228
3326
|
continue;
|
|
3229
3327
|
let data;
|
|
3230
3328
|
try {
|
|
3231
|
-
data = JSON.parse(
|
|
3329
|
+
data = JSON.parse(readFileSync5(file, "utf-8"));
|
|
3232
3330
|
} catch {
|
|
3233
3331
|
continue;
|
|
3234
3332
|
}
|
|
@@ -3570,7 +3668,7 @@ async function ingestLoops(db, verbose = false) {
|
|
|
3570
3668
|
|
|
3571
3669
|
// src/ingest/claude-quota.ts
|
|
3572
3670
|
init_database();
|
|
3573
|
-
import { existsSync as existsSync9, readFileSync as
|
|
3671
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
3574
3672
|
|
|
3575
3673
|
// src/lib/paths.ts
|
|
3576
3674
|
import { homedir as homedir9 } from "os";
|
|
@@ -3608,7 +3706,7 @@ function readClaudeToken() {
|
|
|
3608
3706
|
if (!existsSync9(CREDENTIALS_PATH))
|
|
3609
3707
|
return null;
|
|
3610
3708
|
try {
|
|
3611
|
-
const creds = JSON.parse(
|
|
3709
|
+
const creds = JSON.parse(readFileSync6(CREDENTIALS_PATH, "utf-8"));
|
|
3612
3710
|
const oauth = creds.claudeAiOauth;
|
|
3613
3711
|
if (!oauth?.accessToken)
|
|
3614
3712
|
return null;
|
|
@@ -3744,7 +3842,7 @@ async function ingestClaudeQuota(db, verbose = false) {
|
|
|
3744
3842
|
|
|
3745
3843
|
// src/ingest/codex-quota.ts
|
|
3746
3844
|
init_database();
|
|
3747
|
-
import { existsSync as existsSync10, readFileSync as
|
|
3845
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
3748
3846
|
var WHAM_USAGE_URL = process.env["CODEX_USAGE_URL"] ?? "https://chatgpt.com/backend-api/wham/usage";
|
|
3749
3847
|
function readCodexAuth() {
|
|
3750
3848
|
const fromEnv = process.env["CODEX_OAUTH_TOKEN"];
|
|
@@ -3754,7 +3852,7 @@ function readCodexAuth() {
|
|
|
3754
3852
|
if (!existsSync10(authPath))
|
|
3755
3853
|
return null;
|
|
3756
3854
|
try {
|
|
3757
|
-
const auth = JSON.parse(
|
|
3855
|
+
const auth = JSON.parse(readFileSync7(authPath, "utf-8"));
|
|
3758
3856
|
const token = auth.tokens?.access_token;
|
|
3759
3857
|
if (!token)
|
|
3760
3858
|
return null;
|
package/dist/otel/index.js
CHANGED
|
@@ -1385,18 +1385,116 @@ async function ingestOtelRows(db, rows) {
|
|
|
1385
1385
|
rollupSession(db, sessionId);
|
|
1386
1386
|
return { requests, sessions: sessions.size };
|
|
1387
1387
|
}
|
|
1388
|
+
// package.json
|
|
1389
|
+
var package_default = {
|
|
1390
|
+
name: "@hasna/economy",
|
|
1391
|
+
version: "0.3.27",
|
|
1392
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
1393
|
+
repository: {
|
|
1394
|
+
type: "git",
|
|
1395
|
+
url: "git+https://github.com/hasna/economy.git"
|
|
1396
|
+
},
|
|
1397
|
+
bugs: {
|
|
1398
|
+
url: "https://github.com/hasna/economy/issues"
|
|
1399
|
+
},
|
|
1400
|
+
homepage: "https://github.com/hasna/economy#readme",
|
|
1401
|
+
type: "module",
|
|
1402
|
+
main: "dist/index.js",
|
|
1403
|
+
types: "dist/index.d.ts",
|
|
1404
|
+
bin: {
|
|
1405
|
+
economy: "dist/cli/index.js",
|
|
1406
|
+
"economy-mcp": "dist/mcp/index.js",
|
|
1407
|
+
"economy-serve": "dist/server/index.js",
|
|
1408
|
+
"economy-otel": "dist/otel/index.js"
|
|
1409
|
+
},
|
|
1410
|
+
exports: {
|
|
1411
|
+
".": {
|
|
1412
|
+
types: "./dist/index.d.ts",
|
|
1413
|
+
import: "./dist/index.js"
|
|
1414
|
+
},
|
|
1415
|
+
"./sdk": {
|
|
1416
|
+
types: "./dist/index.d.ts",
|
|
1417
|
+
import: "./dist/index.js"
|
|
1418
|
+
}
|
|
1419
|
+
},
|
|
1420
|
+
files: [
|
|
1421
|
+
"dist",
|
|
1422
|
+
"docs",
|
|
1423
|
+
"dashboard/dist",
|
|
1424
|
+
"LICENSE",
|
|
1425
|
+
"README.md",
|
|
1426
|
+
"CHANGELOG.md",
|
|
1427
|
+
"SECURITY.md",
|
|
1428
|
+
"CONTRIBUTING.md",
|
|
1429
|
+
"CODE_OF_CONDUCT.md"
|
|
1430
|
+
],
|
|
1431
|
+
scripts: {
|
|
1432
|
+
build: "cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
1433
|
+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
1434
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
1435
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
1436
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
1437
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
1438
|
+
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
1439
|
+
prepack: "bun run build && bun run artifact-scan",
|
|
1440
|
+
typecheck: "tsc --noEmit",
|
|
1441
|
+
test: "bun test",
|
|
1442
|
+
"dev:cli": "bun run src/cli/index.ts",
|
|
1443
|
+
"dev:mcp": "bun run src/mcp/index.ts",
|
|
1444
|
+
"dev:serve": "bun run src/server/index.ts",
|
|
1445
|
+
"dev:otel": "bun run src/otel/index.ts",
|
|
1446
|
+
postinstall: "mkdir -p $HOME/.hasna/economy/training 2>/dev/null || true"
|
|
1447
|
+
},
|
|
1448
|
+
keywords: [
|
|
1449
|
+
"economy",
|
|
1450
|
+
"cost",
|
|
1451
|
+
"ai",
|
|
1452
|
+
"claude",
|
|
1453
|
+
"codex",
|
|
1454
|
+
"gemini",
|
|
1455
|
+
"mcp",
|
|
1456
|
+
"cli",
|
|
1457
|
+
"budget",
|
|
1458
|
+
"tracking"
|
|
1459
|
+
],
|
|
1460
|
+
author: "hasna",
|
|
1461
|
+
license: "Apache-2.0",
|
|
1462
|
+
publishConfig: {
|
|
1463
|
+
registry: "https://registry.npmjs.org",
|
|
1464
|
+
access: "public"
|
|
1465
|
+
},
|
|
1466
|
+
dependencies: {
|
|
1467
|
+
"@hasna/accounts": "0.2.23",
|
|
1468
|
+
"@hasna/agent-registry": "^0.1.0",
|
|
1469
|
+
"@hasna/contracts": "0.13.4",
|
|
1470
|
+
"@hasna/events": "^0.1.16",
|
|
1471
|
+
"@hasna/mcp-harness": "^0.1.0",
|
|
1472
|
+
"@hasna/projects": "1.0.0",
|
|
1473
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
1474
|
+
chalk: "^5.4.1",
|
|
1475
|
+
commander: "^13.1.0",
|
|
1476
|
+
pg: "8.13.1",
|
|
1477
|
+
zod: "^3.24.2"
|
|
1478
|
+
},
|
|
1479
|
+
devDependencies: {
|
|
1480
|
+
"@types/bun": "latest",
|
|
1481
|
+
"@types/pg": "^8.20.0",
|
|
1482
|
+
"bun-types": "latest",
|
|
1483
|
+
typescript: "^5.7.2"
|
|
1484
|
+
},
|
|
1485
|
+
trustedDependencies: [
|
|
1486
|
+
"@hasna/projects"
|
|
1487
|
+
]
|
|
1488
|
+
};
|
|
1388
1489
|
|
|
1389
1490
|
// src/lib/package-metadata.ts
|
|
1390
|
-
import { readFileSync } from "fs";
|
|
1391
1491
|
var cachedMetadata = null;
|
|
1392
1492
|
function getPackageMetadata() {
|
|
1393
1493
|
if (cachedMetadata)
|
|
1394
1494
|
return cachedMetadata;
|
|
1395
|
-
const raw = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
1396
|
-
const parsed = JSON.parse(raw);
|
|
1397
1495
|
cachedMetadata = {
|
|
1398
|
-
name:
|
|
1399
|
-
version:
|
|
1496
|
+
name: package_default.name ?? "@hasna/economy",
|
|
1497
|
+
version: package_default.version ?? "0.0.0"
|
|
1400
1498
|
};
|
|
1401
1499
|
return cachedMetadata;
|
|
1402
1500
|
}
|
package/dist/server/index.js
CHANGED
|
@@ -2874,7 +2874,7 @@ __export(exports_billing, {
|
|
|
2874
2874
|
syncGeminiBilling: () => syncGeminiBilling,
|
|
2875
2875
|
syncAnthropicBilling: () => syncAnthropicBilling
|
|
2876
2876
|
});
|
|
2877
|
-
import { readFileSync as
|
|
2877
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
2878
2878
|
function getAnthropicAdminKey() {
|
|
2879
2879
|
return process.env["HASNAXYZ_ANTHROPIC_LIVE_ADMIN_API_KEY"] ?? process.env["ANTHROPIC_ADMIN_API_KEY"] ?? null;
|
|
2880
2880
|
}
|
|
@@ -3101,7 +3101,7 @@ async function syncGeminiBilling(db, opts = {}) {
|
|
|
3101
3101
|
const start = opts.fromDate ? new Date(opts.fromDate) : new Date(end.getTime() - days * 24 * 3600000);
|
|
3102
3102
|
const fromDateStr = toISODate(start);
|
|
3103
3103
|
const toDateStr = toISODate(end);
|
|
3104
|
-
const rows = parseBillingRows(
|
|
3104
|
+
const rows = parseBillingRows(readFileSync8(exportPath, "utf-8"));
|
|
3105
3105
|
clearBillingRange(db, "gemini", fromDateStr, toDateStr);
|
|
3106
3106
|
const updatedAt = new Date().toISOString();
|
|
3107
3107
|
let totalUsd = 0;
|
|
@@ -3165,7 +3165,7 @@ var init_open_projects = __esm(() => {
|
|
|
3165
3165
|
});
|
|
3166
3166
|
|
|
3167
3167
|
// src/lib/config.ts
|
|
3168
|
-
import { existsSync as existsSync12, readFileSync as
|
|
3168
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
3169
3169
|
import { dirname as dirname2, join as join11 } from "path";
|
|
3170
3170
|
function getConfigPath() {
|
|
3171
3171
|
return process.env["HASNA_ECONOMY_CONFIG_PATH"] ?? join11(getDataDir(), "config.json");
|
|
@@ -3174,7 +3174,7 @@ function loadConfig() {
|
|
|
3174
3174
|
try {
|
|
3175
3175
|
const configPath = getConfigPath();
|
|
3176
3176
|
if (existsSync12(configPath)) {
|
|
3177
|
-
const raw =
|
|
3177
|
+
const raw = readFileSync9(configPath, "utf-8");
|
|
3178
3178
|
return { ...DEFAULTS, ...JSON.parse(raw) };
|
|
3179
3179
|
}
|
|
3180
3180
|
} catch {}
|
|
@@ -5976,18 +5976,116 @@ function isAuthorizedRequest(req, path) {
|
|
|
5976
5976
|
import { randomUUID } from "crypto";
|
|
5977
5977
|
import { existsSync as existsSync13 } from "fs";
|
|
5978
5978
|
import { resolve, sep } from "path";
|
|
5979
|
+
// package.json
|
|
5980
|
+
var package_default = {
|
|
5981
|
+
name: "@hasna/economy",
|
|
5982
|
+
version: "0.3.27",
|
|
5983
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
5984
|
+
repository: {
|
|
5985
|
+
type: "git",
|
|
5986
|
+
url: "git+https://github.com/hasna/economy.git"
|
|
5987
|
+
},
|
|
5988
|
+
bugs: {
|
|
5989
|
+
url: "https://github.com/hasna/economy/issues"
|
|
5990
|
+
},
|
|
5991
|
+
homepage: "https://github.com/hasna/economy#readme",
|
|
5992
|
+
type: "module",
|
|
5993
|
+
main: "dist/index.js",
|
|
5994
|
+
types: "dist/index.d.ts",
|
|
5995
|
+
bin: {
|
|
5996
|
+
economy: "dist/cli/index.js",
|
|
5997
|
+
"economy-mcp": "dist/mcp/index.js",
|
|
5998
|
+
"economy-serve": "dist/server/index.js",
|
|
5999
|
+
"economy-otel": "dist/otel/index.js"
|
|
6000
|
+
},
|
|
6001
|
+
exports: {
|
|
6002
|
+
".": {
|
|
6003
|
+
types: "./dist/index.d.ts",
|
|
6004
|
+
import: "./dist/index.js"
|
|
6005
|
+
},
|
|
6006
|
+
"./sdk": {
|
|
6007
|
+
types: "./dist/index.d.ts",
|
|
6008
|
+
import: "./dist/index.js"
|
|
6009
|
+
}
|
|
6010
|
+
},
|
|
6011
|
+
files: [
|
|
6012
|
+
"dist",
|
|
6013
|
+
"docs",
|
|
6014
|
+
"dashboard/dist",
|
|
6015
|
+
"LICENSE",
|
|
6016
|
+
"README.md",
|
|
6017
|
+
"CHANGELOG.md",
|
|
6018
|
+
"SECURITY.md",
|
|
6019
|
+
"CONTRIBUTING.md",
|
|
6020
|
+
"CODE_OF_CONDUCT.md"
|
|
6021
|
+
],
|
|
6022
|
+
scripts: {
|
|
6023
|
+
build: "cd dashboard && bun install --frozen-lockfile && bun run build && cd .. && bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
6024
|
+
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
6025
|
+
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
6026
|
+
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
6027
|
+
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
6028
|
+
"build:dashboard": "cd dashboard && bun run build",
|
|
6029
|
+
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
6030
|
+
prepack: "bun run build && bun run artifact-scan",
|
|
6031
|
+
typecheck: "tsc --noEmit",
|
|
6032
|
+
test: "bun test",
|
|
6033
|
+
"dev:cli": "bun run src/cli/index.ts",
|
|
6034
|
+
"dev:mcp": "bun run src/mcp/index.ts",
|
|
6035
|
+
"dev:serve": "bun run src/server/index.ts",
|
|
6036
|
+
"dev:otel": "bun run src/otel/index.ts",
|
|
6037
|
+
postinstall: "mkdir -p $HOME/.hasna/economy/training 2>/dev/null || true"
|
|
6038
|
+
},
|
|
6039
|
+
keywords: [
|
|
6040
|
+
"economy",
|
|
6041
|
+
"cost",
|
|
6042
|
+
"ai",
|
|
6043
|
+
"claude",
|
|
6044
|
+
"codex",
|
|
6045
|
+
"gemini",
|
|
6046
|
+
"mcp",
|
|
6047
|
+
"cli",
|
|
6048
|
+
"budget",
|
|
6049
|
+
"tracking"
|
|
6050
|
+
],
|
|
6051
|
+
author: "hasna",
|
|
6052
|
+
license: "Apache-2.0",
|
|
6053
|
+
publishConfig: {
|
|
6054
|
+
registry: "https://registry.npmjs.org",
|
|
6055
|
+
access: "public"
|
|
6056
|
+
},
|
|
6057
|
+
dependencies: {
|
|
6058
|
+
"@hasna/accounts": "0.2.23",
|
|
6059
|
+
"@hasna/agent-registry": "^0.1.0",
|
|
6060
|
+
"@hasna/contracts": "0.13.4",
|
|
6061
|
+
"@hasna/events": "^0.1.16",
|
|
6062
|
+
"@hasna/mcp-harness": "^0.1.0",
|
|
6063
|
+
"@hasna/projects": "1.0.0",
|
|
6064
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
6065
|
+
chalk: "^5.4.1",
|
|
6066
|
+
commander: "^13.1.0",
|
|
6067
|
+
pg: "8.13.1",
|
|
6068
|
+
zod: "^3.24.2"
|
|
6069
|
+
},
|
|
6070
|
+
devDependencies: {
|
|
6071
|
+
"@types/bun": "latest",
|
|
6072
|
+
"@types/pg": "^8.20.0",
|
|
6073
|
+
"bun-types": "latest",
|
|
6074
|
+
typescript: "^5.7.2"
|
|
6075
|
+
},
|
|
6076
|
+
trustedDependencies: [
|
|
6077
|
+
"@hasna/projects"
|
|
6078
|
+
]
|
|
6079
|
+
};
|
|
5979
6080
|
|
|
5980
6081
|
// src/lib/package-metadata.ts
|
|
5981
|
-
import { readFileSync as readFileSync8 } from "fs";
|
|
5982
6082
|
var cachedMetadata = null;
|
|
5983
6083
|
function getPackageMetadata() {
|
|
5984
6084
|
if (cachedMetadata)
|
|
5985
6085
|
return cachedMetadata;
|
|
5986
|
-
const raw = readFileSync8(new URL("../../package.json", import.meta.url), "utf8");
|
|
5987
|
-
const parsed = JSON.parse(raw);
|
|
5988
6086
|
cachedMetadata = {
|
|
5989
|
-
name:
|
|
5990
|
-
version:
|
|
6087
|
+
name: package_default.name ?? "@hasna/economy",
|
|
6088
|
+
version: package_default.version ?? "0.0.0"
|
|
5991
6089
|
};
|
|
5992
6090
|
return cachedMetadata;
|
|
5993
6091
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/economy",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.27",
|
|
4
4
|
"description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
".": {
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"import": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./sdk": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
26
30
|
}
|
|
27
31
|
},
|
|
28
32
|
"files": [
|