@hasna/economy 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -109,8 +109,17 @@ var init_pricing = __esm(() => {
109
109
  // src/db/database.ts
110
110
  import { SqliteAdapter as Database } from "@hasna/cloud";
111
111
  import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
112
+ import { hostname } from "os";
112
113
  import { homedir } from "os";
113
114
  import { join } from "path";
115
+ function getMachineId() {
116
+ if (process.env["ECONOMY_MACHINE_ID"])
117
+ return process.env["ECONOMY_MACHINE_ID"];
118
+ const h = hostname().toLowerCase();
119
+ if (h.startsWith("spark") || h.startsWith("apple"))
120
+ return h.split(".")[0];
121
+ return h.split(".")[0];
122
+ }
114
123
  function getDataDir() {
115
124
  const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
116
125
  const newDir = join(home, ".hasna", "economy");
@@ -143,6 +152,7 @@ function openDatabase(dbPath, skipSeed = false) {
143
152
  }
144
153
  const db = new Database(path);
145
154
  db.exec("PRAGMA journal_mode = WAL");
155
+ db.exec("PRAGMA busy_timeout = 5000");
146
156
  db.exec("PRAGMA foreign_keys = ON");
147
157
  initSchema(db);
148
158
  if (!skipSeed) {
@@ -164,7 +174,8 @@ function initSchema(db) {
164
174
  cost_usd REAL NOT NULL DEFAULT 0,
165
175
  duration_ms INTEGER DEFAULT 0,
166
176
  timestamp TEXT NOT NULL,
167
- source_request_id TEXT
177
+ source_request_id TEXT,
178
+ machine_id TEXT DEFAULT ''
168
179
  );
169
180
 
170
181
  CREATE TABLE IF NOT EXISTS sessions (
@@ -176,7 +187,8 @@ function initSchema(db) {
176
187
  ended_at TEXT,
177
188
  total_cost_usd REAL DEFAULT 0,
178
189
  total_tokens INTEGER DEFAULT 0,
179
- request_count INTEGER DEFAULT 0
190
+ request_count INTEGER DEFAULT 0,
191
+ machine_id TEXT DEFAULT ''
180
192
  );
181
193
 
182
194
  CREATE TABLE IF NOT EXISTS projects (
@@ -242,6 +254,15 @@ function initSchema(db) {
242
254
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
243
255
  );
244
256
  `);
257
+ const cols = db.prepare(`PRAGMA table_info(requests)`).all();
258
+ if (!cols.some((c) => c.name === "machine_id")) {
259
+ db.exec(`ALTER TABLE requests ADD COLUMN machine_id TEXT DEFAULT ''`);
260
+ db.exec(`ALTER TABLE sessions ADD COLUMN machine_id TEXT DEFAULT ''`);
261
+ }
262
+ db.exec(`
263
+ CREATE INDEX IF NOT EXISTS idx_requests_machine ON requests(machine_id);
264
+ CREATE INDEX IF NOT EXISTS idx_sessions_machine ON sessions(machine_id);
265
+ `);
245
266
  }
246
267
  function periodWhere(period) {
247
268
  switch (period) {
@@ -280,17 +301,17 @@ function upsertRequest(db, req) {
280
301
  INSERT OR REPLACE INTO requests
281
302
  (id, agent, session_id, model, input_tokens, output_tokens,
282
303
  cache_read_tokens, cache_create_tokens, cost_usd, duration_ms,
283
- timestamp, source_request_id)
284
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
285
- `).run(req.id, req.agent, req.session_id, req.model, req.input_tokens, req.output_tokens, req.cache_read_tokens, req.cache_create_tokens, req.cost_usd, req.duration_ms, req.timestamp, req.source_request_id);
304
+ timestamp, source_request_id, machine_id)
305
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
306
+ `).run(req.id, req.agent, req.session_id, req.model, req.input_tokens, req.output_tokens, req.cache_read_tokens, req.cache_create_tokens, req.cost_usd, req.duration_ms, req.timestamp, req.source_request_id, req.machine_id ?? "");
286
307
  }
287
308
  function upsertSession(db, session) {
288
309
  db.prepare(`
289
310
  INSERT OR REPLACE INTO sessions
290
311
  (id, agent, project_path, project_name, started_at, ended_at,
291
- total_cost_usd, total_tokens, request_count)
292
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
293
- `).run(session.id, session.agent, session.project_path, session.project_name, session.started_at, session.ended_at ?? null, session.total_cost_usd, session.total_tokens, session.request_count);
312
+ total_cost_usd, total_tokens, request_count, machine_id)
313
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
314
+ `).run(session.id, session.agent, session.project_path, session.project_name, session.started_at, session.ended_at ?? null, session.total_cost_usd, session.total_tokens, session.request_count, session.machine_id ?? "");
294
315
  }
295
316
  function rollupSession(db, sessionId) {
296
317
  db.prepare(`
@@ -320,6 +341,10 @@ function querySessions(db, filter = {}) {
320
341
  conditions.push("started_at >= ?");
321
342
  params.push(filter.since);
322
343
  }
344
+ if (filter.machine) {
345
+ conditions.push("machine_id = ?");
346
+ params.push(filter.machine);
347
+ }
323
348
  if (filter.search) {
324
349
  const q = `%${filter.search}%`;
325
350
  conditions.push("(project_name LIKE ? OR agent LIKE ? OR id LIKE ?)");
@@ -338,24 +363,25 @@ function queryTopSessions(db, n = 10, agent) {
338
363
  }
339
364
  return db.prepare(`SELECT * FROM sessions ORDER BY total_cost_usd DESC LIMIT ?`).all(n);
340
365
  }
341
- function querySummary(db, period) {
366
+ function querySummary(db, period, machine) {
342
367
  const rWhere = periodWhere(period);
343
368
  const sWhere = sessionPeriodWhere(period);
369
+ const machineClause = machine ? ` AND machine_id = '${machine.replace(/'/g, "''")}'` : "";
344
370
  const r = db.prepare(`
345
371
  SELECT COALESCE(SUM(cost_usd), 0) as total_usd,
346
372
  COUNT(*) as requests,
347
373
  COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as tokens
348
- FROM requests WHERE ${rWhere}
374
+ FROM requests WHERE ${rWhere}${machineClause}
349
375
  `).get();
350
376
  const codexTotals = db.prepare(`
351
377
  SELECT COALESCE(SUM(total_cost_usd), 0) as cost_usd,
352
378
  COALESCE(SUM(total_tokens), 0) as tokens,
353
379
  COUNT(*) as sessions
354
380
  FROM sessions
355
- WHERE ${sWhere}
381
+ WHERE ${sWhere}${machineClause}
356
382
  AND id NOT IN (SELECT DISTINCT session_id FROM requests)
357
383
  `).get();
358
- const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}`).get();
384
+ const sessionCount = db.prepare(`SELECT COUNT(*) as sessions FROM sessions WHERE ${sWhere}${machineClause}`).get();
359
385
  return {
360
386
  total_usd: r.total_usd + codexTotals.cost_usd,
361
387
  requests: r.requests,
@@ -500,6 +526,20 @@ function getIngestState(db, source, key) {
500
526
  function setIngestState(db, source, key, value) {
501
527
  db.prepare(`INSERT OR REPLACE INTO ingest_state (source, key, value) VALUES (?, ?, ?)`).run(source, key, value);
502
528
  }
529
+ function listMachines(db) {
530
+ return db.prepare(`
531
+ SELECT
532
+ s.machine_id,
533
+ COUNT(DISTINCT s.id) as sessions,
534
+ COALESCE((SELECT COUNT(*) FROM requests r WHERE r.machine_id = s.machine_id), 0) as requests,
535
+ COALESCE(SUM(s.total_cost_usd), 0) as total_cost_usd,
536
+ MAX(s.started_at) as last_active
537
+ FROM sessions s
538
+ WHERE s.machine_id != ''
539
+ GROUP BY s.machine_id
540
+ ORDER BY total_cost_usd DESC
541
+ `).all();
542
+ }
503
543
  function upsertModelPricing(db, p) {
504
544
  db.prepare(`
505
545
  INSERT OR REPLACE INTO model_pricing
@@ -546,7 +586,8 @@ import { join as join2, basename } from "path";
546
586
  function autoDetectProject(cwd, projects) {
547
587
  return projects.find((p) => cwd === p.path || cwd.startsWith(p.path + "/"));
548
588
  }
549
- var PROJECTS_DIR = join2(homedir2(), ".claude", "projects");
589
+ var CLAUDE_PROJECTS_DIR = join2(homedir2(), ".claude", "projects");
590
+ var TAKUMI_PROJECTS_DIR = join2(homedir2(), ".takumi", "projects");
550
591
  function dirNameToPath(dirName) {
551
592
  return dirName.replace(/^-/, "/").replace(/-/g, "/").replace(/\/\//g, "/-");
552
593
  }
@@ -566,29 +607,36 @@ function collectJsonlFiles(projectDir) {
566
607
  return files;
567
608
  }
568
609
  async function ingestClaude(db, verbose = false, _telemetryDir) {
569
- if (!existsSync2(PROJECTS_DIR)) {
610
+ return ingestJsonlProjects(db, CLAUDE_PROJECTS_DIR, "claude", verbose);
611
+ }
612
+ async function ingestTakumi(db, verbose = false) {
613
+ return ingestJsonlProjects(db, TAKUMI_PROJECTS_DIR, "takumi", verbose);
614
+ }
615
+ async function ingestJsonlProjects(db, projectsDir, agentName, verbose = false) {
616
+ if (!existsSync2(projectsDir)) {
570
617
  if (verbose)
571
- console.log("Claude projects dir not found:", PROJECTS_DIR);
618
+ console.log(`${agentName} projects dir not found:`, projectsDir);
572
619
  return { files: 0, requests: 0, sessions: 0 };
573
620
  }
621
+ const machineId = getMachineId();
574
622
  let totalFiles = 0;
575
623
  let totalRequests = 0;
576
624
  const touchedSessions = new Set;
577
625
  const registeredProjects = db.prepare(`SELECT path, name FROM projects ORDER BY LENGTH(path) DESC`).all();
578
- const projectDirs = readdirSync2(PROJECTS_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
626
+ const projectDirs = readdirSync2(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
579
627
  for (const projectDirEntry of projectDirs) {
580
- const projectDirPath = join2(PROJECTS_DIR, projectDirEntry.name);
628
+ const projectDirPath = join2(projectsDir, projectDirEntry.name);
581
629
  const projectPath = dirNameToPath(projectDirEntry.name);
582
630
  const jsonlFiles = collectJsonlFiles(projectDirPath);
583
631
  for (const filePath of jsonlFiles) {
584
- const stateKey = filePath.replace(PROJECTS_DIR, "");
632
+ const stateKey = filePath.replace(projectsDir, "");
585
633
  let fileMtime = "0";
586
634
  try {
587
635
  fileMtime = statSync2(filePath).mtimeMs.toString();
588
636
  } catch {
589
637
  continue;
590
638
  }
591
- const processed = getIngestState(db, "claude", stateKey);
639
+ const processed = getIngestState(db, agentName, stateKey);
592
640
  if (processed === fileMtime)
593
641
  continue;
594
642
  let lines;
@@ -629,10 +677,10 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
629
677
  if (inputTokens + outputTokens + cacheWriteTokens === 0)
630
678
  continue;
631
679
  const costUsd = computeCostFromDb(db, model, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens);
632
- const reqId = `claude-${sessionId}-${timestamp}`;
680
+ const reqId = `${agentName}-${sessionId}-${timestamp}`;
633
681
  upsertRequest(db, {
634
682
  id: reqId,
635
- agent: "claude",
683
+ agent: agentName,
636
684
  session_id: sessionId,
637
685
  model,
638
686
  input_tokens: inputTokens,
@@ -642,7 +690,8 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
642
690
  cost_usd: costUsd,
643
691
  duration_ms: 0,
644
692
  timestamp,
645
- source_request_id: reqId
693
+ source_request_id: reqId,
694
+ machine_id: machineId
646
695
  });
647
696
  if (!touchedSessions.has(sessionId)) {
648
697
  const existing = db.prepare(`SELECT id FROM sessions WHERE id = ?`).get(sessionId);
@@ -651,14 +700,15 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
651
700
  const detectedProject = autoDetectProject(effectiveCwd, registeredProjects);
652
701
  const session = {
653
702
  id: sessionId,
654
- agent: "claude",
703
+ agent: agentName,
655
704
  project_path: detectedProject ? detectedProject.path : effectiveCwd,
656
705
  project_name: detectedProject ? detectedProject.name : "",
657
706
  started_at: timestamp,
658
707
  ended_at: null,
659
708
  total_cost_usd: 0,
660
709
  total_tokens: 0,
661
- request_count: 0
710
+ request_count: 0,
711
+ machine_id: machineId
662
712
  };
663
713
  upsertSession(db, session);
664
714
  }
@@ -666,7 +716,7 @@ async function ingestClaude(db, verbose = false, _telemetryDir) {
666
716
  }
667
717
  totalRequests++;
668
718
  }
669
- setIngestState(db, "claude", stateKey, fileMtime);
719
+ setIngestState(db, agentName, stateKey, fileMtime);
670
720
  totalFiles++;
671
721
  }
672
722
  }
@@ -690,6 +740,7 @@ async function ingestCodex(db, verbose = false) {
690
740
  console.log("Codex DB not found:", CODEX_DB_PATH);
691
741
  return { sessions: 0 };
692
742
  }
743
+ const machineId = getMachineId();
693
744
  let codexDb = null;
694
745
  let ingested = 0;
695
746
  try {
@@ -714,7 +765,8 @@ async function ingestCodex(db, verbose = false) {
714
765
  ended_at: endedAt,
715
766
  total_cost_usd: costUsd,
716
767
  total_tokens: thread.tokens_used,
717
- request_count: 1
768
+ request_count: 1,
769
+ machine_id: machineId
718
770
  });
719
771
  setIngestState(db, "codex", stateKey, "done");
720
772
  ingested++;
@@ -739,6 +791,7 @@ async function ingestGemini(db, verbose) {
739
791
  console.log("Gemini tmp dir not found:", GEMINI_TMP_DIR);
740
792
  return { sessions: 0 };
741
793
  }
794
+ const machineId = getMachineId();
742
795
  let totalSessions = 0;
743
796
  const touchedSessions = new Set;
744
797
  let projectHashDirs = [];
@@ -789,7 +842,8 @@ async function ingestGemini(db, verbose) {
789
842
  ended_at: chatData.lastUpdated ?? null,
790
843
  total_cost_usd: 0,
791
844
  total_tokens: 0,
792
- request_count: 0
845
+ request_count: 0,
846
+ machine_id: machineId
793
847
  };
794
848
  upsertSession(db, session);
795
849
  touchedSessions.add(sessionId);
@@ -854,7 +908,11 @@ function createHandler(db) {
854
908
  return ok({ status: "ok", ts: new Date().toISOString() });
855
909
  if (path === "/api/summary" && method === "GET") {
856
910
  const period = url.searchParams.get("period") ?? "today";
857
- return ok(querySummary(db, period));
911
+ const machine = url.searchParams.get("machine") ?? undefined;
912
+ return ok(querySummary(db, period, machine));
913
+ }
914
+ if (path === "/api/machines" && method === "GET") {
915
+ return ok(listMachines(db), { current_machine: getMachineId() });
858
916
  }
859
917
  if (path === "/api/daily" && method === "GET") {
860
918
  const days = Number(url.searchParams.get("days") ?? 30);
@@ -864,6 +922,7 @@ function createHandler(db) {
864
922
  const agent = url.searchParams.get("agent");
865
923
  const project = url.searchParams.get("project") ?? undefined;
866
924
  const search = url.searchParams.get("search") ?? undefined;
925
+ const machine = url.searchParams.get("machine") ?? undefined;
867
926
  const limit = Number(url.searchParams.get("limit") ?? 50);
868
927
  const offset = Number(url.searchParams.get("offset") ?? 0);
869
928
  const since = url.searchParams.get("since") ?? undefined;
@@ -873,6 +932,7 @@ function createHandler(db) {
873
932
  agent: agent ?? undefined,
874
933
  project,
875
934
  search,
935
+ machine,
876
936
  limit,
877
937
  offset,
878
938
  since
@@ -965,6 +1025,8 @@ function createHandler(db) {
965
1025
  const results = {};
966
1026
  if (sources === "all" || sources === "claude")
967
1027
  results["claude"] = await ingestClaude(db);
1028
+ if (sources === "all" || sources === "takumi")
1029
+ results["takumi"] = await ingestTakumi(db);
968
1030
  if (sources === "all" || sources === "codex")
969
1031
  results["codex"] = await ingestCodex(db);
970
1032
  if (sources === "all" || sources === "gemini")
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA2D7D,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAwL/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,GAAG,IAAI,CAuC7C"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAA;AA4D7D,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAiM/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,GAAG,IAAI,CAuC7C"}
@@ -1,4 +1,4 @@
1
- export type Agent = 'claude' | 'codex' | 'gemini';
1
+ export type Agent = 'claude' | 'codex' | 'gemini' | 'takumi';
2
2
  export type Period = 'today' | 'yesterday' | 'week' | 'month' | 'year' | 'all';
3
3
  export interface EconomyRequest {
4
4
  id: string;
@@ -13,6 +13,7 @@ export interface EconomyRequest {
13
13
  duration_ms: number;
14
14
  timestamp: string;
15
15
  source_request_id: string;
16
+ machine_id?: string;
16
17
  }
17
18
  export interface EconomySession {
18
19
  id: string;
@@ -24,6 +25,7 @@ export interface EconomySession {
24
25
  total_cost_usd: number;
25
26
  total_tokens: number;
26
27
  request_count: number;
28
+ machine_id?: string;
27
29
  }
28
30
  export interface EconomyProject {
29
31
  id: string;
@@ -97,5 +99,6 @@ export interface SessionFilter {
97
99
  offset?: number;
98
100
  since?: string;
99
101
  search?: string;
102
+ machine?: string;
100
103
  }
101
104
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/economy",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, and Gemini",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",