archondev 2.19.4 → 2.19.6
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/dist/{chunk-3UOMLERV.js → chunk-KDWIKBM2.js} +1 -1
- package/dist/{chunk-K3XN7PN6.js → chunk-MIT5Z5V7.js} +243 -86
- package/dist/{chunk-IKMCIWK3.js → chunk-OTODLPY4.js} +177 -104
- package/dist/{chunk-C4HVI2NJ.js → chunk-W6TYXCZA.js} +1 -1
- package/dist/{chunk-HQBF3VTN.js → chunk-X5ZZCJBQ.js} +52 -11
- package/dist/{execute-JAHXFYXL.js → execute-DBNVIJ3P.js} +3 -2
- package/dist/index.js +332 -91
- package/dist/{list-Q4HLHQJI.js → list-SKRHIZ5T.js} +3 -2
- package/dist/{parallel-QLKYSZZ3.js → parallel-KRBYFJ4O.js} +3 -2
- package/dist/{plan-7M27X3OD.js → plan-7SCZH7EA.js} +2 -1
- package/dist/{preferences-SFXRVXT3.js → preferences-4V4C7MVD.js} +3 -1
- package/package.json +1 -1
|
@@ -763,6 +763,7 @@ async function interactiveSettings() {
|
|
|
763
763
|
}
|
|
764
764
|
await displayCurrentSettings(profile, usage, providers);
|
|
765
765
|
console.log(chalk.bold("\nOptions:\n"));
|
|
766
|
+
console.log(chalk.dim("Type naturally (recommended) or use a shortcut:\n"));
|
|
766
767
|
console.log(` ${chalk.cyan("1")}) Change billing mode (BYOK / Credits)`);
|
|
767
768
|
console.log(` ${chalk.cyan("2")}) Set default models`);
|
|
768
769
|
console.log(` ${chalk.cyan("x")}) Smart Routing (cost optimization)`);
|
|
@@ -771,7 +772,8 @@ async function interactiveSettings() {
|
|
|
771
772
|
console.log(` ${chalk.cyan("5")}) Reset to defaults`);
|
|
772
773
|
console.log(` ${chalk.cyan("b")}) Back to project`);
|
|
773
774
|
console.log();
|
|
774
|
-
const
|
|
775
|
+
const rawChoice = await prompt("What would you like to do?");
|
|
776
|
+
const choice = resolveSettingsChoice(rawChoice);
|
|
775
777
|
switch (choice.toLowerCase()) {
|
|
776
778
|
case "1":
|
|
777
779
|
await changeBillingMode(profile.tier);
|
|
@@ -790,7 +792,7 @@ async function interactiveSettings() {
|
|
|
790
792
|
await interactiveSettings();
|
|
791
793
|
break;
|
|
792
794
|
case "4":
|
|
793
|
-
await showUsageDetails();
|
|
795
|
+
await showUsageDetails({ pauseForInput: true });
|
|
794
796
|
await interactiveSettings();
|
|
795
797
|
break;
|
|
796
798
|
case "5":
|
|
@@ -801,7 +803,7 @@ async function interactiveSettings() {
|
|
|
801
803
|
console.log(chalk.dim("\nReturning to project...\n"));
|
|
802
804
|
return;
|
|
803
805
|
default:
|
|
804
|
-
console.log(chalk.yellow("
|
|
806
|
+
console.log(chalk.yellow("I did not catch that. Try again or describe what you need."));
|
|
805
807
|
await interactiveSettings();
|
|
806
808
|
}
|
|
807
809
|
}
|
|
@@ -843,7 +845,8 @@ async function changeBillingMode(currentTier) {
|
|
|
843
845
|
console.log(chalk.dim(" 10% service fee applied.\n"));
|
|
844
846
|
console.log(` ${chalk.cyan("b")}) Back`);
|
|
845
847
|
console.log();
|
|
846
|
-
const
|
|
848
|
+
const rawChoice = await prompt("How do you want to pay?");
|
|
849
|
+
const choice = resolveBillingChoice(rawChoice);
|
|
847
850
|
if (choice === "1" && !byokSelected) {
|
|
848
851
|
const spinner = ora("Switching to BYOK...").start();
|
|
849
852
|
const result = await updateUserTier("BYOK");
|
|
@@ -861,9 +864,11 @@ async function changeBillingMode(currentTier) {
|
|
|
861
864
|
} else {
|
|
862
865
|
spinner.fail(chalk.red(result.error ?? "Failed to update"));
|
|
863
866
|
}
|
|
864
|
-
} else if (choice
|
|
867
|
+
} else if (choice !== "b") {
|
|
865
868
|
if (choice === "1" && byokSelected || choice === "2" && creditsSelected) {
|
|
866
869
|
console.log(chalk.dim("Already using this billing mode."));
|
|
870
|
+
} else {
|
|
871
|
+
console.log(chalk.yellow("I did not catch that."));
|
|
867
872
|
}
|
|
868
873
|
}
|
|
869
874
|
}
|
|
@@ -877,7 +882,8 @@ async function setDefaultModelsMenu(profile, providers) {
|
|
|
877
882
|
console.log();
|
|
878
883
|
console.log(` ${chalk.cyan("b")}) Back`);
|
|
879
884
|
console.log();
|
|
880
|
-
const
|
|
885
|
+
const rawChoice = await prompt("Which default model should change?");
|
|
886
|
+
const choice = resolveDefaultModelSlotChoice(rawChoice);
|
|
881
887
|
const keyMap = {
|
|
882
888
|
"1": "fast-model",
|
|
883
889
|
"2": "thinking-model",
|
|
@@ -889,7 +895,7 @@ async function setDefaultModelsMenu(profile, providers) {
|
|
|
889
895
|
}
|
|
890
896
|
const prefKey = keyMap[choice];
|
|
891
897
|
if (!prefKey) {
|
|
892
|
-
console.log(chalk.yellow("
|
|
898
|
+
console.log(chalk.yellow("I did not catch that."));
|
|
893
899
|
return;
|
|
894
900
|
}
|
|
895
901
|
const models = getAllActiveModels();
|
|
@@ -906,8 +912,8 @@ async function setDefaultModelsMenu(profile, providers) {
|
|
|
906
912
|
console.log(` ${chalk.cyan(String(i + 1))}) ${m.modelName} ${categoryLabel}`);
|
|
907
913
|
});
|
|
908
914
|
console.log();
|
|
909
|
-
const modelChoice = await prompt("
|
|
910
|
-
const modelIndex =
|
|
915
|
+
const modelChoice = await prompt("Which model do you want? (number or model name)");
|
|
916
|
+
const modelIndex = resolveModelChoice(modelChoice, availableModels);
|
|
911
917
|
if (modelIndex >= 0 && modelIndex < availableModels.length) {
|
|
912
918
|
const selectedModel = availableModels[modelIndex];
|
|
913
919
|
if (selectedModel) {
|
|
@@ -940,7 +946,8 @@ async function setSmartRoutingMenu(profile, providers) {
|
|
|
940
946
|
console.log(` ${chalk.cyan("5")}) View operations by tier`);
|
|
941
947
|
console.log(` ${chalk.cyan("b")}) Back`);
|
|
942
948
|
console.log();
|
|
943
|
-
const
|
|
949
|
+
const rawChoice = await prompt("What would you like to change?");
|
|
950
|
+
const choice = resolveSmartRoutingChoice(rawChoice);
|
|
944
951
|
if (choice.toLowerCase() === "b") {
|
|
945
952
|
return;
|
|
946
953
|
}
|
|
@@ -963,7 +970,8 @@ async function setSmartRoutingMenu(profile, providers) {
|
|
|
963
970
|
console.log(` ${chalk.cyan("3")}) google`);
|
|
964
971
|
console.log(` ${chalk.cyan("0")}) Clear preference (auto)`);
|
|
965
972
|
console.log();
|
|
966
|
-
const
|
|
973
|
+
const provChoiceRaw = await prompt("Which provider should be preferred?");
|
|
974
|
+
const provChoice = resolveProviderChoice(provChoiceRaw);
|
|
967
975
|
const providerMap = {
|
|
968
976
|
"0": null,
|
|
969
977
|
"1": "anthropic",
|
|
@@ -997,12 +1005,12 @@ Select model for ${selectedTier.tier} tier:
|
|
|
997
1005
|
console.log(` ${chalk.cyan(String(i + 1))}) ${m.modelName} ${categoryLabel}`);
|
|
998
1006
|
});
|
|
999
1007
|
console.log();
|
|
1000
|
-
const modelChoice = await prompt("
|
|
1008
|
+
const modelChoice = await prompt("Which model do you want for this tier? (number or model name)");
|
|
1001
1009
|
if (modelChoice === "0") {
|
|
1002
1010
|
await setTierPreference(selectedTier.key, null);
|
|
1003
1011
|
return;
|
|
1004
1012
|
}
|
|
1005
|
-
const modelIndex =
|
|
1013
|
+
const modelIndex = resolveModelChoice(modelChoice, availableModels);
|
|
1006
1014
|
if (modelIndex >= 0 && modelIndex < availableModels.length) {
|
|
1007
1015
|
const selectedModel = availableModels[modelIndex];
|
|
1008
1016
|
if (selectedModel) {
|
|
@@ -1057,7 +1065,8 @@ async function manageApiKeys() {
|
|
|
1057
1065
|
console.log(` ${chalk.cyan("4")}) Remove a key`);
|
|
1058
1066
|
console.log(` ${chalk.cyan("b")}) Back`);
|
|
1059
1067
|
console.log();
|
|
1060
|
-
const
|
|
1068
|
+
const rawChoice = await prompt("What do you want to do with API keys?");
|
|
1069
|
+
const choice = resolveApiKeysChoice(rawChoice);
|
|
1061
1070
|
const providerMap = {
|
|
1062
1071
|
"1": "anthropic",
|
|
1063
1072
|
"2": "openai",
|
|
@@ -1073,8 +1082,8 @@ async function manageApiKeys() {
|
|
|
1073
1082
|
}
|
|
1074
1083
|
console.log("\nWhich provider to remove?");
|
|
1075
1084
|
providers.forEach((p, i) => console.log(` ${chalk.cyan(String(i + 1))}) ${p}`));
|
|
1076
|
-
const removeChoice = await prompt("
|
|
1077
|
-
const removeIndex =
|
|
1085
|
+
const removeChoice = await prompt("Which provider key should be removed?");
|
|
1086
|
+
const removeIndex = resolveProviderIndexChoice(removeChoice, providers);
|
|
1078
1087
|
if (removeIndex >= 0 && removeIndex < providers.length) {
|
|
1079
1088
|
const providerToRemove = providers[removeIndex];
|
|
1080
1089
|
if (providerToRemove) {
|
|
@@ -1088,9 +1097,182 @@ async function manageApiKeys() {
|
|
|
1088
1097
|
if (provider) {
|
|
1089
1098
|
const { addKey } = await import("./keys-T2VPHE7Z.js");
|
|
1090
1099
|
await addKey(provider);
|
|
1100
|
+
} else if (choice !== "b") {
|
|
1101
|
+
console.log(chalk.yellow("I did not catch that."));
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function resolveSettingsChoice(input) {
|
|
1105
|
+
const normalized = input.trim().toLowerCase();
|
|
1106
|
+
if (!normalized) return "";
|
|
1107
|
+
if (normalized === "1" || normalized.includes("billing") || normalized.includes("tier") || normalized.includes("pay")) return "1";
|
|
1108
|
+
if (normalized === "2" || normalized.includes("default model") || normalized.includes("model")) return "2";
|
|
1109
|
+
if (normalized === "x" || normalized === "smart" || normalized.includes("routing") || normalized.includes("cost optimization")) return "x";
|
|
1110
|
+
if (normalized === "3" || normalized.includes("key")) return "3";
|
|
1111
|
+
if (normalized === "4" || normalized.includes("usage") || normalized.includes("spend") || normalized.includes("cost details")) return "4";
|
|
1112
|
+
if (normalized === "5" || normalized.includes("reset") || normalized.includes("defaults")) return "5";
|
|
1113
|
+
if (normalized === "b" || normalized.includes("back") || normalized.includes("return")) return "b";
|
|
1114
|
+
return normalized;
|
|
1115
|
+
}
|
|
1116
|
+
function resolveBillingChoice(input) {
|
|
1117
|
+
const normalized = input.trim().toLowerCase();
|
|
1118
|
+
if (!normalized) return "";
|
|
1119
|
+
if (normalized === "1" || normalized.includes("byok") || normalized.includes("own key")) return "1";
|
|
1120
|
+
if (normalized === "2" || normalized.includes("credit") || normalized.includes("managed")) return "2";
|
|
1121
|
+
if (normalized === "b" || normalized.includes("back")) return "b";
|
|
1122
|
+
return normalized;
|
|
1123
|
+
}
|
|
1124
|
+
function resolveDefaultModelSlotChoice(input) {
|
|
1125
|
+
const normalized = input.trim().toLowerCase();
|
|
1126
|
+
if (!normalized) return "";
|
|
1127
|
+
if (normalized === "1" || normalized.includes("fast")) return "1";
|
|
1128
|
+
if (normalized === "2" || normalized.includes("thinking")) return "2";
|
|
1129
|
+
if (normalized === "3" || normalized.includes("primary")) return "3";
|
|
1130
|
+
if (normalized === "4" || normalized.includes("secondary")) return "4";
|
|
1131
|
+
if (normalized === "b" || normalized.includes("back")) return "b";
|
|
1132
|
+
return normalized;
|
|
1133
|
+
}
|
|
1134
|
+
function resolveModelChoice(choice, models) {
|
|
1135
|
+
const normalized = choice.trim().toLowerCase();
|
|
1136
|
+
const numeric = parseInt(normalized, 10);
|
|
1137
|
+
if (!Number.isNaN(numeric)) {
|
|
1138
|
+
return numeric - 1;
|
|
1139
|
+
}
|
|
1140
|
+
const idx = models.findIndex(
|
|
1141
|
+
(m) => m.modelId.toLowerCase() === normalized || m.modelName.toLowerCase() === normalized || m.modelName.toLowerCase().includes(normalized) || normalized.includes(m.modelName.toLowerCase())
|
|
1142
|
+
);
|
|
1143
|
+
return idx;
|
|
1144
|
+
}
|
|
1145
|
+
function resolveSmartRoutingChoice(input) {
|
|
1146
|
+
const normalized = input.trim().toLowerCase();
|
|
1147
|
+
if (!normalized) return "";
|
|
1148
|
+
if (normalized === "1" || normalized.includes("planning")) return "1";
|
|
1149
|
+
if (normalized === "2" || normalized.includes("reasoning")) return "2";
|
|
1150
|
+
if (normalized === "3" || normalized.includes("execution")) return "3";
|
|
1151
|
+
if (normalized === "4" || normalized.includes("provider")) return "4";
|
|
1152
|
+
if (normalized === "5" || normalized.includes("operation")) return "5";
|
|
1153
|
+
if (normalized === "b" || normalized.includes("back")) return "b";
|
|
1154
|
+
return normalized;
|
|
1155
|
+
}
|
|
1156
|
+
function resolveProviderChoice(input) {
|
|
1157
|
+
const normalized = input.trim().toLowerCase();
|
|
1158
|
+
if (!normalized) return "";
|
|
1159
|
+
if (normalized === "0" || normalized.includes("auto") || normalized.includes("clear")) return "0";
|
|
1160
|
+
if (normalized === "1" || normalized.includes("anthropic")) return "1";
|
|
1161
|
+
if (normalized === "2" || normalized.includes("openai")) return "2";
|
|
1162
|
+
if (normalized === "3" || normalized.includes("google") || normalized.includes("gemini")) return "3";
|
|
1163
|
+
return normalized;
|
|
1164
|
+
}
|
|
1165
|
+
function resolveApiKeysChoice(input) {
|
|
1166
|
+
const normalized = input.trim().toLowerCase();
|
|
1167
|
+
if (!normalized) return "";
|
|
1168
|
+
if (normalized === "1" || normalized.includes("add") && normalized.includes("anthropic")) return "1";
|
|
1169
|
+
if (normalized === "2" || normalized.includes("add") && normalized.includes("openai")) return "2";
|
|
1170
|
+
if (normalized === "3" || normalized.includes("add") && (normalized.includes("google") || normalized.includes("gemini"))) return "3";
|
|
1171
|
+
if (normalized === "4" || normalized.includes("remove") || normalized.includes("delete")) return "4";
|
|
1172
|
+
if (normalized === "b" || normalized.includes("back")) return "b";
|
|
1173
|
+
return normalized;
|
|
1174
|
+
}
|
|
1175
|
+
function resolveProviderIndexChoice(choice, providers) {
|
|
1176
|
+
const normalized = choice.trim().toLowerCase();
|
|
1177
|
+
const numeric = parseInt(normalized, 10);
|
|
1178
|
+
if (!Number.isNaN(numeric)) return numeric - 1;
|
|
1179
|
+
return providers.findIndex((p) => normalized.includes(p));
|
|
1180
|
+
}
|
|
1181
|
+
var __preferencesChoiceHelpers = {
|
|
1182
|
+
resolveSettingsChoice,
|
|
1183
|
+
resolveBillingChoice,
|
|
1184
|
+
resolveDefaultModelSlotChoice,
|
|
1185
|
+
resolveSmartRoutingChoice,
|
|
1186
|
+
resolveProviderChoice,
|
|
1187
|
+
resolveApiKeysChoice,
|
|
1188
|
+
resolveProviderIndexChoice,
|
|
1189
|
+
resolveModelChoice
|
|
1190
|
+
};
|
|
1191
|
+
function formatLocalDateTime(value) {
|
|
1192
|
+
const date = new Date(value);
|
|
1193
|
+
if (isNaN(date.getTime())) {
|
|
1194
|
+
return value;
|
|
1091
1195
|
}
|
|
1196
|
+
return date.toLocaleString();
|
|
1197
|
+
}
|
|
1198
|
+
function formatUsagePeriodLabel(periodSource) {
|
|
1199
|
+
if (periodSource === "credit_purchase") return "Since last top-up";
|
|
1200
|
+
if (periodSource === "month") return "Current month to date";
|
|
1201
|
+
return "Current billing period";
|
|
1092
1202
|
}
|
|
1093
|
-
|
|
1203
|
+
function sumModelCost(byModel) {
|
|
1204
|
+
return (byModel ?? []).reduce((sum, row) => sum + row.cost, 0);
|
|
1205
|
+
}
|
|
1206
|
+
function renderModelBreakdown(rows, options = {}) {
|
|
1207
|
+
const indent = options.indent ?? " ";
|
|
1208
|
+
if (rows.length === 0) {
|
|
1209
|
+
console.log(chalk.dim(`${indent}No usage recorded.`));
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
const total = rows.reduce((sum, row) => sum + row.cost, 0);
|
|
1213
|
+
const sorted = [...rows].sort((a, b) => b.cost - a.cost);
|
|
1214
|
+
for (const row of sorted) {
|
|
1215
|
+
const modelInfo = findModel(row.model);
|
|
1216
|
+
const name = modelInfo?.name ?? row.model;
|
|
1217
|
+
const tokenTotal = row.inputTokens + row.outputTokens;
|
|
1218
|
+
const share = total > 0 ? (row.cost / total * 100).toFixed(1) : "0.0";
|
|
1219
|
+
const note = options.costNote ? ` ${chalk.dim(options.costNote)}` : "";
|
|
1220
|
+
console.log(`${indent}${name}: ${formatTokens(tokenTotal)} tokens | ${formatCost(row.cost)} (${share}%)${note}`);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
async function resolveAuthAndProfileIds(authToken, fallbackAuthId) {
|
|
1224
|
+
const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
|
|
1225
|
+
let authId = fallbackAuthId ?? null;
|
|
1226
|
+
if (!authId) {
|
|
1227
|
+
const { data, error } = await supabase.auth.getUser();
|
|
1228
|
+
if (error || !data.user?.id) {
|
|
1229
|
+
return { authId: null, profileId: null };
|
|
1230
|
+
}
|
|
1231
|
+
authId = data.user.id;
|
|
1232
|
+
}
|
|
1233
|
+
const { data: profileRow, error: profileError } = await supabase.from("user_profiles").select("id").eq("auth_id", authId).single();
|
|
1234
|
+
if (profileError || !profileRow?.id) {
|
|
1235
|
+
return { authId, profileId: null };
|
|
1236
|
+
}
|
|
1237
|
+
return { authId, profileId: profileRow.id };
|
|
1238
|
+
}
|
|
1239
|
+
async function fetchUsageRows(authToken, profileId, startIso, endIso) {
|
|
1240
|
+
const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
|
|
1241
|
+
const { data, error } = await supabase.from("token_usage").select("model, input_tokens, output_tokens, base_cost, created_at").eq("user_id", profileId).gte("created_at", startIso).lte("created_at", endIso);
|
|
1242
|
+
if (error || !data) {
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
return data;
|
|
1246
|
+
}
|
|
1247
|
+
function aggregateUsageRows(rows, start, end) {
|
|
1248
|
+
let totalInputTokens = 0;
|
|
1249
|
+
let totalOutputTokens = 0;
|
|
1250
|
+
let totalCost = 0;
|
|
1251
|
+
const byModelMap = /* @__PURE__ */ new Map();
|
|
1252
|
+
for (const row of rows) {
|
|
1253
|
+
const ts = new Date(row.created_at);
|
|
1254
|
+
if (ts < start || ts > end) continue;
|
|
1255
|
+
totalInputTokens += row.input_tokens;
|
|
1256
|
+
totalOutputTokens += row.output_tokens;
|
|
1257
|
+
totalCost += row.base_cost;
|
|
1258
|
+
const existing = byModelMap.get(row.model);
|
|
1259
|
+
if (existing) {
|
|
1260
|
+
existing.inputTokens += row.input_tokens;
|
|
1261
|
+
existing.outputTokens += row.output_tokens;
|
|
1262
|
+
existing.cost += row.base_cost;
|
|
1263
|
+
} else {
|
|
1264
|
+
byModelMap.set(row.model, {
|
|
1265
|
+
inputTokens: row.input_tokens,
|
|
1266
|
+
outputTokens: row.output_tokens,
|
|
1267
|
+
cost: row.base_cost
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
const byModel = Array.from(byModelMap.entries()).map(([model, stats]) => ({ model, ...stats })).sort((a, b) => b.cost - a.cost);
|
|
1272
|
+
return { totalInputTokens, totalOutputTokens, totalCost, byModel };
|
|
1273
|
+
}
|
|
1274
|
+
async function showUsageDetails(options = {}) {
|
|
1275
|
+
const { pauseForInput = false } = options;
|
|
1094
1276
|
console.log(chalk.bold("\n-- Usage Details --\n"));
|
|
1095
1277
|
const spinner = ora("Loading usage data...").start();
|
|
1096
1278
|
const config = await loadConfig();
|
|
@@ -1112,84 +1294,49 @@ async function showUsageDetails() {
|
|
|
1112
1294
|
}
|
|
1113
1295
|
const data = await response.json();
|
|
1114
1296
|
if (data.tier === "BYOK") {
|
|
1115
|
-
|
|
1297
|
+
const ids = await resolveAuthAndProfileIds(authToken, authId);
|
|
1298
|
+
if (!ids.authId || !ids.profileId) {
|
|
1116
1299
|
console.log(chalk.yellow("Unable to resolve user ID for usage details."));
|
|
1117
1300
|
return;
|
|
1118
1301
|
}
|
|
1119
|
-
const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
|
|
1120
|
-
const { data: profileRow, error: profileError } = await supabase.from("user_profiles").select("id").eq("auth_id", authId).single();
|
|
1121
|
-
if (profileError || !profileRow?.id) {
|
|
1122
|
-
console.log(chalk.yellow("Unable to resolve profile for usage details."));
|
|
1123
|
-
return;
|
|
1124
|
-
}
|
|
1125
|
-
const profileId = profileRow.id;
|
|
1126
1302
|
const now = /* @__PURE__ */ new Date();
|
|
1127
1303
|
const yearStart = new Date(now.getFullYear(), 0, 1);
|
|
1128
|
-
const
|
|
1129
|
-
if (
|
|
1304
|
+
const usageRows = await fetchUsageRows(authToken, ids.profileId, yearStart.toISOString(), now.toISOString());
|
|
1305
|
+
if (!usageRows) {
|
|
1130
1306
|
console.log(chalk.yellow("Unable to fetch BYOK usage data."));
|
|
1131
1307
|
return;
|
|
1132
1308
|
}
|
|
1133
|
-
const rows = usageRows;
|
|
1134
1309
|
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
1135
|
-
const
|
|
1136
|
-
const
|
|
1310
|
+
const startOf24h = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
|
|
1311
|
+
const startOf7d = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
|
|
1312
|
+
const startOf30d = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
|
|
1137
1313
|
const periods = [
|
|
1138
1314
|
{ label: "Today", start: startOfToday, end: now },
|
|
1139
|
-
{ label: "
|
|
1140
|
-
{ label: "
|
|
1315
|
+
{ label: "Last 24 Hours", start: startOf24h, end: now },
|
|
1316
|
+
{ label: "Last 7 Days", start: startOf7d, end: now },
|
|
1317
|
+
{ label: "Last 30 Days", start: startOf30d, end: now },
|
|
1141
1318
|
{ label: "Year to Date", start: yearStart, end: now }
|
|
1142
1319
|
];
|
|
1143
|
-
const aggregate = (start, end) => {
|
|
1144
|
-
let totalInputTokens = 0;
|
|
1145
|
-
let totalOutputTokens = 0;
|
|
1146
|
-
let totalCost = 0;
|
|
1147
|
-
const byModelMap = /* @__PURE__ */ new Map();
|
|
1148
|
-
for (const row of rows) {
|
|
1149
|
-
const ts = new Date(row.created_at);
|
|
1150
|
-
if (ts < start || ts > end) continue;
|
|
1151
|
-
totalInputTokens += row.input_tokens;
|
|
1152
|
-
totalOutputTokens += row.output_tokens;
|
|
1153
|
-
totalCost += row.base_cost;
|
|
1154
|
-
const existing = byModelMap.get(row.model);
|
|
1155
|
-
if (existing) {
|
|
1156
|
-
existing.inputTokens += row.input_tokens;
|
|
1157
|
-
existing.outputTokens += row.output_tokens;
|
|
1158
|
-
existing.cost += row.base_cost;
|
|
1159
|
-
} else {
|
|
1160
|
-
byModelMap.set(row.model, {
|
|
1161
|
-
inputTokens: row.input_tokens,
|
|
1162
|
-
outputTokens: row.output_tokens,
|
|
1163
|
-
cost: row.base_cost
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
const byModel = Array.from(byModelMap.entries()).map(([model, stats]) => ({ model, ...stats })).sort((a, b) => b.cost - a.cost);
|
|
1168
|
-
return { totalInputTokens, totalOutputTokens, totalCost, byModel };
|
|
1169
|
-
};
|
|
1170
1320
|
console.log(chalk.blue("BYOK Usage (local time):"));
|
|
1321
|
+
console.log(chalk.dim("Estimated provider spend by model (you are billed directly by provider)."));
|
|
1171
1322
|
for (const period of periods) {
|
|
1172
|
-
const summary =
|
|
1323
|
+
const summary = aggregateUsageRows(usageRows, period.start, period.end);
|
|
1173
1324
|
console.log();
|
|
1174
1325
|
console.log(chalk.bold(`${period.label}:`));
|
|
1175
1326
|
console.log(` ${period.start.toLocaleDateString()} \u2192 ${period.end.toLocaleDateString()}`);
|
|
1176
1327
|
console.log(` Tokens: ${formatTokens(summary.totalInputTokens + summary.totalOutputTokens)} (in ${formatTokens(summary.totalInputTokens)} / out ${formatTokens(summary.totalOutputTokens)})`);
|
|
1177
|
-
console.log(`
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
for (const model of summary.byModel) {
|
|
1181
|
-
const modelInfo = findModel(model.model);
|
|
1182
|
-
const name = modelInfo?.name ?? model.model;
|
|
1183
|
-
const tokenTotal = model.inputTokens + model.outputTokens;
|
|
1184
|
-
console.log(` ${name}: ${formatTokens(tokenTotal)} tokens (${formatCost(model.cost)})`);
|
|
1185
|
-
}
|
|
1186
|
-
} else {
|
|
1187
|
-
console.log(chalk.dim(" No usage recorded."));
|
|
1188
|
-
}
|
|
1328
|
+
console.log(` Estimated Spend: ${formatCost(summary.totalCost)} ${chalk.dim("(paid directly to provider)")}`);
|
|
1329
|
+
console.log(chalk.dim(" By Model:"));
|
|
1330
|
+
renderModelBreakdown(summary.byModel, { indent: " " });
|
|
1189
1331
|
}
|
|
1190
1332
|
} else {
|
|
1191
|
-
|
|
1192
|
-
|
|
1333
|
+
const periodLabel = formatUsagePeriodLabel(data.periodSource);
|
|
1334
|
+
const byModel = [...data.byModel ?? []].sort((a, b) => b.cost - a.cost);
|
|
1335
|
+
const modelBilledTotal = sumModelCost(byModel);
|
|
1336
|
+
const modelBaseTotal = data.totalBaseCost;
|
|
1337
|
+
const modelFeeTotal = Math.max(0, modelBilledTotal - modelBaseTotal);
|
|
1338
|
+
console.log(chalk.blue(`${periodLabel}:`));
|
|
1339
|
+
console.log(` ${formatLocalDateTime(data.periodStart)} \u2192 ${formatLocalDateTime(data.periodEnd)}`);
|
|
1193
1340
|
console.log();
|
|
1194
1341
|
console.log(chalk.blue("Token Usage:"));
|
|
1195
1342
|
console.log(` Input: ${formatTokens(data.totalInputTokens)} tokens`);
|
|
@@ -1197,24 +1344,29 @@ async function showUsageDetails() {
|
|
|
1197
1344
|
console.log(` Total: ${formatTokens(data.totalInputTokens + data.totalOutputTokens)} tokens`);
|
|
1198
1345
|
console.log();
|
|
1199
1346
|
console.log(chalk.blue("Cost:"));
|
|
1200
|
-
console.log(` Base Cost: ${formatCost(data.totalBaseCost)}`);
|
|
1201
1347
|
if (data.tier === "CREDITS") {
|
|
1202
|
-
|
|
1203
|
-
console.log(`
|
|
1348
|
+
console.log(` Base Model Cost: ${formatCost(modelBaseTotal)}`);
|
|
1349
|
+
console.log(` Platform Fee: ${formatCost(modelFeeTotal)}`);
|
|
1350
|
+
console.log(` Credits Deducted:${formatCost(modelBilledTotal)}`);
|
|
1351
|
+
} else {
|
|
1352
|
+
console.log(` Estimated Cost: ${formatCost(modelBaseTotal)}`);
|
|
1204
1353
|
}
|
|
1205
|
-
if (
|
|
1354
|
+
if (byModel.length > 0) {
|
|
1206
1355
|
console.log();
|
|
1207
1356
|
console.log(chalk.blue("By Model:"));
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1357
|
+
renderModelBreakdown(
|
|
1358
|
+
byModel.map((row) => ({
|
|
1359
|
+
model: row.model,
|
|
1360
|
+
inputTokens: row.inputTokens,
|
|
1361
|
+
outputTokens: row.outputTokens,
|
|
1362
|
+
cost: row.cost
|
|
1363
|
+
}))
|
|
1364
|
+
);
|
|
1213
1365
|
}
|
|
1214
1366
|
if (data.byOperation && data.byOperation.length > 0) {
|
|
1215
1367
|
console.log();
|
|
1216
1368
|
console.log(chalk.blue("By Operation:"));
|
|
1217
|
-
for (const stats of data.byOperation) {
|
|
1369
|
+
for (const stats of [...data.byOperation].sort((a, b) => b.cost - a.cost)) {
|
|
1218
1370
|
console.log(` ${stats.operation}: ${formatTokens(stats.tokenCount)} tokens (${formatCost(stats.cost)})`);
|
|
1219
1371
|
}
|
|
1220
1372
|
}
|
|
@@ -1223,8 +1375,12 @@ async function showUsageDetails() {
|
|
|
1223
1375
|
spinner.stop();
|
|
1224
1376
|
console.log(chalk.yellow("Error fetching usage data."));
|
|
1225
1377
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1378
|
+
if (pauseForInput) {
|
|
1379
|
+
console.log();
|
|
1380
|
+
await prompt("Press Enter to continue");
|
|
1381
|
+
} else {
|
|
1382
|
+
console.log();
|
|
1383
|
+
}
|
|
1228
1384
|
}
|
|
1229
1385
|
|
|
1230
1386
|
export {
|
|
@@ -1236,5 +1392,6 @@ export {
|
|
|
1236
1392
|
resetPreferences,
|
|
1237
1393
|
listModels,
|
|
1238
1394
|
interactiveSettings,
|
|
1395
|
+
__preferencesChoiceHelpers,
|
|
1239
1396
|
showUsageDetails
|
|
1240
1397
|
};
|