@hasna/economy 0.5.4 → 0.5.5

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Read Codex and Claude usage and quota credentials from their selected native profile directories while preserving explicit Economy source overrides. A missing selected profile stays missing instead of reading another account's default directory. An explicitly selected Codex profile includes the legacy Codewith reader only when its source is explicitly configured too.
8
+
3
9
  ## 0.5.4
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -128,7 +128,9 @@ economy sync --recalculate
128
128
  economy sync --backfill-machine
129
129
  ```
130
130
 
131
- Full sync also imports active project metadata from `@hasna/projects` when the registry is available. The Codex source reads both `~/.codex/state_5.sqlite` and the Codewith store at `~/.codewith/state_5.sqlite` by default; explicit `HASNA_ECONOMY_CODEX_DB_PATH` and `HASNA_ECONOMY_CODEWITH_DB_PATH` values override those locations.
131
+ Full sync also imports active project metadata from `@hasna/projects` when the registry is available. Codex reads `CODEX_HOME/state_5.sqlite` and Claude reads `CLAUDE_CONFIG_DIR/projects` when those native profile directories are set; otherwise they use `~/.codex/state_5.sqlite` and `~/.claude/projects`. Explicit `HASNA_ECONOMY_CODEX_DB_PATH` and `HASNA_ECONOMY_CLAUDE_PROJECTS_DIR` overrides take precedence. Codex configuration follows `CODEX_HOME/config.toml` unless `HASNA_ECONOMY_CODEX_CONFIG_PATH` is set. Quota credentials follow those same native profile directories, retaining the existing OAuth-token environment overrides. A missing selected source or credential is reported as missing, without falling back to another profile.
132
+
133
+ The existing Codewith compatibility reader uses `~/.codewith/state_5.sqlite`, with `HASNA_ECONOMY_CODEWITH_DB_PATH` as its explicit override. When `CODEX_HOME` or `HASNA_ECONOMY_CODEX_DB_PATH` explicitly selects a Codex source, the compatibility reader runs only if `HASNA_ECONOMY_CODEWITH_DB_PATH` is also set.
132
134
 
133
135
  Account attribution uses the hosted Subscriptions registry through the installed `subscriptions` CLI and its own credential resolver. Economy reads `subscriptions list --json` and `subscriptions tools list --json` once per resolution, retaining the owning package's station-local paths and applied bindings. It does not activate a profile or copy credentials. A matching explicit agent directory takes precedence; an unmatched or ambiguous directory cannot inherit another profile. With no explicit directory, a station's applied binding can supply attribution; the shared registry's current selection alone cannot identify the local account.
134
136
 
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  LOCAL_STORAGE_OPT_IN_KEYS
4
- } from "./index-n1wwqxfe.js";
4
+ } from "./index-pnnqdv3r.js";
5
5
  import {
6
6
  assessCostFromDb,
7
7
  getIngestState,
@@ -71,8 +71,8 @@ function sourceTimeMillis(value) {
71
71
 
72
72
  // src/ingest/claude.ts
73
73
  import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync2, statSync } from "fs";
74
- import { homedir as homedir2 } from "os";
75
- import { join as join2, basename } from "path";
74
+ import { homedir as homedir3 } from "os";
75
+ import { join as join3, basename } from "path";
76
76
 
77
77
  // src/lib/accounts-store.ts
78
78
  import { existsSync, readFileSync } from "fs";
@@ -679,12 +679,41 @@ function withAccount(record, account) {
679
679
  };
680
680
  }
681
681
 
682
+ // src/lib/paths.ts
683
+ import { homedir as homedir2 } from "os";
684
+ import { join as join2 } from "path";
685
+ function getHomeDir() {
686
+ return process.env["USERPROFILE"] ?? process.env["HOME"] ?? homedir2();
687
+ }
688
+ function agentPaths() {
689
+ const home = getHomeDir();
690
+ const claudeHome = process.env["CLAUDE_CONFIG_DIR"] || join2(home, ".claude");
691
+ const codexHome = process.env["CODEX_HOME"] || join2(home, ".codex");
692
+ return {
693
+ claudeProjects: join2(claudeHome, "projects"),
694
+ claudeCredentials: join2(claudeHome, ".credentials.json"),
695
+ takumiProjects: join2(home, ".takumi", "projects"),
696
+ codexDir: codexHome,
697
+ codexDb: join2(codexHome, "state_5.sqlite"),
698
+ codexAuth: join2(codexHome, "auth.json"),
699
+ codexConfig: join2(codexHome, "config.toml"),
700
+ geminiTmp: join2(home, ".gemini", "tmp"),
701
+ geminiHistory: join2(home, ".gemini", "history"),
702
+ opencodeMessages: join2(home, ".local", "share", "opencode", "storage", "message"),
703
+ piSessions: join2(home, ".pi", "agent", "sessions"),
704
+ hermesDir: join2(home, ".hermes"),
705
+ hermesDb: join2(home, ".hermes", "state.db")
706
+ };
707
+ }
708
+
682
709
  // src/ingest/claude.ts
683
710
  function autoDetectProject(cwd, projects) {
684
711
  return projects.find((p) => cwd === p.path || cwd.startsWith(p.path + "/"));
685
712
  }
686
- var CLAUDE_PROJECTS_DIR = process.env["HASNA_ECONOMY_CLAUDE_PROJECTS_DIR"] ?? join2(homedir2(), ".claude", "projects");
687
- var TAKUMI_PROJECTS_DIR = process.env["HASNA_ECONOMY_TAKUMI_PROJECTS_DIR"] ?? join2(homedir2(), ".takumi", "projects");
713
+ var TAKUMI_PROJECTS_DIR = process.env["HASNA_ECONOMY_TAKUMI_PROJECTS_DIR"] ?? join3(homedir3(), ".takumi", "projects");
714
+ function claudeProjectsDir() {
715
+ return process.env["HASNA_ECONOMY_CLAUDE_PROJECTS_DIR"] ?? agentPaths().claudeProjects;
716
+ }
688
717
  function dirNameToPath(dirName) {
689
718
  return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
690
719
  }
@@ -694,9 +723,9 @@ function collectJsonlFiles(projectDir) {
694
723
  try {
695
724
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
696
725
  if (entry.isDirectory())
697
- walk(join2(dir, entry.name));
726
+ walk(join3(dir, entry.name));
698
727
  else if (entry.name.endsWith(".jsonl"))
699
- files.push(join2(dir, entry.name));
728
+ files.push(join3(dir, entry.name));
700
729
  }
701
730
  } catch {
702
731
  collectionProblem("failed", "source_unreadable");
@@ -705,7 +734,7 @@ function collectJsonlFiles(projectDir) {
705
734
  walk(projectDir);
706
735
  return files;
707
736
  }
708
- async function ingestClaude(db, verbose = false, projectsDir = CLAUDE_PROJECTS_DIR) {
737
+ async function ingestClaude(db, verbose = false, projectsDir = claudeProjectsDir()) {
709
738
  return ingestJsonlProjects(db, projectsDir, "claude", verbose);
710
739
  }
711
740
  async function ingestTakumi(db, verbose = false, projectsDir = TAKUMI_PROJECTS_DIR) {
@@ -727,7 +756,7 @@ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false)
727
756
  const ingestState = loadIngestState(db, agentName);
728
757
  const projectDirs = readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
729
758
  for (const projectDirEntry of projectDirs) {
730
- const projectDirPath = join2(projectsDir, projectDirEntry.name);
759
+ const projectDirPath = join3(projectsDir, projectDirEntry.name);
731
760
  const projectPath = dirNameToPath(projectDirEntry.name);
732
761
  const jsonlFiles = collectJsonlFiles(projectDirPath);
733
762
  for (const filePath of jsonlFiles) {
@@ -876,24 +905,19 @@ function supportsClaudeDataResidencyPricing(model) {
876
905
  // src/ingest/codex.ts
877
906
  import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
878
907
  import { createHash } from "crypto";
879
- import { homedir as homedir3 } from "os";
880
- import { join as join3, basename as basename2 } from "path";
881
- var DEFAULT_CODEX_DB_PATH = join3(homedir3(), ".codex", "state_5.sqlite");
882
- var DEFAULT_CODEX_CONFIG_PATH = join3(homedir3(), ".codex", "config.toml");
883
- var DEFAULT_CODEWITH_DB_PATH = join3(homedir3(), ".codewith", "state_5.sqlite");
884
- var DEFAULT_CODEWITH_CONFIG_PATH = join3(homedir3(), ".codewith", "config.toml");
908
+ import { join as join4, basename as basename2 } from "path";
885
909
  var CODEX_INGEST_VERSION = "rollout-events-v4";
886
910
  function codexDbPath() {
887
- return process.env["HASNA_ECONOMY_CODEX_DB_PATH"] ?? DEFAULT_CODEX_DB_PATH;
911
+ return process.env["HASNA_ECONOMY_CODEX_DB_PATH"] ?? agentPaths().codexDb;
888
912
  }
889
913
  function codexConfigPath() {
890
- return process.env["HASNA_ECONOMY_CODEX_CONFIG_PATH"] ?? DEFAULT_CODEX_CONFIG_PATH;
914
+ return process.env["HASNA_ECONOMY_CODEX_CONFIG_PATH"] ?? agentPaths().codexConfig;
891
915
  }
892
916
  function codewithDbPath() {
893
- return process.env["HASNA_ECONOMY_CODEWITH_DB_PATH"] ?? DEFAULT_CODEWITH_DB_PATH;
917
+ return process.env["HASNA_ECONOMY_CODEWITH_DB_PATH"] ?? join4(getHomeDir(), ".codewith", "state_5.sqlite");
894
918
  }
895
919
  function codewithConfigPath() {
896
- return process.env["HASNA_ECONOMY_CODEWITH_CONFIG_PATH"] ?? DEFAULT_CODEWITH_CONFIG_PATH;
920
+ return process.env["HASNA_ECONOMY_CODEWITH_CONFIG_PATH"] ?? join4(getHomeDir(), ".codewith", "config.toml");
897
921
  }
898
922
  function codexSources() {
899
923
  const explicitCodexPath = process.env["HASNA_ECONOMY_CODEX_DB_PATH"];
@@ -905,7 +929,7 @@ function codexSources() {
905
929
  sessionPrefix: "codex",
906
930
  stateSource: "codex"
907
931
  }];
908
- if (!explicitCodexPath || explicitCodewithPath) {
932
+ if (!explicitCodexPath && !process.env["CODEX_HOME"] || explicitCodewithPath) {
909
933
  sources.push({
910
934
  label: "Codewith",
911
935
  dbPath: codewithDbPath(),
@@ -1143,9 +1167,9 @@ async function ingestCodex(db, verbose = false) {
1143
1167
  // src/ingest/gemini.ts
1144
1168
  import { readdirSync as readdirSync2, readFileSync as readFileSync4, existsSync as existsSync4, statSync as statSync3 } from "fs";
1145
1169
  import { homedir as homedir4 } from "os";
1146
- import { join as join4, basename as basename3 } from "path";
1147
- var DEFAULT_GEMINI_TMP_DIR = join4(homedir4(), ".gemini", "tmp");
1148
- var DEFAULT_GEMINI_HISTORY_DIR = join4(homedir4(), ".gemini", "history");
1170
+ import { join as join5, basename as basename3 } from "path";
1171
+ var DEFAULT_GEMINI_TMP_DIR = join5(homedir4(), ".gemini", "tmp");
1172
+ var DEFAULT_GEMINI_HISTORY_DIR = join5(homedir4(), ".gemini", "history");
1149
1173
  function geminiTmpDir() {
1150
1174
  return process.env["HASNA_ECONOMY_GEMINI_TMP_DIR"] ?? DEFAULT_GEMINI_TMP_DIR;
1151
1175
  }
@@ -1167,7 +1191,7 @@ function listProjectDirs(...roots) {
1167
1191
  try {
1168
1192
  for (const entry of readdirSync2(root, { withFileTypes: true })) {
1169
1193
  if (entry.isDirectory())
1170
- dirs.add(join4(root, entry.name));
1194
+ dirs.add(join5(root, entry.name));
1171
1195
  }
1172
1196
  } catch {
1173
1197
  collectionProblem("failed", "source_unreadable");
@@ -1180,7 +1204,7 @@ function projectRoot(projectDir, chatData) {
1180
1204
  return chatData.projectPath;
1181
1205
  if (chatData.project_path)
1182
1206
  return chatData.project_path;
1183
- const rootFile = join4(projectDir, ".project_root");
1207
+ const rootFile = join5(projectDir, ".project_root");
1184
1208
  try {
1185
1209
  if (existsSync4(rootFile))
1186
1210
  return readFileSync4(rootFile, "utf-8").trim();
@@ -1205,12 +1229,12 @@ async function ingestGemini(db, verbose) {
1205
1229
  const account = await resolveAccountForAgent("gemini");
1206
1230
  const projectDirs = listProjectDirs(tmpDir, historyDir);
1207
1231
  for (const projectDir of projectDirs) {
1208
- const chatsDir = join4(projectDir, "chats");
1232
+ const chatsDir = join5(projectDir, "chats");
1209
1233
  if (!existsSync4(chatsDir))
1210
1234
  continue;
1211
1235
  let chatFiles = [];
1212
1236
  try {
1213
- chatFiles = readdirSync2(chatsDir).filter((f) => f.endsWith(".json")).map((f) => join4(chatsDir, f));
1237
+ chatFiles = readdirSync2(chatsDir).filter((f) => f.endsWith(".json")).map((f) => join5(chatsDir, f));
1214
1238
  } catch {
1215
1239
  collectionProblem("failed", "source_unreadable");
1216
1240
  continue;
@@ -1320,13 +1344,13 @@ async function ingestGemini(db, verbose) {
1320
1344
  // src/ingest/opencode.ts
1321
1345
  import { existsSync as existsSync5, readFileSync as readFileSync5, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
1322
1346
  import { homedir as homedir5 } from "os";
1323
- import { join as join5 } from "path";
1324
- var OPENCODE_STORAGE = join5(homedir5(), ".local", "share", "opencode", "storage");
1347
+ import { join as join6 } from "path";
1348
+ var OPENCODE_STORAGE = join6(homedir5(), ".local", "share", "opencode", "storage");
1325
1349
  function walkJsonFiles(dir, acc = []) {
1326
1350
  if (!existsSync5(dir))
1327
1351
  return acc;
1328
1352
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
1329
- const p = join5(dir, entry.name);
1353
+ const p = join6(dir, entry.name);
1330
1354
  if (entry.isDirectory())
1331
1355
  walkJsonFiles(p, acc);
1332
1356
  else if (entry.name.endsWith(".json"))
@@ -1346,7 +1370,7 @@ function parseSessionIdFromPath(filePath) {
1346
1370
  return null;
1347
1371
  }
1348
1372
  async function ingestOpenCode(db, verbose = false, sourceDir = OPENCODE_STORAGE) {
1349
- const messageDir = join5(sourceDir, "message");
1373
+ const messageDir = join6(sourceDir, "message");
1350
1374
  if (!existsSync5(messageDir))
1351
1375
  collectionProblem("missing", "source_missing");
1352
1376
  const files = walkJsonFiles(messageDir);
@@ -1538,13 +1562,13 @@ async function ingestCursor(db, verbose = false) {
1538
1562
  // src/ingest/pi.ts
1539
1563
  import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync5 } from "fs";
1540
1564
  import { homedir as homedir6 } from "os";
1541
- import { join as join6 } from "path";
1542
- var PI_SESSION_DIR = process.env["PI_CODING_AGENT_SESSION_DIR"] ?? join6(homedir6(), ".pi", "agent", "sessions");
1565
+ import { join as join7 } from "path";
1566
+ var PI_SESSION_DIR = process.env["PI_CODING_AGENT_SESSION_DIR"] ?? join7(homedir6(), ".pi", "agent", "sessions");
1543
1567
  function walkSessions(dir, acc = []) {
1544
1568
  if (!existsSync6(dir))
1545
1569
  return acc;
1546
1570
  for (const entry of readdirSync4(dir, { withFileTypes: true })) {
1547
- const p = join6(dir, entry.name);
1571
+ const p = join7(dir, entry.name);
1548
1572
  if (entry.isDirectory())
1549
1573
  walkSessions(p, acc);
1550
1574
  else if (entry.name.endsWith(".json"))
@@ -1644,8 +1668,8 @@ async function ingestPi(db, verbose = false, sourceDir = PI_SESSION_DIR) {
1644
1668
  // src/ingest/hermes.ts
1645
1669
  import { existsSync as existsSync7, statSync as statSync6 } from "fs";
1646
1670
  import { homedir as homedir7 } from "os";
1647
- import { join as join7 } from "path";
1648
- var HERMES_DB = join7(homedir7(), ".hermes", "state.db");
1671
+ import { join as join8 } from "path";
1672
+ var HERMES_DB = join8(homedir7(), ".hermes", "state.db");
1649
1673
  async function ingestHermes(db, verbose = false, sourcePath = HERMES_DB) {
1650
1674
  if (!existsSync7(sourcePath)) {
1651
1675
  collectionProblem("missing", "source_missing");
@@ -1713,7 +1737,7 @@ function statSyncSafe(path) {
1713
1737
  // src/ingest/loops.ts
1714
1738
  import { existsSync as existsSync8 } from "fs";
1715
1739
  import { homedir as homedir8 } from "os";
1716
- import { join as join8 } from "path";
1740
+ import { join as join9 } from "path";
1717
1741
  import { homedir as pathsResolverHomedir } from "os";
1718
1742
  import { join as pathsResolverJoin } from "path";
1719
1743
  var PATHS_RESOLVER_KIND_ENV = {
@@ -1780,8 +1804,8 @@ function defaultLoopsDbPath() {
1780
1804
  app: "loops",
1781
1805
  home: process.env["HOME"] || process.env["USERPROFILE"] || undefined
1782
1806
  });
1783
- const legacy = join8(process.env["HOME"] || process.env["USERPROFILE"] || homedir8(), ".hasna", "loops", "loops.db");
1784
- return existsSync8(join8(resolved, "loops.db")) ? join8(resolved, "loops.db") : legacy;
1807
+ const legacy = join9(process.env["HOME"] || process.env["USERPROFILE"] || homedir8(), ".hasna", "loops", "loops.db");
1808
+ return existsSync8(join9(resolved, "loops.db")) ? join9(resolved, "loops.db") : legacy;
1785
1809
  }
1786
1810
  function loopsDbPath() {
1787
1811
  return process.env["HASNA_ECONOMY_LOOPS_DB_PATH"] ?? defaultLoopsDbPath();
@@ -1965,33 +1989,6 @@ async function ingestLoops(db, verbose = false) {
1965
1989
 
1966
1990
  // src/ingest/claude-quota.ts
1967
1991
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
1968
-
1969
- // src/lib/paths.ts
1970
- import { homedir as homedir9 } from "os";
1971
- import { join as join9 } from "path";
1972
- function getHomeDir() {
1973
- return process.env["USERPROFILE"] ?? process.env["HOME"] ?? homedir9();
1974
- }
1975
- function agentPaths() {
1976
- const home = getHomeDir();
1977
- return {
1978
- claudeProjects: join9(home, ".claude", "projects"),
1979
- claudeCredentials: join9(home, ".claude", ".credentials.json"),
1980
- takumiProjects: join9(home, ".takumi", "projects"),
1981
- codexDir: join9(home, ".codex"),
1982
- codexDb: join9(home, ".codex", "state_5.sqlite"),
1983
- codexAuth: join9(home, ".codex", "auth.json"),
1984
- codexConfig: join9(home, ".codex", "config.toml"),
1985
- geminiTmp: join9(home, ".gemini", "tmp"),
1986
- geminiHistory: join9(home, ".gemini", "history"),
1987
- opencodeMessages: join9(home, ".local", "share", "opencode", "storage", "message"),
1988
- piSessions: join9(home, ".pi", "agent", "sessions"),
1989
- hermesDir: join9(home, ".hermes"),
1990
- hermesDb: join9(home, ".hermes", "state.db")
1991
- };
1992
- }
1993
-
1994
- // src/ingest/claude-quota.ts
1995
1992
  var USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
1996
1993
  var OAUTH_BETA = "oauth-2025-04-20";
1997
1994
  function readClaudeToken() {
@@ -4,7 +4,7 @@ import {
4
4
  } from "./index-w3bvv0ns.js";
5
5
  import {
6
6
  getStore
7
- } from "./index-ct3zdefz.js";
7
+ } from "./index-z9psed59.js";
8
8
  import {
9
9
  formatReportedUsd,
10
10
  formatSummaryCoverage,
@@ -20,7 +20,7 @@ import {
20
20
  // package.json
21
21
  var package_default = {
22
22
  name: "@hasna/economy",
23
- version: "0.5.4",
23
+ version: "0.5.5",
24
24
  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",
25
25
  repository: {
26
26
  type: "git",
@@ -14,7 +14,7 @@ import {
14
14
  querySavingsSummary,
15
15
  requireCurrentBillingDiffSummary,
16
16
  requireCurrentSavingsReport
17
- } from "./index-n1wwqxfe.js";
17
+ } from "./index-pnnqdv3r.js";
18
18
  import {
19
19
  deleteBudget,
20
20
  deleteGoal,
@@ -5,7 +5,7 @@ import {
5
5
  } from "./index-w3bvv0ns.js";
6
6
  import {
7
7
  syncAll
8
- } from "./index-9arv0b1j.js";
8
+ } from "./index-61c0vz9p.js";
9
9
  import {
10
10
  buildBrief,
11
11
  packageMetadata,
@@ -16,7 +16,7 @@ import {
16
16
  queryProjectDetail,
17
17
  queryRangeStats,
18
18
  querySavingsSummary
19
- } from "./index-n1wwqxfe.js";
19
+ } from "./index-pnnqdv3r.js";
20
20
  import {
21
21
  AGENTS,
22
22
  INGEST_SCHEMA_SQL,
@@ -6,10 +6,10 @@ import {
6
6
  printStatusLine,
7
7
  printWaybarJson,
8
8
  runTui
9
- } from "./index-nheq2nrz.js";
9
+ } from "./index-7k1xt8mj.js";
10
10
  import"./index-w3bvv0ns.js";
11
- import"./index-ct3zdefz.js";
12
- import"./index-n1wwqxfe.js";
11
+ import"./index-z9psed59.js";
12
+ import"./index-pnnqdv3r.js";
13
13
  import"./index-f5jv6q5q.js";
14
14
  import"./index-p35cyhc4.js";
15
15
  export {
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  agentPaths,
4
4
  syncAll
5
- } from "./index-9arv0b1j.js";
5
+ } from "./index-61c0vz9p.js";
6
6
  import {
7
7
  getStore,
8
8
  isCloudStore
9
- } from "./index-ct3zdefz.js";
10
- import"./index-n1wwqxfe.js";
9
+ } from "./index-z9psed59.js";
10
+ import"./index-pnnqdv3r.js";
11
11
  import {
12
12
  formatSummaryValue
13
13
  } from "./index-f5jv6q5q.js";
package/dist/cli/index.js CHANGED
@@ -8,22 +8,22 @@ import {
8
8
  import {
9
9
  buildStatusLine,
10
10
  gatherStatusData
11
- } from "../chunks/index-nheq2nrz.js";
11
+ } from "../chunks/index-7k1xt8mj.js";
12
12
  import"../chunks/index-w3bvv0ns.js";
13
13
  import {
14
14
  agentPaths,
15
15
  syncAll
16
- } from "../chunks/index-9arv0b1j.js";
16
+ } from "../chunks/index-61c0vz9p.js";
17
17
  import {
18
18
  getStore,
19
19
  isCloudStore
20
- } from "../chunks/index-ct3zdefz.js";
20
+ } from "../chunks/index-z9psed59.js";
21
21
  import {
22
22
  billingDriftCheck,
23
23
  economyCloudStorage,
24
24
  economyTransportReport,
25
25
  packageMetadata
26
- } from "../chunks/index-n1wwqxfe.js";
26
+ } from "../chunks/index-pnnqdv3r.js";
27
27
  import {
28
28
  AGENTS,
29
29
  MAX_INGEST_BYTES,
@@ -1357,23 +1357,23 @@ function registerExtendedCommands(program) {
1357
1357
  console.log();
1358
1358
  });
1359
1359
  program.command("tui").description("Terminal status dashboard (Linux/SSH friendly)").option("--watch", "Live refresh").option("--interval <seconds>", "Refresh interval", "30").action(async (opts) => {
1360
- const { runTui } = await import("../chunks/tui-a1tvcw2j.js");
1360
+ const { runTui } = await import("../chunks/tui-2yea642b.js");
1361
1361
  await runTui({
1362
1362
  watch: Boolean(opts.watch),
1363
1363
  interval: Number(opts.interval ?? 30)
1364
1364
  });
1365
1365
  });
1366
1366
  program.command("waybar").description("Print waybar-compatible JSON status line").action(async () => {
1367
- const { printWaybarJson } = await import("../chunks/tui-a1tvcw2j.js");
1367
+ const { printWaybarJson } = await import("../chunks/tui-2yea642b.js");
1368
1368
  await printWaybarJson();
1369
1369
  });
1370
1370
  const barCmd = program.command("bar").description("Status bar helpers (Linux)");
1371
1371
  barCmd.command("tui").description("Alias for economy tui").option("--watch", "Live refresh").action(async (opts) => {
1372
- const { runTui } = await import("../chunks/tui-a1tvcw2j.js");
1372
+ const { runTui } = await import("../chunks/tui-2yea642b.js");
1373
1373
  await runTui({ watch: Boolean(opts.watch) });
1374
1374
  });
1375
1375
  barCmd.command("waybar").description("Alias for economy waybar").action(async () => {
1376
- const { printWaybarJson } = await import("../chunks/tui-a1tvcw2j.js");
1376
+ const { printWaybarJson } = await import("../chunks/tui-2yea642b.js");
1377
1377
  await printWaybarJson();
1378
1378
  });
1379
1379
  program.command("estimate").description("Estimate cost for token counts").requiredOption("--model <model>", "Model name").option("--input <n>", "Input tokens", "0").option("--output <n>", "Output tokens", "0").action(async (opts) => {
@@ -3198,7 +3198,7 @@ program.command("accounts [period]").description("List account usage by email ad
3198
3198
  console.log();
3199
3199
  });
3200
3200
  program.command("watch").description("Live stream of incoming costs").option("--interval <seconds>", "Poll interval in seconds", "10").option("--daemon", "Watch agent data directories and sync on change").option("--agent <agent>", `Filter by agent (${AGENTS.join("|")})`).option("--notify <amount>", "Fire macOS notification when cumulative cost crosses this USD threshold").action(async (opts) => {
3201
- const { watchCosts } = await import("../chunks/watch-rvd3dn6r.js");
3201
+ const { watchCosts } = await import("../chunks/watch-811vncjz.js");
3202
3202
  await watchCosts({
3203
3203
  interval: parsePositiveCliInteger(opts.interval ?? "10", "--interval"),
3204
3204
  daemon: Boolean(opts.daemon),
@@ -3434,7 +3434,7 @@ pricingCmd.command("remove <model>").description("Remove pricing for a model").a
3434
3434
  });
3435
3435
  program.command("serve").description("Start the REST API server").option("-p, --port <port>", "Port", "3456").action(async (opts) => {
3436
3436
  const port = parseCliPort(opts.port ?? "3456", "--port");
3437
- const { startServer } = await import("../chunks/serve-ra46ms69.js");
3437
+ const { startServer } = await import("../chunks/serve-zp5a3qzw.js");
3438
3438
  startServer(port);
3439
3439
  });
3440
3440
  program.command("mcp").description("Show MCP server install commands").option("--claude", "Install into Claude Code").option("--codex", "Install into Codex").option("--gemini", "Install into Gemini CLI").option("--all", "Install into all agents").action(async (opts) => {
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import { randomUUID } from "crypto";
62
62
  // package.json
63
63
  var package_default = {
64
64
  name: "@hasna/economy",
65
- version: "0.5.4",
65
+ version: "0.5.5",
66
66
  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",
67
67
  repository: {
68
68
  type: "git",
@@ -1 +1 @@
1
- {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAWxE,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAiE9D,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,KAAK,EAChB,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAoJhE"}
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAWxE,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAsE9D,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,KAAK,EAChB,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAoJhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/ingest/codex.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAyBxE,UAAU,eAAe;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,eAAe,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAuDD,iBAAS,cAAc,CAAC,UAAU,SAAoB,GAAG,MAAM,CAS9D;AAkCD;;uEAEuE;AACvE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CA0CpG;AAED,MAAM,WAAW,gBAAgB;IAAG,IAAI,EAAE,qCAAqC,GAAG,0BAA0B,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AACrL,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC,CAmG7I;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/ingest/codex.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAsBxE,UAAU,eAAe;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,eAAe,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAuDD,iBAAS,cAAc,CAAC,UAAU,SAAoB,GAAG,MAAM,CAS9D;AAkCD;;uEAEuE;AACvE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CA0CpG;AAED,MAAM,WAAW,gBAAgB;IAAG,IAAI,EAAE,qCAAqC,GAAG,0BAA0B,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AACrL,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC,CAmG7I;AAED,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAIA,sEAAsE;AACtE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,wBAAgB,UAAU;;;;;;;;;;;;;;EAiBzB;AAED,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAIA,sEAAsE;AACtE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,wBAAgB,UAAU;;;;;;;;;;;;;;EAmBzB;AAED,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C"}