@hasna/economy 0.2.22 → 0.2.24

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.
@@ -1057,23 +1057,20 @@ function labelForPath(projectPath, projectName) {
1057
1057
  return segments[segments.length - 1] ?? projectPath;
1058
1058
  }
1059
1059
  function queryProjectBreakdown(db, period = "all") {
1060
- const where = sessionPeriodWhere(period);
1060
+ const requestWhere = requestPeriodWhere(period);
1061
+ const sessionWhere = sessionPeriodWhere(period);
1061
1062
  const sessions = db.prepare(`
1062
1063
  SELECT id, project_path, project_name, total_cost_usd, started_at
1063
1064
  FROM sessions
1064
- WHERE ${where}
1065
- AND (project_path != '' OR project_name != '')
1065
+ WHERE project_path != '' OR project_name != ''
1066
1066
  `).all();
1067
1067
  const groups = new Map;
1068
1068
  for (const s of sessions) {
1069
1069
  const label = labelForPath(s.project_path, s.project_name);
1070
1070
  if (!label)
1071
1071
  continue;
1072
- const g = groups.get(label) ?? { sessionIds: [], samplePath: s.project_path, totalCost: 0, lastActive: "" };
1072
+ const g = groups.get(label) ?? { sessionIds: [], samplePath: s.project_path };
1073
1073
  g.sessionIds.push(s.id);
1074
- g.totalCost += s.total_cost_usd || 0;
1075
- if (!g.lastActive || s.started_at > g.lastActive)
1076
- g.lastActive = s.started_at;
1077
1074
  if (!g.samplePath)
1078
1075
  g.samplePath = s.project_path;
1079
1076
  groups.set(label, g);
@@ -1083,32 +1080,52 @@ function queryProjectBreakdown(db, period = "all") {
1083
1080
  const placeholders = g.sessionIds.map(() => "?").join(",");
1084
1081
  const reqStats = placeholders.length ? db.prepare(`
1085
1082
  SELECT
1083
+ COUNT(DISTINCT session_id) as sessions,
1086
1084
  COUNT(*) as requests,
1087
1085
  COALESCE(SUM(cost_usd), 0) as cost_usd,
1088
- COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as total_tokens
1089
- FROM requests WHERE session_id IN (${placeholders})
1090
- `).get(...g.sessionIds) : { requests: 0, cost_usd: 0, total_tokens: 0 };
1086
+ COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as total_tokens,
1087
+ MAX(timestamp) as last_active
1088
+ FROM requests
1089
+ WHERE session_id IN (${placeholders})
1090
+ AND ${requestWhere}
1091
+ `).get(...g.sessionIds) : { sessions: 0, requests: 0, cost_usd: 0, total_tokens: 0, last_active: null };
1092
+ const sessionOnlyStats = placeholders.length ? db.prepare(`
1093
+ SELECT
1094
+ COUNT(*) as sessions,
1095
+ COALESCE(SUM(request_count), 0) as requests,
1096
+ COALESCE(SUM(total_tokens), 0) as total_tokens,
1097
+ COALESCE(SUM(total_cost_usd), 0) as cost_usd,
1098
+ MAX(started_at) as last_active
1099
+ FROM sessions
1100
+ WHERE id IN (${placeholders})
1101
+ AND ${sessionWhere}
1102
+ AND id NOT IN (SELECT DISTINCT session_id FROM requests)
1103
+ `).get(...g.sessionIds) : { sessions: 0, requests: 0, total_tokens: 0, cost_usd: 0, last_active: null };
1104
+ const totalSessions = reqStats.sessions + sessionOnlyStats.sessions;
1105
+ if (totalSessions === 0)
1106
+ continue;
1107
+ const lastActive = [reqStats.last_active, sessionOnlyStats.last_active].filter(Boolean).sort().at(-1) ?? "";
1091
1108
  result.push({
1092
1109
  project_path: g.samplePath,
1093
1110
  project_name: label,
1094
- sessions: g.sessionIds.length,
1095
- requests: reqStats.requests,
1096
- total_tokens: reqStats.total_tokens,
1097
- cost_usd: reqStats.cost_usd > 0 ? reqStats.cost_usd : g.totalCost,
1098
- last_active: g.lastActive
1111
+ sessions: totalSessions,
1112
+ requests: reqStats.requests + sessionOnlyStats.requests,
1113
+ total_tokens: reqStats.total_tokens + sessionOnlyStats.total_tokens,
1114
+ cost_usd: reqStats.cost_usd + sessionOnlyStats.cost_usd,
1115
+ last_active: lastActive
1099
1116
  });
1100
1117
  }
1101
1118
  result.sort((a, b) => b.cost_usd - a.cost_usd);
1102
1119
  return result;
1103
1120
  }
1104
1121
  function queryAccountBreakdown(db, period = "all") {
1105
- const sWhere = sessionPeriodWhere(period);
1122
+ const requestWhere = requestPeriodWhere(period);
1123
+ const sessionWhere = sessionPeriodWhere(period);
1106
1124
  const sessions = db.prepare(`
1107
1125
  SELECT id, account_key, account_tool, account_name, account_email, account_source,
1108
1126
  total_cost_usd, total_tokens, request_count, started_at
1109
1127
  FROM sessions
1110
- WHERE ${sWhere}
1111
- AND (account_key != '' OR account_tool != '' OR account_name != '' OR account_email != '')
1128
+ WHERE account_key != '' OR account_tool != '' OR account_name != '' OR account_email != ''
1112
1129
  `).all();
1113
1130
  const groups = new Map;
1114
1131
  for (const session of sessions) {
@@ -1120,18 +1137,9 @@ function queryAccountBreakdown(db, period = "all") {
1120
1137
  account_tool: session.account_tool,
1121
1138
  account_name: session.account_name,
1122
1139
  account_email: session.account_email || null,
1123
- account_source: session.account_source || "unknown",
1124
- totalCost: 0,
1125
- totalTokens: 0,
1126
- requests: 0,
1127
- lastActive: ""
1140
+ account_source: session.account_source || "unknown"
1128
1141
  };
1129
1142
  group.sessionIds.push(session.id);
1130
- group.totalCost += session.total_cost_usd || 0;
1131
- group.totalTokens += session.total_tokens || 0;
1132
- group.requests += session.request_count || 0;
1133
- if (!group.lastActive || session.started_at > group.lastActive)
1134
- group.lastActive = session.started_at;
1135
1143
  groups.set(key, group);
1136
1144
  }
1137
1145
  const result = [];
@@ -1139,36 +1147,57 @@ function queryAccountBreakdown(db, period = "all") {
1139
1147
  const placeholders = group.sessionIds.map(() => "?").join(",");
1140
1148
  const reqStats = placeholders ? db.prepare(`
1141
1149
  SELECT
1150
+ COUNT(DISTINCT session_id) as sessions,
1142
1151
  COUNT(*) as requests,
1143
1152
  COALESCE(SUM(cost_usd), 0) as cost_usd,
1144
1153
  COALESCE(SUM(input_tokens + output_tokens + cache_read_tokens + cache_create_tokens), 0) as total_tokens,
1145
1154
  COALESCE(SUM(CASE WHEN cost_basis = 'metered_api' THEN cost_usd ELSE 0 END), 0) as metered_api_usd,
1146
1155
  COALESCE(SUM(CASE WHEN cost_basis = 'subscription_included' THEN cost_usd ELSE 0 END), 0) as subscription_included_usd,
1147
1156
  COALESCE(SUM(CASE WHEN COALESCE(cost_basis, 'estimated') = 'estimated' THEN cost_usd ELSE 0 END), 0) as estimated_usd,
1148
- COALESCE(SUM(CASE WHEN cost_basis = 'unknown' THEN cost_usd ELSE 0 END), 0) as unknown_usd
1149
- FROM requests WHERE session_id IN (${placeholders})
1157
+ COALESCE(SUM(CASE WHEN cost_basis = 'unknown' THEN cost_usd ELSE 0 END), 0) as unknown_usd,
1158
+ MAX(timestamp) as last_active
1159
+ FROM requests
1160
+ WHERE session_id IN (${placeholders})
1161
+ AND ${requestWhere}
1150
1162
  `).get(...group.sessionIds) : {
1163
+ sessions: 0,
1151
1164
  requests: 0,
1152
1165
  cost_usd: 0,
1153
1166
  total_tokens: 0,
1154
1167
  metered_api_usd: 0,
1155
1168
  subscription_included_usd: 0,
1156
1169
  estimated_usd: 0,
1157
- unknown_usd: 0
1170
+ unknown_usd: 0,
1171
+ last_active: null
1158
1172
  };
1159
- const hasRequestCosts = reqStats.requests > 0;
1160
- const apiEquivalentUsd = hasRequestCosts ? reqStats.cost_usd : group.totalCost;
1161
- const estimatedUsd = hasRequestCosts ? reqStats.estimated_usd : group.totalCost;
1173
+ const sessionOnlyStats = placeholders ? db.prepare(`
1174
+ SELECT
1175
+ COUNT(*) as sessions,
1176
+ COALESCE(SUM(request_count), 0) as requests,
1177
+ COALESCE(SUM(total_tokens), 0) as total_tokens,
1178
+ COALESCE(SUM(total_cost_usd), 0) as cost_usd,
1179
+ MAX(started_at) as last_active
1180
+ FROM sessions
1181
+ WHERE id IN (${placeholders})
1182
+ AND ${sessionWhere}
1183
+ AND id NOT IN (SELECT DISTINCT session_id FROM requests)
1184
+ `).get(...group.sessionIds) : { sessions: 0, requests: 0, total_tokens: 0, cost_usd: 0, last_active: null };
1185
+ const sessionsTotal = reqStats.sessions + sessionOnlyStats.sessions;
1186
+ if (sessionsTotal === 0)
1187
+ continue;
1188
+ const apiEquivalentUsd = reqStats.cost_usd + sessionOnlyStats.cost_usd;
1189
+ const estimatedUsd = reqStats.estimated_usd + sessionOnlyStats.cost_usd;
1162
1190
  const billableUsd = reqStats.metered_api_usd;
1191
+ const lastActive = [reqStats.last_active, sessionOnlyStats.last_active].filter(Boolean).sort().at(-1) ?? "";
1163
1192
  result.push({
1164
1193
  account_key: key,
1165
1194
  account_tool: group.account_tool,
1166
1195
  account_name: group.account_name,
1167
1196
  account_email: group.account_email,
1168
1197
  account_source: group.account_source,
1169
- sessions: group.sessionIds.length,
1170
- requests: reqStats.requests || group.requests,
1171
- total_tokens: reqStats.total_tokens || group.totalTokens,
1198
+ sessions: sessionsTotal,
1199
+ requests: reqStats.requests + sessionOnlyStats.requests,
1200
+ total_tokens: reqStats.total_tokens + sessionOnlyStats.total_tokens,
1172
1201
  api_equivalent_usd: apiEquivalentUsd,
1173
1202
  billable_usd: billableUsd,
1174
1203
  metered_api_usd: reqStats.metered_api_usd,
@@ -1176,7 +1205,7 @@ function queryAccountBreakdown(db, period = "all") {
1176
1205
  estimated_usd: estimatedUsd,
1177
1206
  unknown_usd: reqStats.unknown_usd,
1178
1207
  cost_usd: apiEquivalentUsd,
1179
- last_active: group.lastActive
1208
+ last_active: lastActive
1180
1209
  });
1181
1210
  }
1182
1211
  result.sort((a, b) => b.cost_usd - a.cost_usd);
@@ -1364,6 +1393,12 @@ function upsertSubscription(db, sub) {
1364
1393
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1365
1394
  `).run(sub.id, sub.agent, sub.provider, sub.plan, sub.monthly_fee_usd, sub.included_usage_usd, sub.billing_cycle_start, sub.reset_policy, sub.active, sub.created_at, sub.updated_at);
1366
1395
  }
1396
+ function listSubscriptions(db) {
1397
+ return db.prepare(`SELECT * FROM subscriptions ORDER BY provider, plan`).all();
1398
+ }
1399
+ function deleteSubscription(db, id) {
1400
+ db.prepare(`DELETE FROM subscriptions WHERE id = ?`).run(id);
1401
+ }
1367
1402
  function upsertUsageSnapshot(db, snap) {
1368
1403
  const now = snap.updated_at ?? new Date().toISOString();
1369
1404
  const id = snap.id ?? `${snap.agent}-${snap.date}-${snap.metric}-${snap.machine_id}`;
@@ -2053,6 +2088,10 @@ function prorateMonthlyFee(monthlyFee, period) {
2053
2088
  return monthlyFee;
2054
2089
  }
2055
2090
  }
2091
+ function proratedIncludedConsumed(includedUsage, includedCap, period) {
2092
+ const cap = prorateMonthlyFee(includedCap, period);
2093
+ return cap > 0 ? Math.min(includedUsage, cap) : includedUsage;
2094
+ }
2056
2095
  function computeSavedUsd(apiEquivalent, onDemand, subscriptionFee) {
2057
2096
  return Math.max(0, apiEquivalent - onDemand - subscriptionFee);
2058
2097
  }
@@ -2080,24 +2119,74 @@ function querySavingsSummary(db, period, agent) {
2080
2119
  AND metric = 'on_demand_usd'
2081
2120
  `).get(...params);
2082
2121
  const subs = db.prepare(`
2083
- SELECT COALESCE(SUM(monthly_fee_usd), 0) as total
2122
+ SELECT
2123
+ COALESCE(SUM(monthly_fee_usd), 0) as fee,
2124
+ COALESCE(SUM(included_usage_usd), 0) as included
2084
2125
  FROM subscriptions
2085
- WHERE active = 1${agent ? " AND agent = ?" : ""}
2126
+ WHERE active = 1${agent ? " AND (agent = ? OR agent IS NULL)" : ""}
2086
2127
  `).get(...agent ? [agent] : []);
2087
- const subscriptionFee = prorateMonthlyFee(subs.total, period);
2128
+ const subscriptionFee = prorateMonthlyFee(subs.fee, period);
2088
2129
  const apiEquivalent = apiRow.total + includedRow.total;
2130
+ const includedConsumed = proratedIncludedConsumed(includedRow.total, subs.included, period);
2089
2131
  const onDemand = onDemandRow.total;
2090
2132
  const saved = computeSavedUsd(apiEquivalent, onDemand, subscriptionFee);
2091
2133
  const byAgent = {};
2092
2134
  if (!agent) {
2135
+ const onDemandByAgent = new Map;
2136
+ for (const row of db.prepare(`
2137
+ SELECT agent, COALESCE(SUM(value), 0) as total
2138
+ FROM usage_snapshots
2139
+ WHERE ${subWhere}
2140
+ AND metric = 'on_demand_usd'
2141
+ GROUP BY agent
2142
+ `).all()) {
2143
+ onDemandByAgent.set(row.agent, row.total);
2144
+ }
2145
+ const subscriptionByAgent = new Map;
2146
+ for (const row of db.prepare(`
2147
+ SELECT agent,
2148
+ COALESCE(SUM(monthly_fee_usd), 0) as fee,
2149
+ COALESCE(SUM(included_usage_usd), 0) as included
2150
+ FROM subscriptions
2151
+ WHERE active = 1 AND agent IS NOT NULL
2152
+ GROUP BY agent
2153
+ `).all()) {
2154
+ subscriptionByAgent.set(row.agent, row);
2155
+ }
2156
+ const globalSubs = db.prepare(`
2157
+ SELECT
2158
+ COALESCE(SUM(monthly_fee_usd), 0) as fee,
2159
+ COALESCE(SUM(included_usage_usd), 0) as included
2160
+ FROM subscriptions
2161
+ WHERE active = 1 AND agent IS NULL
2162
+ `).get();
2163
+ const rows = db.prepare(`
2164
+ SELECT agent,
2165
+ COALESCE(SUM(cost_usd), 0) as api_eq,
2166
+ COALESCE(SUM(CASE WHEN cost_basis = 'subscription_included' THEN cost_usd ELSE 0 END), 0) as included
2167
+ FROM requests WHERE ${where}
2168
+ GROUP BY agent
2169
+ `).all();
2170
+ const totalAgentApiEq = rows.reduce((sum, row) => sum + row.api_eq, 0);
2093
2171
  for (const row of db.prepare(`
2094
- SELECT agent, COALESCE(SUM(cost_usd), 0) as api_eq
2172
+ SELECT agent,
2173
+ COALESCE(SUM(cost_usd), 0) as api_eq,
2174
+ COALESCE(SUM(CASE WHEN cost_basis = 'subscription_included' THEN cost_usd ELSE 0 END), 0) as included
2095
2175
  FROM requests WHERE ${where}
2096
2176
  GROUP BY agent
2097
2177
  `).all()) {
2178
+ const agentSubs = subscriptionByAgent.get(row.agent) ?? { fee: 0, included: 0 };
2179
+ const globalShare = totalAgentApiEq > 0 ? row.api_eq / totalAgentApiEq : 0;
2180
+ const agentFee = prorateMonthlyFee(agentSubs.fee + globalSubs.fee * globalShare, period);
2181
+ const agentIncludedCap = agentSubs.included + globalSubs.included * globalShare;
2182
+ const agentIncludedConsumed = proratedIncludedConsumed(row.included, agentIncludedCap, period);
2183
+ const agentOnDemand = onDemandByAgent.get(row.agent) ?? 0;
2098
2184
  byAgent[row.agent] = {
2099
2185
  api_equivalent_usd: row.api_eq,
2100
- saved_usd: row.api_eq
2186
+ subscription_fee_usd: agentFee,
2187
+ included_consumed_usd: agentIncludedConsumed,
2188
+ on_demand_usd: agentOnDemand,
2189
+ saved_usd: computeSavedUsd(row.api_eq, agentOnDemand, agentFee)
2101
2190
  };
2102
2191
  }
2103
2192
  }
@@ -2105,7 +2194,7 @@ function querySavingsSummary(db, period, agent) {
2105
2194
  period,
2106
2195
  api_equivalent_usd: apiEquivalent,
2107
2196
  subscription_fee_usd: subscriptionFee,
2108
- included_consumed_usd: includedRow.total,
2197
+ included_consumed_usd: includedConsumed,
2109
2198
  on_demand_usd: onDemand,
2110
2199
  saved_usd: saved,
2111
2200
  by_agent: byAgent
@@ -3681,6 +3770,34 @@ async function syncAll(db, opts = {}) {
3681
3770
  return result;
3682
3771
  }
3683
3772
 
3773
+ // src/lib/periods.ts
3774
+ function ymd(date) {
3775
+ return date.toISOString().substring(0, 10);
3776
+ }
3777
+ function usageSnapshotFilterForPeriod(period) {
3778
+ const now = new Date;
3779
+ switch (period) {
3780
+ case "today":
3781
+ return { date: ymd(now) };
3782
+ case "yesterday": {
3783
+ const yesterday = new Date(now);
3784
+ yesterday.setUTCDate(yesterday.getUTCDate() - 1);
3785
+ return { date: ymd(yesterday) };
3786
+ }
3787
+ case "week": {
3788
+ const weekAgo = new Date(now);
3789
+ weekAgo.setUTCDate(weekAgo.getUTCDate() - 7);
3790
+ return { since: ymd(weekAgo) };
3791
+ }
3792
+ case "month":
3793
+ return { since: ymd(new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1))) };
3794
+ case "year":
3795
+ return { since: ymd(new Date(Date.UTC(now.getUTCFullYear(), 0, 1))) };
3796
+ case "all":
3797
+ return {};
3798
+ }
3799
+ }
3800
+
3684
3801
  // src/lib/billing-diff.ts
3685
3802
  init_database();
3686
3803
  var PROVIDER_TO_AGENT = {
@@ -4101,9 +4218,11 @@ function createHandler(db) {
4101
4218
  if (path === "/api/usage" && method === "GET") {
4102
4219
  const period = url.searchParams.get("period") ?? "month";
4103
4220
  const agent = url.searchParams.get("agent") ?? undefined;
4104
- const since = period === "month" ? new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString().substring(0, 10) : undefined;
4105
4221
  return ok({
4106
- snapshots: queryUsageSnapshots(db, { agent: agent && isAgent(agent) ? agent : undefined, since }),
4222
+ snapshots: queryUsageSnapshots(db, {
4223
+ agent: agent && isAgent(agent) ? agent : undefined,
4224
+ ...usageSnapshotFilterForPeriod(period)
4225
+ }),
4107
4226
  summary: querySummary(db, period, undefined, true)
4108
4227
  });
4109
4228
  }
@@ -4112,6 +4231,50 @@ function createHandler(db) {
4112
4231
  const agent = url.searchParams.get("agent") ?? undefined;
4113
4232
  return ok(querySavingsSummary(db, period, agent && isAgent(agent) ? agent : undefined));
4114
4233
  }
4234
+ if (path === "/api/subscriptions" && method === "GET") {
4235
+ return ok(listSubscriptions(db));
4236
+ }
4237
+ if (path === "/api/subscriptions" && method === "POST") {
4238
+ const body = await jsonBody(req);
4239
+ if (!body)
4240
+ return err("invalid JSON body");
4241
+ const provider = optionalString(body["provider"])?.trim();
4242
+ const plan = optionalString(body["plan"])?.trim();
4243
+ if (!provider)
4244
+ return err("provider is required");
4245
+ if (!plan)
4246
+ return err("plan is required");
4247
+ const monthlyFee = finiteNumber(body["monthly_fee_usd"] ?? body["fee_usd"] ?? 0);
4248
+ const includedUsage = finiteNumber(body["included_usage_usd"] ?? 0);
4249
+ if (monthlyFee == null || monthlyFee < 0)
4250
+ return err("monthly_fee_usd must be a non-negative number");
4251
+ if (includedUsage == null || includedUsage < 0)
4252
+ return err("included_usage_usd must be a non-negative number");
4253
+ const agent = optionalAgent(body["agent"]);
4254
+ if (agent === undefined)
4255
+ return err(AGENT_ERROR);
4256
+ const now = new Date().toISOString();
4257
+ const subscription = {
4258
+ id: optionalString(body["id"])?.trim() || randomUUID(),
4259
+ agent,
4260
+ provider,
4261
+ plan,
4262
+ monthly_fee_usd: monthlyFee,
4263
+ included_usage_usd: includedUsage,
4264
+ billing_cycle_start: optionalString(body["billing_cycle_start"]),
4265
+ reset_policy: optionalString(body["reset_policy"]) ?? "monthly",
4266
+ active: body["active"] === false || body["active"] === 0 ? 0 : 1,
4267
+ created_at: optionalString(body["created_at"]) ?? now,
4268
+ updated_at: now
4269
+ };
4270
+ upsertSubscription(db, subscription);
4271
+ return ok(subscription);
4272
+ }
4273
+ const subscriptionMatch = path.match(/^\/api\/subscriptions\/(.+)$/);
4274
+ if (subscriptionMatch && method === "DELETE") {
4275
+ deleteSubscription(db, decodeURIComponent(subscriptionMatch[1]));
4276
+ return ok({ ok: true });
4277
+ }
4115
4278
  const sessionRequestsMatch = path.match(/^\/api\/sessions\/([^/]+)\/requests$/);
4116
4279
  if (sessionRequestsMatch && method === "GET") {
4117
4280
  const sessionId = decodeURIComponent(sessionRequestsMatch[1]);
@@ -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;AAqC7D,UAAU,kBAAkB;IAC1B,EAAE,CAAC,EAAE,QAAQ,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAqED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAAE,YAAY,SAAwB,IACzF,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAwB7D;AAQD,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAuT/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,EAAE,OAAO,GAAE,kBAAuB,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAcvG"}
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;AAuC7D,UAAU,kBAAkB;IAC1B,EAAE,CAAC,EAAE,QAAQ,CAAA;IACb,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC;AAqED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,EAAE,YAAY,SAAwB,IACzF,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAwB7D;AAQD,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAkW/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,EAAE,OAAO,GAAE,kBAAuB,GAAG,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAcvG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/economy",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, Gemini, OpenCode, Cursor, Pi, and Hermes",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",