@hasna/economy 0.2.28 → 0.2.29
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/LICENSE +2 -1
- package/README.md +16 -1
- package/dist/cli/index.js +332 -132
- package/dist/db/database.d.ts +9 -4
- package/dist/db/database.d.ts.map +1 -1
- package/dist/index.js +185 -107
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/mcp/http.d.ts +13 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/index.js +763 -615
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/server/index.js +200 -114
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,QAAQ,YAAY,CAAA;AACjC,eAAO,MAAM,qBAAqB,OAAO,CAAA;AAEzC,wBAAgB,WAAW,IAAI,GAAG,CAssBjC"}
|
package/dist/server/index.js
CHANGED
|
@@ -971,8 +971,10 @@ function queryModelBreakdown(db) {
|
|
|
971
971
|
FROM requests GROUP BY model, agent ORDER BY cost_usd DESC
|
|
972
972
|
`).all();
|
|
973
973
|
}
|
|
974
|
-
function queryAgentBreakdown(db, period = "all") {
|
|
974
|
+
function queryAgentBreakdown(db, period = "all", machine) {
|
|
975
975
|
const requestWhere = requestPeriodWhere(period);
|
|
976
|
+
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
977
|
+
const machineParams = machine ? [machine] : [];
|
|
976
978
|
const groups = new Map;
|
|
977
979
|
const requestRows = db.prepare(`
|
|
978
980
|
SELECT agent,
|
|
@@ -988,10 +990,10 @@ function queryAgentBreakdown(db, period = "all") {
|
|
|
988
990
|
COALESCE(SUM(cost_usd), 0) as cost_usd,
|
|
989
991
|
MAX(timestamp) as last_active
|
|
990
992
|
FROM requests
|
|
991
|
-
WHERE ${requestWhere}
|
|
993
|
+
WHERE ${requestWhere}${machineClause}
|
|
992
994
|
GROUP BY agent
|
|
993
995
|
ORDER BY api_equivalent_usd DESC
|
|
994
|
-
`).all();
|
|
996
|
+
`).all(...machineParams);
|
|
995
997
|
for (const row of requestRows) {
|
|
996
998
|
groups.set(row.agent, row);
|
|
997
999
|
}
|
|
@@ -1004,10 +1006,10 @@ function queryAgentBreakdown(db, period = "all") {
|
|
|
1004
1006
|
COALESCE(SUM(total_cost_usd), 0) as cost_usd,
|
|
1005
1007
|
MAX(started_at) as last_active
|
|
1006
1008
|
FROM sessions
|
|
1007
|
-
WHERE ${sessionWhere}
|
|
1009
|
+
WHERE ${sessionWhere}${machineClause}
|
|
1008
1010
|
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
1009
1011
|
GROUP BY agent
|
|
1010
|
-
`).all();
|
|
1012
|
+
`).all(...machineParams);
|
|
1011
1013
|
for (const row of sessionOnlyRows) {
|
|
1012
1014
|
const existing = groups.get(row.agent) ?? {
|
|
1013
1015
|
agent: row.agent,
|
|
@@ -1084,14 +1086,20 @@ function labelForPath(projectPath, projectName) {
|
|
|
1084
1086
|
function groupKeyForPath(projectPath, projectName) {
|
|
1085
1087
|
return labelForPath(projectPath, projectName).trim().toLowerCase();
|
|
1086
1088
|
}
|
|
1087
|
-
function queryProjectBreakdown(db, period = "all") {
|
|
1089
|
+
function queryProjectBreakdown(db, period = "all", machine) {
|
|
1088
1090
|
const requestWhere = requestPeriodWhere(period);
|
|
1089
1091
|
const sessionWhere = sessionPeriodWhere(period);
|
|
1092
|
+
const sessionMachineClause = machine ? " AND (machine_id = ? OR id IN (SELECT DISTINCT session_id FROM requests WHERE machine_id = ?))" : "";
|
|
1093
|
+
const requestMachineClause = machine ? " AND machine_id = ?" : "";
|
|
1094
|
+
const sessionMachineParams = machine ? [machine, machine] : [];
|
|
1095
|
+
const requestMachineParams = machine ? [machine] : [];
|
|
1096
|
+
const sessionOnlyMachineClause = machine ? " AND machine_id = ?" : "";
|
|
1097
|
+
const sessionOnlyMachineParams = machine ? [machine] : [];
|
|
1090
1098
|
const sessions = db.prepare(`
|
|
1091
1099
|
SELECT id, project_path, project_name, total_cost_usd, started_at
|
|
1092
1100
|
FROM sessions
|
|
1093
|
-
WHERE project_path != '' OR project_name != ''
|
|
1094
|
-
`).all();
|
|
1101
|
+
WHERE (project_path != '' OR project_name != '')${sessionMachineClause}
|
|
1102
|
+
`).all(...sessionMachineParams);
|
|
1095
1103
|
const groups = new Map;
|
|
1096
1104
|
for (const s of sessions) {
|
|
1097
1105
|
const label = labelForPath(s.project_path, s.project_name);
|
|
@@ -1117,7 +1125,8 @@ function queryProjectBreakdown(db, period = "all") {
|
|
|
1117
1125
|
FROM requests
|
|
1118
1126
|
WHERE session_id IN (${placeholders})
|
|
1119
1127
|
AND ${requestWhere}
|
|
1120
|
-
|
|
1128
|
+
${requestMachineClause}
|
|
1129
|
+
`).get(...g.sessionIds, ...requestMachineParams) : { sessions: 0, requests: 0, cost_usd: 0, total_tokens: 0, last_active: null };
|
|
1121
1130
|
const sessionOnlyStats = placeholders.length ? db.prepare(`
|
|
1122
1131
|
SELECT
|
|
1123
1132
|
COUNT(*) as sessions,
|
|
@@ -1128,8 +1137,9 @@ function queryProjectBreakdown(db, period = "all") {
|
|
|
1128
1137
|
FROM sessions
|
|
1129
1138
|
WHERE id IN (${placeholders})
|
|
1130
1139
|
AND ${sessionWhere}
|
|
1140
|
+
${sessionOnlyMachineClause}
|
|
1131
1141
|
AND id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
1132
|
-
`).get(...g.sessionIds) : { sessions: 0, requests: 0, total_tokens: 0, cost_usd: 0, last_active: null };
|
|
1142
|
+
`).get(...g.sessionIds, ...sessionOnlyMachineParams) : { sessions: 0, requests: 0, total_tokens: 0, cost_usd: 0, last_active: null };
|
|
1133
1143
|
const totalSessions = reqStats.sessions + sessionOnlyStats.sessions;
|
|
1134
1144
|
if (totalSessions === 0)
|
|
1135
1145
|
continue;
|
|
@@ -1147,107 +1157,167 @@ function queryProjectBreakdown(db, period = "all") {
|
|
|
1147
1157
|
result.sort((a, b) => b.cost_usd - a.cost_usd);
|
|
1148
1158
|
return result;
|
|
1149
1159
|
}
|
|
1150
|
-
function
|
|
1160
|
+
function normalizeAccountEmail(email) {
|
|
1161
|
+
return (email ?? "").trim().toLowerCase();
|
|
1162
|
+
}
|
|
1163
|
+
function accountIdentityKey(agent, accountKey, accountName, accountEmail) {
|
|
1164
|
+
const identityAgent = (agent || "").trim();
|
|
1165
|
+
const normalizedEmail = normalizeAccountEmail(accountEmail);
|
|
1166
|
+
if (identityAgent && normalizedEmail)
|
|
1167
|
+
return `${identityAgent}:${normalizedEmail}`;
|
|
1168
|
+
if (identityAgent && accountName)
|
|
1169
|
+
return `${identityAgent}:${accountName}`;
|
|
1170
|
+
if (accountKey)
|
|
1171
|
+
return accountKey;
|
|
1172
|
+
return identityAgent ? `${identityAgent}:unknown` : "";
|
|
1173
|
+
}
|
|
1174
|
+
function addAccountBreakdownRow(groups, row, sessionOnly) {
|
|
1175
|
+
const agent = row.agent || row.account_tool;
|
|
1176
|
+
const email = normalizeAccountEmail(row.account_email);
|
|
1177
|
+
const accountName = row.account_name || email || row.account_key;
|
|
1178
|
+
const key = accountIdentityKey(agent, row.account_key, accountName, email);
|
|
1179
|
+
if (!key)
|
|
1180
|
+
return;
|
|
1181
|
+
const group = groups.get(key) ?? {
|
|
1182
|
+
account_key: key,
|
|
1183
|
+
account_tool: agent,
|
|
1184
|
+
account_name: accountName,
|
|
1185
|
+
account_email: email || null,
|
|
1186
|
+
account_source: row.account_source || "unknown",
|
|
1187
|
+
sessionIds: new Set,
|
|
1188
|
+
requests: 0,
|
|
1189
|
+
total_tokens: 0,
|
|
1190
|
+
api_equivalent_usd: 0,
|
|
1191
|
+
metered_api_usd: 0,
|
|
1192
|
+
subscription_included_usd: 0,
|
|
1193
|
+
estimated_usd: 0,
|
|
1194
|
+
unknown_usd: 0,
|
|
1195
|
+
last_active: ""
|
|
1196
|
+
};
|
|
1197
|
+
if (!group.account_email && email)
|
|
1198
|
+
group.account_email = email;
|
|
1199
|
+
if (!group.account_name && accountName)
|
|
1200
|
+
group.account_name = accountName;
|
|
1201
|
+
if ((!group.account_source || group.account_source === "unknown") && row.account_source && row.account_source !== "unknown") {
|
|
1202
|
+
group.account_source = row.account_source;
|
|
1203
|
+
}
|
|
1204
|
+
if (row.session_id)
|
|
1205
|
+
group.sessionIds.add(row.session_id);
|
|
1206
|
+
group.requests += row.requests;
|
|
1207
|
+
group.total_tokens += row.total_tokens;
|
|
1208
|
+
group.api_equivalent_usd += row.cost_usd;
|
|
1209
|
+
if (sessionOnly) {
|
|
1210
|
+
group.estimated_usd += row.cost_usd;
|
|
1211
|
+
} else if (row.cost_basis === "metered_api") {
|
|
1212
|
+
group.metered_api_usd += row.cost_usd;
|
|
1213
|
+
} else if (row.cost_basis === "subscription_included") {
|
|
1214
|
+
group.subscription_included_usd += row.cost_usd;
|
|
1215
|
+
} else if (row.cost_basis === "unknown") {
|
|
1216
|
+
group.unknown_usd += row.cost_usd;
|
|
1217
|
+
} else {
|
|
1218
|
+
group.estimated_usd += row.cost_usd;
|
|
1219
|
+
}
|
|
1220
|
+
if (!group.last_active || row.last_active > group.last_active)
|
|
1221
|
+
group.last_active = row.last_active;
|
|
1222
|
+
groups.set(key, group);
|
|
1223
|
+
}
|
|
1224
|
+
function queryAccountBreakdown(db, period = "all", machine) {
|
|
1151
1225
|
const requestWhere = requestPeriodWhere(period);
|
|
1152
1226
|
const sessionWhere = sessionPeriodWhere(period);
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
WHERE account_key != '' OR account_tool != '' OR account_name != '' OR account_email != ''
|
|
1158
|
-
`).all();
|
|
1227
|
+
const requestMachineClause = machine ? " AND r.machine_id = ?" : "";
|
|
1228
|
+
const sessionMachineClause = machine ? " AND s.machine_id = ?" : "";
|
|
1229
|
+
const requestMachineParams = machine ? [machine] : [];
|
|
1230
|
+
const sessionMachineParams = machine ? [machine] : [];
|
|
1159
1231
|
const groups = new Map;
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
account_email: group.account_email,
|
|
1226
|
-
account_source: group.account_source,
|
|
1227
|
-
sessions: sessionsTotal,
|
|
1228
|
-
requests: reqStats.requests + sessionOnlyStats.requests,
|
|
1229
|
-
total_tokens: reqStats.total_tokens + sessionOnlyStats.total_tokens,
|
|
1230
|
-
api_equivalent_usd: apiEquivalentUsd,
|
|
1231
|
-
billable_usd: billableUsd,
|
|
1232
|
-
metered_api_usd: reqStats.metered_api_usd,
|
|
1233
|
-
subscription_included_usd: reqStats.subscription_included_usd,
|
|
1234
|
-
estimated_usd: estimatedUsd,
|
|
1235
|
-
unknown_usd: reqStats.unknown_usd,
|
|
1236
|
-
cost_usd: apiEquivalentUsd,
|
|
1237
|
-
last_active: lastActive
|
|
1238
|
-
});
|
|
1239
|
-
}
|
|
1232
|
+
const requestRows = db.prepare(`
|
|
1233
|
+
SELECT
|
|
1234
|
+
r.session_id as session_id,
|
|
1235
|
+
COALESCE(NULLIF(r.agent, ''), NULLIF(s.agent, ''), '') as agent,
|
|
1236
|
+
COALESCE(NULLIF(r.account_key, ''), NULLIF(s.account_key, ''), '') as account_key,
|
|
1237
|
+
COALESCE(NULLIF(r.account_tool, ''), NULLIF(s.account_tool, ''), '') as account_tool,
|
|
1238
|
+
COALESCE(NULLIF(r.account_name, ''), NULLIF(s.account_name, ''), '') as account_name,
|
|
1239
|
+
COALESCE(NULLIF(r.account_email, ''), NULLIF(s.account_email, ''), '') as account_email,
|
|
1240
|
+
COALESCE(NULLIF(r.account_source, ''), NULLIF(s.account_source, ''), 'unknown') as account_source,
|
|
1241
|
+
1 as requests,
|
|
1242
|
+
COALESCE(r.input_tokens + r.output_tokens + r.cache_read_tokens + r.cache_create_tokens, 0) as total_tokens,
|
|
1243
|
+
COALESCE(r.cost_usd, 0) as cost_usd,
|
|
1244
|
+
COALESCE(NULLIF(r.cost_basis, ''), 'estimated') as cost_basis,
|
|
1245
|
+
r.timestamp as last_active
|
|
1246
|
+
FROM requests r
|
|
1247
|
+
LEFT JOIN sessions s ON s.id = r.session_id
|
|
1248
|
+
WHERE ${requestWhere}${requestMachineClause}
|
|
1249
|
+
AND (
|
|
1250
|
+
COALESCE(NULLIF(r.account_key, ''), NULLIF(s.account_key, ''), '') != ''
|
|
1251
|
+
OR COALESCE(NULLIF(r.account_tool, ''), NULLIF(s.account_tool, ''), '') != ''
|
|
1252
|
+
OR COALESCE(NULLIF(r.account_name, ''), NULLIF(s.account_name, ''), '') != ''
|
|
1253
|
+
OR COALESCE(NULLIF(r.account_email, ''), NULLIF(s.account_email, ''), '') != ''
|
|
1254
|
+
)
|
|
1255
|
+
`).all(...requestMachineParams);
|
|
1256
|
+
for (const row of requestRows)
|
|
1257
|
+
addAccountBreakdownRow(groups, row, false);
|
|
1258
|
+
const sessionOnlyRows = db.prepare(`
|
|
1259
|
+
SELECT
|
|
1260
|
+
s.id as session_id,
|
|
1261
|
+
s.agent as agent,
|
|
1262
|
+
s.account_key as account_key,
|
|
1263
|
+
s.account_tool as account_tool,
|
|
1264
|
+
s.account_name as account_name,
|
|
1265
|
+
s.account_email as account_email,
|
|
1266
|
+
COALESCE(NULLIF(s.account_source, ''), 'unknown') as account_source,
|
|
1267
|
+
COALESCE(s.request_count, 0) as requests,
|
|
1268
|
+
COALESCE(s.total_tokens, 0) as total_tokens,
|
|
1269
|
+
COALESCE(s.total_cost_usd, 0) as cost_usd,
|
|
1270
|
+
'estimated' as cost_basis,
|
|
1271
|
+
s.started_at as last_active
|
|
1272
|
+
FROM sessions s
|
|
1273
|
+
WHERE ${sessionWhere}${sessionMachineClause}
|
|
1274
|
+
AND s.id NOT IN (SELECT DISTINCT session_id FROM requests)
|
|
1275
|
+
AND (s.account_key != '' OR s.account_tool != '' OR s.account_name != '' OR s.account_email != '')
|
|
1276
|
+
`).all(...sessionMachineParams);
|
|
1277
|
+
for (const row of sessionOnlyRows)
|
|
1278
|
+
addAccountBreakdownRow(groups, row, true);
|
|
1279
|
+
const result = [...groups.values()].map((group) => ({
|
|
1280
|
+
account_key: group.account_key,
|
|
1281
|
+
account_tool: group.account_tool,
|
|
1282
|
+
account_name: group.account_name,
|
|
1283
|
+
account_email: group.account_email,
|
|
1284
|
+
account_source: group.account_source,
|
|
1285
|
+
sessions: group.sessionIds.size,
|
|
1286
|
+
requests: group.requests,
|
|
1287
|
+
total_tokens: group.total_tokens,
|
|
1288
|
+
api_equivalent_usd: group.api_equivalent_usd,
|
|
1289
|
+
billable_usd: group.metered_api_usd,
|
|
1290
|
+
metered_api_usd: group.metered_api_usd,
|
|
1291
|
+
subscription_included_usd: group.subscription_included_usd,
|
|
1292
|
+
estimated_usd: group.estimated_usd,
|
|
1293
|
+
unknown_usd: group.unknown_usd,
|
|
1294
|
+
cost_usd: group.api_equivalent_usd,
|
|
1295
|
+
last_active: group.last_active
|
|
1296
|
+
}));
|
|
1240
1297
|
result.sort((a, b) => b.cost_usd - a.cost_usd);
|
|
1241
1298
|
return result;
|
|
1242
1299
|
}
|
|
1243
|
-
function queryDailyBreakdown(db, days = 30) {
|
|
1300
|
+
function queryDailyBreakdown(db, days = 30, machine) {
|
|
1301
|
+
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
1302
|
+
const params = machine ? [`-${days}`, machine] : [`-${days}`];
|
|
1244
1303
|
return db.prepare(`
|
|
1245
1304
|
SELECT DATE(timestamp) as date, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
1246
1305
|
FROM requests
|
|
1247
|
-
WHERE timestamp >= DATE('now', ? || ' days')
|
|
1306
|
+
WHERE timestamp >= DATE('now', ? || ' days')${machineClause}
|
|
1248
1307
|
GROUP BY DATE(timestamp), agent
|
|
1249
1308
|
ORDER BY date ASC
|
|
1250
|
-
`).all(
|
|
1309
|
+
`).all(...params);
|
|
1310
|
+
}
|
|
1311
|
+
function queryHourlyBreakdown(db, machine) {
|
|
1312
|
+
const machineClause = machine ? " AND machine_id = ?" : "";
|
|
1313
|
+
const params = machine ? [machine] : [];
|
|
1314
|
+
return db.prepare(`
|
|
1315
|
+
SELECT STRFTIME('%H', timestamp) as hour, agent, COALESCE(SUM(cost_usd), 0) as cost_usd
|
|
1316
|
+
FROM requests
|
|
1317
|
+
WHERE DATE(timestamp) = DATE('now')${machineClause}
|
|
1318
|
+
GROUP BY STRFTIME('%H', timestamp), agent
|
|
1319
|
+
ORDER BY hour ASC
|
|
1320
|
+
`).all(...params);
|
|
1251
1321
|
}
|
|
1252
1322
|
function upsertProject(db, project) {
|
|
1253
1323
|
db.prepare(`
|
|
@@ -2283,18 +2353,22 @@ var AGENT_ACCOUNT_TOOLS = {
|
|
|
2283
2353
|
pi: ["pi"],
|
|
2284
2354
|
hermes: ["hermes"]
|
|
2285
2355
|
};
|
|
2286
|
-
function
|
|
2287
|
-
return
|
|
2356
|
+
function normalizeEmail(email) {
|
|
2357
|
+
return (email ?? "").trim().toLowerCase();
|
|
2358
|
+
}
|
|
2359
|
+
function accountKey(tool, name, email) {
|
|
2360
|
+
const normalizedEmail = normalizeEmail(email);
|
|
2361
|
+
return `${tool}:${normalizedEmail || name}`;
|
|
2288
2362
|
}
|
|
2289
2363
|
function normalizeDir(value) {
|
|
2290
2364
|
return value.replace(/\/+$/, "");
|
|
2291
2365
|
}
|
|
2292
2366
|
function fromProfile(profile, source) {
|
|
2293
2367
|
return {
|
|
2294
|
-
account_key: accountKey(profile.tool, profile.name),
|
|
2368
|
+
account_key: accountKey(profile.tool, profile.name, profile.email),
|
|
2295
2369
|
account_tool: profile.tool,
|
|
2296
2370
|
account_name: profile.name,
|
|
2297
|
-
...profile.email ? { account_email: profile.email } : {},
|
|
2371
|
+
...profile.email ? { account_email: normalizeEmail(profile.email) } : {},
|
|
2298
2372
|
account_source: source
|
|
2299
2373
|
};
|
|
2300
2374
|
}
|
|
@@ -2306,10 +2380,12 @@ function fromOverride(raw, agent) {
|
|
|
2306
2380
|
const [tool, name] = value.includes(":") ? value.split(":", 2) : [candidateTool, value];
|
|
2307
2381
|
if (!tool || !name)
|
|
2308
2382
|
return null;
|
|
2383
|
+
const email = name.includes("@") ? normalizeEmail(name) : undefined;
|
|
2309
2384
|
return {
|
|
2310
|
-
account_key: accountKey(tool, name),
|
|
2385
|
+
account_key: accountKey(tool, name, email),
|
|
2311
2386
|
account_tool: tool,
|
|
2312
2387
|
account_name: name,
|
|
2388
|
+
...email ? { account_email: email } : {},
|
|
2313
2389
|
account_source: "override"
|
|
2314
2390
|
};
|
|
2315
2391
|
}
|
|
@@ -2322,11 +2398,12 @@ function envOverride(agent, env) {
|
|
|
2322
2398
|
const name = env[`ECONOMY_${agentPrefix}_ACCOUNT_NAME`] ?? env["ECONOMY_ACCOUNT_NAME"];
|
|
2323
2399
|
if (!tool || !name)
|
|
2324
2400
|
return null;
|
|
2401
|
+
const email = normalizeEmail(env[`ECONOMY_${agentPrefix}_ACCOUNT_EMAIL`] ?? env["ECONOMY_ACCOUNT_EMAIL"]);
|
|
2325
2402
|
return {
|
|
2326
|
-
account_key: accountKey(tool, name),
|
|
2403
|
+
account_key: accountKey(tool, name, email),
|
|
2327
2404
|
account_tool: tool,
|
|
2328
2405
|
account_name: name,
|
|
2329
|
-
account_email:
|
|
2406
|
+
...email ? { account_email: email } : {},
|
|
2330
2407
|
account_source: "override"
|
|
2331
2408
|
};
|
|
2332
2409
|
}
|
|
@@ -4085,8 +4162,9 @@ function createHandler(db) {
|
|
|
4085
4162
|
}
|
|
4086
4163
|
if (path === "/api/fleet" && method === "GET") {
|
|
4087
4164
|
const period = url.searchParams.get("period") ?? "month";
|
|
4165
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4088
4166
|
return ok({
|
|
4089
|
-
summary: querySummary(db, period,
|
|
4167
|
+
summary: querySummary(db, period, machine),
|
|
4090
4168
|
machines: listMachines(db, period),
|
|
4091
4169
|
registry: listMachineRegistry(db),
|
|
4092
4170
|
current_machine: getMachineId()
|
|
@@ -4094,7 +4172,12 @@ function createHandler(db) {
|
|
|
4094
4172
|
}
|
|
4095
4173
|
if (path === "/api/daily" && method === "GET") {
|
|
4096
4174
|
const days = Number(url.searchParams.get("days") ?? 30);
|
|
4097
|
-
|
|
4175
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4176
|
+
return ok(queryDailyBreakdown(db, days, machine));
|
|
4177
|
+
}
|
|
4178
|
+
if (path === "/api/hourly" && method === "GET") {
|
|
4179
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4180
|
+
return ok(queryHourlyBreakdown(db, machine));
|
|
4098
4181
|
}
|
|
4099
4182
|
if (path === "/api/sessions" && method === "GET") {
|
|
4100
4183
|
const agent = url.searchParams.get("agent");
|
|
@@ -4164,21 +4247,24 @@ function createHandler(db) {
|
|
|
4164
4247
|
}
|
|
4165
4248
|
if (path === "/api/projects" && method === "GET") {
|
|
4166
4249
|
const period = url.searchParams.get("period") ?? "all";
|
|
4167
|
-
|
|
4250
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4251
|
+
return ok(queryProjectBreakdown(db, period, machine));
|
|
4168
4252
|
}
|
|
4169
4253
|
if (path === "/api/accounts" && method === "GET") {
|
|
4170
4254
|
const period = url.searchParams.get("period") ?? "all";
|
|
4171
|
-
|
|
4255
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4256
|
+
return ok(queryAccountBreakdown(db, period, machine));
|
|
4172
4257
|
}
|
|
4173
4258
|
if (path === "/api/breakdown" && method === "GET") {
|
|
4174
4259
|
const by = url.searchParams.get("by") ?? "model";
|
|
4175
4260
|
const period = url.searchParams.get("period") ?? "all";
|
|
4261
|
+
const machine = url.searchParams.get("machine") ?? undefined;
|
|
4176
4262
|
if (by === "project")
|
|
4177
|
-
return ok(queryProjectBreakdown(db, period));
|
|
4263
|
+
return ok(queryProjectBreakdown(db, period, machine));
|
|
4178
4264
|
if (by === "agent")
|
|
4179
|
-
return ok(queryAgentBreakdown(db, period));
|
|
4265
|
+
return ok(queryAgentBreakdown(db, period, machine));
|
|
4180
4266
|
if (by === "account")
|
|
4181
|
-
return ok(queryAccountBreakdown(db, period));
|
|
4267
|
+
return ok(queryAccountBreakdown(db, period, machine));
|
|
4182
4268
|
return ok(queryModelBreakdown(db));
|
|
4183
4269
|
}
|
|
4184
4270
|
if (path === "/api/budgets" && method === "GET") {
|
|
@@ -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;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,
|
|
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,CA4W/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.
|
|
3
|
+
"version": "0.2.29",
|
|
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",
|