archondev 2.19.56 → 3.0.0
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/README.md +63 -47
- package/dist/{auth-XRKCCFJ3.js → auth-T4C7OQWO.js} +1 -1
- package/dist/{chunk-F3DZZHZB.js → chunk-43IIEFB2.js} +1 -1
- package/dist/{chunk-4K3XNRU6.js → chunk-45T2VB5R.js} +14 -4
- package/dist/{chunk-6TBYNRNF.js → chunk-57NSGWWD.js} +9 -7
- package/dist/{chunk-OHIN6OHU.js → chunk-7RXZTPXY.js} +14 -4
- package/dist/chunk-AJNKSFHL.js +491 -0
- package/dist/chunk-I3BBA7MB.js +150 -0
- package/dist/{chunk-L6VHJQ6M.js → chunk-PQS3TQB6.js} +128 -379
- package/dist/{chunk-LU4DXW3J.js → chunk-YK5Z6U5A.js} +489 -100
- package/dist/{execute-C3NFIEEI.js → execute-HWUL2M3B.js} +3 -3
- package/dist/index.js +1876 -1721
- package/dist/{list-ULMKVK7D.js → list-7IBMJCCF.js} +3 -3
- package/dist/{parallel-T37FF7GD.js → parallel-4PXJA2QD.js} +3 -3
- package/dist/{plan-WBNGP2UE.js → plan-HBAUG3KD.js} +2 -2
- package/dist/{preferences-PELPR2MO.js → preferences-VVFGRNPD.js} +2 -6
- package/dist/ship-KHL6NVC2.js +7 -0
- package/package.json +1 -1
- package/dist/chunk-R664NEAA.js +0 -66
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createAuthedSupabaseClient
|
|
3
|
-
} from "./chunk-Q3GIFHIQ.js";
|
|
4
1
|
import {
|
|
5
2
|
debugLog,
|
|
6
|
-
getDebugLogPath
|
|
7
|
-
|
|
3
|
+
getDebugLogPath,
|
|
4
|
+
summarizeLocalUsage
|
|
5
|
+
} from "./chunk-I3BBA7MB.js";
|
|
8
6
|
import {
|
|
9
7
|
findModel,
|
|
10
8
|
getAllActiveModels,
|
|
@@ -20,16 +18,8 @@ import {
|
|
|
20
18
|
keyManager
|
|
21
19
|
} from "./chunk-RDG5BUED.js";
|
|
22
20
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import {
|
|
26
|
-
SUPABASE_ANON_KEY,
|
|
27
|
-
SUPABASE_URL
|
|
28
|
-
} from "./chunk-M4LGRTLC.js";
|
|
29
|
-
import {
|
|
30
|
-
getApiUrl,
|
|
31
|
-
getAuthToken,
|
|
32
|
-
loadConfig
|
|
21
|
+
loadConfig,
|
|
22
|
+
saveConfig
|
|
33
23
|
} from "./chunk-GGRW4NTA.js";
|
|
34
24
|
|
|
35
25
|
// src/cli/preferences.ts
|
|
@@ -414,24 +404,24 @@ var SmartModelRouter = class {
|
|
|
414
404
|
|
|
415
405
|
// src/cli/preferences.ts
|
|
416
406
|
var PREF_KEYS = ["fast-model", "thinking-model", "primary-adversarial", "secondary-adversarial"];
|
|
417
|
-
function
|
|
407
|
+
function prefKeyToConfigField(key) {
|
|
418
408
|
const map = {
|
|
419
|
-
"fast-model": "
|
|
420
|
-
"thinking-model": "
|
|
421
|
-
"primary-adversarial": "
|
|
422
|
-
"secondary-adversarial": "
|
|
409
|
+
"fast-model": "fastModel",
|
|
410
|
+
"thinking-model": "thinkingModel",
|
|
411
|
+
"primary-adversarial": "primaryAdversarialModel",
|
|
412
|
+
"secondary-adversarial": "secondaryAdversarialModel"
|
|
423
413
|
};
|
|
424
414
|
return map[key];
|
|
425
415
|
}
|
|
426
416
|
function isPrefKey(key) {
|
|
427
417
|
return PREF_KEYS.includes(key);
|
|
428
418
|
}
|
|
429
|
-
function
|
|
419
|
+
function tierPrefKeyToConfigField(key) {
|
|
430
420
|
const map = {
|
|
431
|
-
"planning-model": "
|
|
432
|
-
"reasoning-model": "
|
|
433
|
-
"execution-model": "
|
|
434
|
-
"provider": "
|
|
421
|
+
"planning-model": "planningModel",
|
|
422
|
+
"reasoning-model": "reasoningModel",
|
|
423
|
+
"execution-model": "executionModel",
|
|
424
|
+
"provider": "preferredProvider"
|
|
435
425
|
};
|
|
436
426
|
return map[key];
|
|
437
427
|
}
|
|
@@ -475,24 +465,20 @@ async function setExecutionPreference(key, value, cwd = process.cwd()) {
|
|
|
475
465
|
if (!existing.execution) {
|
|
476
466
|
existing.execution = {};
|
|
477
467
|
}
|
|
478
|
-
const validKeys = ["parallel.mode", "
|
|
468
|
+
const validKeys = ["parallel.mode", "max-parallel-agents"];
|
|
479
469
|
if (!validKeys.includes(key)) {
|
|
480
470
|
console.error(chalk.red(`Invalid execution preference key: ${key}`));
|
|
481
471
|
console.log(chalk.dim(`Valid keys: ${validKeys.join(", ")}`));
|
|
482
472
|
process.exit(1);
|
|
483
473
|
}
|
|
484
|
-
if (key === "parallel.mode"
|
|
474
|
+
if (key === "parallel.mode") {
|
|
485
475
|
const validModes = ["always", "ask", "never"];
|
|
486
476
|
if (!validModes.includes(value)) {
|
|
487
477
|
console.error(chalk.red(`Invalid value: ${value}`));
|
|
488
478
|
console.log(chalk.dim(`Valid values: ${validModes.join(", ")}`));
|
|
489
479
|
process.exit(1);
|
|
490
480
|
}
|
|
491
|
-
|
|
492
|
-
existing.execution.parallelMode = value;
|
|
493
|
-
} else {
|
|
494
|
-
existing.execution.cloudMode = value;
|
|
495
|
-
}
|
|
481
|
+
existing.execution.parallelMode = value;
|
|
496
482
|
} else if (key === "max-parallel-agents") {
|
|
497
483
|
const num = parseInt(value, 10);
|
|
498
484
|
if (isNaN(num) || num < 1 || num > 10) {
|
|
@@ -510,57 +496,25 @@ async function showExecutionPreferences(cwd = process.cwd()) {
|
|
|
510
496
|
console.log(chalk.green("Execution Preferences:"));
|
|
511
497
|
console.log();
|
|
512
498
|
console.log(` ${chalk.blue("Parallel Mode:")} ${prefs.parallelMode}`);
|
|
513
|
-
console.log(` ${chalk.blue("Cloud Mode:")} ${prefs.cloudMode}`);
|
|
514
499
|
console.log(` ${chalk.blue("Max Parallel Agents:")} ${prefs.maxParallelAgents}`);
|
|
515
500
|
}
|
|
516
501
|
async function fetchPreferences() {
|
|
517
502
|
const config = await loadConfig();
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const response = await fetch(`${apiUrl}/api/preferences`, {
|
|
525
|
-
headers: {
|
|
526
|
-
"Authorization": `Bearer ${authToken}`
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
if (!response.ok) {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
const data = await response.json();
|
|
533
|
-
return {
|
|
534
|
-
fastModel: data.pref_fast_model,
|
|
535
|
-
thinkingModel: data.pref_thinking_model,
|
|
536
|
-
primaryAdversarial: data.pref_primary_adversarial,
|
|
537
|
-
secondaryAdversarial: data.pref_secondary_adversarial
|
|
538
|
-
};
|
|
539
|
-
} catch {
|
|
540
|
-
return null;
|
|
541
|
-
}
|
|
503
|
+
return {
|
|
504
|
+
fastModel: config.fastModel ?? null,
|
|
505
|
+
thinkingModel: config.thinkingModel ?? null,
|
|
506
|
+
primaryAdversarial: config.primaryAdversarialModel ?? null,
|
|
507
|
+
secondaryAdversarial: config.secondaryAdversarialModel ?? null
|
|
508
|
+
};
|
|
542
509
|
}
|
|
543
510
|
async function updatePreference(key, value) {
|
|
544
|
-
const config = await loadConfig();
|
|
545
|
-
const authToken = getAuthToken(config);
|
|
546
|
-
if (!authToken) {
|
|
547
|
-
return { success: false, error: "Not logged in. Run: archon login" };
|
|
548
|
-
}
|
|
549
|
-
const apiUrl = getApiUrl(config);
|
|
550
|
-
const column = prefKeyToDbColumn(key);
|
|
551
511
|
try {
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
},
|
|
558
|
-
body: JSON.stringify({ [column]: value })
|
|
512
|
+
const config = await loadConfig();
|
|
513
|
+
const field = prefKeyToConfigField(key);
|
|
514
|
+
await saveConfig({
|
|
515
|
+
...config,
|
|
516
|
+
[field]: value ?? void 0
|
|
559
517
|
});
|
|
560
|
-
if (!response.ok) {
|
|
561
|
-
const text = await response.text();
|
|
562
|
-
return { success: false, error: text };
|
|
563
|
-
}
|
|
564
518
|
return { success: true };
|
|
565
519
|
} catch (err) {
|
|
566
520
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -689,54 +643,42 @@ async function listModels() {
|
|
|
689
643
|
}
|
|
690
644
|
async function fetchUserProfile() {
|
|
691
645
|
const config = await loadConfig();
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
}
|
|
646
|
+
return {
|
|
647
|
+
tier: config.tier ?? "FREE",
|
|
648
|
+
pref_fast_model: config.fastModel ?? null,
|
|
649
|
+
pref_thinking_model: config.thinkingModel ?? null,
|
|
650
|
+
pref_primary_adversarial: config.primaryAdversarialModel ?? null,
|
|
651
|
+
pref_secondary_adversarial: config.secondaryAdversarialModel ?? null,
|
|
652
|
+
pref_planning_model: config.planningModel ?? null,
|
|
653
|
+
pref_reasoning_model: config.reasoningModel ?? null,
|
|
654
|
+
pref_execution_model: config.executionModel ?? null,
|
|
655
|
+
pref_provider: config.preferredProvider ?? null
|
|
656
|
+
};
|
|
704
657
|
}
|
|
705
658
|
async function fetchUsageSummary() {
|
|
706
|
-
const config = await loadConfig();
|
|
707
|
-
const authToken = getAuthToken(config);
|
|
708
|
-
if (!authToken) return null;
|
|
709
|
-
const apiUrl = getApiUrl(config);
|
|
710
659
|
try {
|
|
711
|
-
const
|
|
712
|
-
|
|
660
|
+
const now = /* @__PURE__ */ new Date();
|
|
661
|
+
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
662
|
+
const summary = await summarizeLocalUsage({
|
|
663
|
+
start: monthStart,
|
|
664
|
+
end: now
|
|
713
665
|
});
|
|
714
|
-
|
|
715
|
-
|
|
666
|
+
return {
|
|
667
|
+
totalInputTokens: summary.totalInputTokens,
|
|
668
|
+
totalOutputTokens: summary.totalOutputTokens,
|
|
669
|
+
totalBaseCost: summary.totalBaseCost,
|
|
670
|
+
totalMarkedUpCost: summary.totalBaseCost,
|
|
671
|
+
periodStart: monthStart.toISOString(),
|
|
672
|
+
periodEnd: now.toISOString()
|
|
673
|
+
};
|
|
716
674
|
} catch {
|
|
717
675
|
return null;
|
|
718
676
|
}
|
|
719
677
|
}
|
|
720
678
|
async function updateUserTier(tier) {
|
|
721
|
-
const config = await loadConfig();
|
|
722
|
-
const authToken = getAuthToken(config);
|
|
723
|
-
if (!authToken) {
|
|
724
|
-
return { success: false, error: "Not logged in" };
|
|
725
|
-
}
|
|
726
|
-
const apiUrl = getApiUrl(config);
|
|
727
679
|
try {
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
headers: {
|
|
731
|
-
"Authorization": `Bearer ${authToken}`,
|
|
732
|
-
"Content-Type": "application/json"
|
|
733
|
-
},
|
|
734
|
-
body: JSON.stringify({ tier })
|
|
735
|
-
});
|
|
736
|
-
if (!response.ok) {
|
|
737
|
-
const text = await response.text();
|
|
738
|
-
return { success: false, error: text };
|
|
739
|
-
}
|
|
680
|
+
const config = await loadConfig();
|
|
681
|
+
await saveConfig({ ...config, tier, tierConfirmed: true });
|
|
740
682
|
return { success: true };
|
|
741
683
|
} catch (err) {
|
|
742
684
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -755,23 +697,6 @@ function prompt(question) {
|
|
|
755
697
|
});
|
|
756
698
|
});
|
|
757
699
|
}
|
|
758
|
-
function promptYesNo(question, defaultValue) {
|
|
759
|
-
return new Promise((resolve) => {
|
|
760
|
-
const rl = readline.createInterface({
|
|
761
|
-
input: process.stdin,
|
|
762
|
-
output: process.stdout
|
|
763
|
-
});
|
|
764
|
-
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
765
|
-
rl.question(`${chalk.cyan("?")} ${question} ${hint}: `, (answer) => {
|
|
766
|
-
rl.close();
|
|
767
|
-
if (answer.trim() === "") {
|
|
768
|
-
resolve(defaultValue);
|
|
769
|
-
} else {
|
|
770
|
-
resolve(answer.toLowerCase().startsWith("y"));
|
|
771
|
-
}
|
|
772
|
-
});
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
700
|
function formatCost(dollars) {
|
|
776
701
|
if (dollars < 0.01) {
|
|
777
702
|
return `$${dollars.toFixed(4)}`;
|
|
@@ -797,18 +722,13 @@ async function interactiveSettings() {
|
|
|
797
722
|
]);
|
|
798
723
|
spinner.stop();
|
|
799
724
|
if (!profile) {
|
|
800
|
-
console.log(chalk.yellow("
|
|
801
|
-
const shouldLogin = await promptYesNo("Would you like to login now?", true);
|
|
802
|
-
if (shouldLogin) {
|
|
803
|
-
await login("github");
|
|
804
|
-
await interactiveSettings();
|
|
805
|
-
}
|
|
725
|
+
console.log(chalk.yellow("Unable to load local settings.\n"));
|
|
806
726
|
return;
|
|
807
727
|
}
|
|
808
728
|
await displayCurrentSettings(profile, usage, providers);
|
|
809
729
|
console.log(chalk.bold("\nOptions:\n"));
|
|
810
730
|
console.log(chalk.dim("Type naturally (recommended) or use a shortcut:\n"));
|
|
811
|
-
console.log(` ${chalk.cyan("1")}) Change
|
|
731
|
+
console.log(` ${chalk.cyan("1")}) Change AI mode (Local governance / BYOK)`);
|
|
812
732
|
console.log(` ${chalk.cyan("2")}) Set default models`);
|
|
813
733
|
console.log(` ${chalk.cyan("x")}) Smart Routing (cost optimization)`);
|
|
814
734
|
console.log(` ${chalk.cyan("3")}) Manage API keys`);
|
|
@@ -853,8 +773,8 @@ async function interactiveSettings() {
|
|
|
853
773
|
}
|
|
854
774
|
async function displayCurrentSettings(profile, usage, providers) {
|
|
855
775
|
const defaults = getDefaultAdversarialModels();
|
|
856
|
-
const tierDisplay = profile.tier === "BYOK" ? chalk.cyan("BYOK (
|
|
857
|
-
console.log(chalk.blue("
|
|
776
|
+
const tierDisplay = profile.tier === "BYOK" ? chalk.cyan("BYOK (your provider keys)") : chalk.dim("Local governance only");
|
|
777
|
+
console.log(chalk.blue("AI Mode:"), tierDisplay);
|
|
858
778
|
if (providers.length > 0) {
|
|
859
779
|
console.log(chalk.blue("API Keys:"), providers.map((p) => chalk.green(p)).join(", "));
|
|
860
780
|
} else {
|
|
@@ -864,14 +784,9 @@ async function displayCurrentSettings(profile, usage, providers) {
|
|
|
864
784
|
console.log();
|
|
865
785
|
console.log(chalk.blue("Current Period Usage:"));
|
|
866
786
|
console.log(` Tokens: ${chalk.white(formatTokens(usage.totalInputTokens))} in / ${chalk.white(formatTokens(usage.totalOutputTokens))} out`);
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
console.log(
|
|
870
|
-
} else {
|
|
871
|
-
console.log(` Estimated Cost: ${chalk.white(formatCost(usage.totalBaseCost))}`);
|
|
872
|
-
if (profile.tier === "BYOK") {
|
|
873
|
-
console.log(chalk.dim(" (You pay your provider directly)"));
|
|
874
|
-
}
|
|
787
|
+
console.log(` Estimated Cost: ${chalk.white(formatCost(usage.totalBaseCost))}`);
|
|
788
|
+
if (profile.tier === "BYOK") {
|
|
789
|
+
console.log(chalk.dim(" (You pay your provider directly)"));
|
|
875
790
|
}
|
|
876
791
|
}
|
|
877
792
|
console.log();
|
|
@@ -882,40 +797,40 @@ async function displayCurrentSettings(profile, usage, providers) {
|
|
|
882
797
|
console.log(` Secondary: ${formatModelDisplay(profile.pref_secondary_adversarial, defaults.secondary)}`);
|
|
883
798
|
}
|
|
884
799
|
async function changeBillingMode(currentTier) {
|
|
885
|
-
console.log(chalk.bold("\n--
|
|
886
|
-
console.log(chalk.dim("Choose
|
|
800
|
+
console.log(chalk.bold("\n-- AI Mode --\n"));
|
|
801
|
+
console.log(chalk.dim("Choose whether Archon should stay governance-only or use your provider keys.\n"));
|
|
802
|
+
const freeSelected = currentTier !== "BYOK";
|
|
887
803
|
const byokSelected = currentTier === "BYOK";
|
|
888
|
-
|
|
889
|
-
console.log(
|
|
804
|
+
console.log(` ${chalk.cyan("1")}) ${freeSelected ? chalk.green("\u25CF ") : "\u25CB "}Local governance only`);
|
|
805
|
+
console.log(chalk.dim(" Plan, review, and govern locally without making provider AI calls.\n"));
|
|
806
|
+
console.log(` ${chalk.cyan("2")}) ${byokSelected ? chalk.green("\u25CF ") : "\u25CB "}BYOK - Bring Your Own Key`);
|
|
890
807
|
console.log(chalk.dim(" Use your own API keys. You pay providers directly."));
|
|
891
|
-
console.log(chalk.dim("
|
|
892
|
-
console.log(` ${chalk.cyan("2")}) ${creditsSelected ? chalk.green("\u25CF ") : "\u25CB "}Credits - Pay via ArchonDev`);
|
|
893
|
-
console.log(chalk.dim(" We handle API access. Pay only for what you use."));
|
|
894
|
-
console.log(chalk.dim(" 10% service fee applied.\n"));
|
|
808
|
+
console.log(chalk.dim(" Archon keeps a local usage ledger for transparency.\n"));
|
|
895
809
|
console.log(` ${chalk.cyan("b")}) Back`);
|
|
896
810
|
console.log();
|
|
897
|
-
const rawChoice = await prompt("
|
|
811
|
+
const rawChoice = await prompt("Which AI mode do you want?");
|
|
898
812
|
const choice = resolveBillingChoice(rawChoice);
|
|
899
|
-
if (choice === "1" && !
|
|
900
|
-
const spinner = ora("Switching to
|
|
901
|
-
const result = await updateUserTier("
|
|
813
|
+
if (choice === "1" && !freeSelected) {
|
|
814
|
+
const spinner = ora("Switching to local governance mode...").start();
|
|
815
|
+
const result = await updateUserTier("FREE");
|
|
902
816
|
if (result.success) {
|
|
903
|
-
spinner.succeed(chalk.green("Switched to
|
|
904
|
-
console.log(chalk.dim("Add
|
|
817
|
+
spinner.succeed(chalk.green("Switched to local governance mode"));
|
|
818
|
+
console.log(chalk.dim("Add provider keys anytime with: archon config ai"));
|
|
905
819
|
} else {
|
|
906
820
|
spinner.fail(chalk.red(result.error ?? "Failed to update"));
|
|
907
821
|
}
|
|
908
|
-
} else if (choice === "2" && !
|
|
909
|
-
const spinner = ora("Switching to
|
|
910
|
-
const result = await updateUserTier("
|
|
822
|
+
} else if (choice === "2" && !byokSelected) {
|
|
823
|
+
const spinner = ora("Switching to BYOK...").start();
|
|
824
|
+
const result = await updateUserTier("BYOK");
|
|
911
825
|
if (result.success) {
|
|
912
|
-
spinner.succeed(chalk.green("Switched to
|
|
826
|
+
spinner.succeed(chalk.green("Switched to BYOK mode"));
|
|
827
|
+
console.log(chalk.dim("Add API keys with: archon keys add <provider>"));
|
|
913
828
|
} else {
|
|
914
829
|
spinner.fail(chalk.red(result.error ?? "Failed to update"));
|
|
915
830
|
}
|
|
916
831
|
} else if (choice !== "b") {
|
|
917
|
-
if (choice === "1" &&
|
|
918
|
-
console.log(chalk.dim("Already using this
|
|
832
|
+
if (choice === "1" && freeSelected || choice === "2" && byokSelected) {
|
|
833
|
+
console.log(chalk.dim("Already using this AI mode."));
|
|
919
834
|
} else {
|
|
920
835
|
console.log(chalk.yellow("I did not catch that."));
|
|
921
836
|
}
|
|
@@ -948,11 +863,9 @@ async function setDefaultModelsMenu(profile, providers) {
|
|
|
948
863
|
return;
|
|
949
864
|
}
|
|
950
865
|
const models = getAllActiveModels();
|
|
951
|
-
const availableModels = models.filter(
|
|
952
|
-
(m) => providers.includes(m.provider) || profile.tier === "CREDITS"
|
|
953
|
-
);
|
|
866
|
+
const availableModels = models.filter((m) => providers.includes(m.provider));
|
|
954
867
|
if (availableModels.length === 0) {
|
|
955
|
-
console.log(chalk.yellow("\nNo models available. Add
|
|
868
|
+
console.log(chalk.yellow("\nNo models available. Add at least one provider API key first."));
|
|
956
869
|
return;
|
|
957
870
|
}
|
|
958
871
|
console.log(chalk.bold("\nAvailable models:\n"));
|
|
@@ -1038,11 +951,9 @@ async function setSmartRoutingMenu(profile, providers) {
|
|
|
1038
951
|
const selectedTier = tiers[tierIndex];
|
|
1039
952
|
if (!selectedTier) return;
|
|
1040
953
|
const models = getAllActiveModels();
|
|
1041
|
-
const availableModels = models.filter(
|
|
1042
|
-
(m) => providers.includes(m.provider) || profile.tier === "CREDITS"
|
|
1043
|
-
);
|
|
954
|
+
const availableModels = models.filter((m) => providers.includes(m.provider));
|
|
1044
955
|
if (availableModels.length === 0) {
|
|
1045
|
-
console.log(chalk.yellow("\nNo models available. Add
|
|
956
|
+
console.log(chalk.yellow("\nNo models available. Add at least one provider API key first."));
|
|
1046
957
|
return;
|
|
1047
958
|
}
|
|
1048
959
|
console.log(chalk.bold(`
|
|
@@ -1071,28 +982,14 @@ Select model for ${selectedTier.tier} tier:
|
|
|
1071
982
|
}
|
|
1072
983
|
}
|
|
1073
984
|
async function setTierPreference(key, value) {
|
|
1074
|
-
const config = await loadConfig();
|
|
1075
|
-
const token = getAuthToken(config);
|
|
1076
|
-
if (!token) {
|
|
1077
|
-
console.error(chalk.red("Not logged in. Run: archon auth login"));
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
985
|
const spinner = ora(`Updating ${key}...`).start();
|
|
1081
986
|
try {
|
|
1082
|
-
const
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
"Content-Type": "application/json",
|
|
1088
|
-
"Authorization": `Bearer ${token}`
|
|
1089
|
-
},
|
|
1090
|
-
body: JSON.stringify({ [dbColumn]: value })
|
|
987
|
+
const config = await loadConfig();
|
|
988
|
+
const field = tierPrefKeyToConfigField(key);
|
|
989
|
+
await saveConfig({
|
|
990
|
+
...config,
|
|
991
|
+
[field]: value ?? void 0
|
|
1091
992
|
});
|
|
1092
|
-
if (!response.ok) {
|
|
1093
|
-
const error = await response.text();
|
|
1094
|
-
throw new Error(error || "Failed to update preference");
|
|
1095
|
-
}
|
|
1096
993
|
spinner.succeed(chalk.green(`Set ${key} = ${value || "(auto)"}`));
|
|
1097
994
|
} catch (error) {
|
|
1098
995
|
spinner.fail(chalk.red(`Failed to update: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
@@ -1165,8 +1062,8 @@ function resolveSettingsChoice(input) {
|
|
|
1165
1062
|
function resolveBillingChoice(input) {
|
|
1166
1063
|
const normalized = input.trim().toLowerCase();
|
|
1167
1064
|
if (!normalized) return "";
|
|
1168
|
-
if (normalized === "1" || normalized.includes("
|
|
1169
|
-
if (normalized === "2" || normalized.includes("
|
|
1065
|
+
if (normalized === "1" || normalized.includes("free") || normalized.includes("local") || normalized.includes("governance")) return "1";
|
|
1066
|
+
if (normalized === "2" || normalized.includes("byok") || normalized.includes("own key")) return "2";
|
|
1170
1067
|
if (normalized === "b" || normalized.includes("back")) return "b";
|
|
1171
1068
|
return normalized;
|
|
1172
1069
|
}
|
|
@@ -1237,21 +1134,6 @@ var __preferencesChoiceHelpers = {
|
|
|
1237
1134
|
resolveProviderIndexChoice,
|
|
1238
1135
|
resolveModelChoice
|
|
1239
1136
|
};
|
|
1240
|
-
function formatLocalDateTime(value) {
|
|
1241
|
-
const date = new Date(value);
|
|
1242
|
-
if (isNaN(date.getTime())) {
|
|
1243
|
-
return value;
|
|
1244
|
-
}
|
|
1245
|
-
return date.toLocaleString();
|
|
1246
|
-
}
|
|
1247
|
-
function formatUsagePeriodLabel(periodSource) {
|
|
1248
|
-
if (periodSource === "credit_purchase") return "Since last top-up";
|
|
1249
|
-
if (periodSource === "month") return "Current month to date";
|
|
1250
|
-
return "Current billing period";
|
|
1251
|
-
}
|
|
1252
|
-
function sumModelCost(byModel) {
|
|
1253
|
-
return (byModel ?? []).reduce((sum, row) => sum + row.cost, 0);
|
|
1254
|
-
}
|
|
1255
1137
|
function renderModelBreakdown(rows, options = {}) {
|
|
1256
1138
|
const indent = options.indent ?? " ";
|
|
1257
1139
|
if (rows.length === 0) {
|
|
@@ -1269,62 +1151,6 @@ function renderModelBreakdown(rows, options = {}) {
|
|
|
1269
1151
|
console.log(`${indent}${name}: ${formatTokens(tokenTotal)} tokens | ${formatCost(row.cost)} (${share}%)${note}`);
|
|
1270
1152
|
}
|
|
1271
1153
|
}
|
|
1272
|
-
async function resolveAuthAndProfileIds(authToken, fallbackAuthId) {
|
|
1273
|
-
const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
|
|
1274
|
-
let authId = fallbackAuthId ?? null;
|
|
1275
|
-
if (!authId) {
|
|
1276
|
-
const { data, error } = await supabase.auth.getUser();
|
|
1277
|
-
if (error || !data.user?.id) {
|
|
1278
|
-
return { authId: null, profileId: null };
|
|
1279
|
-
}
|
|
1280
|
-
authId = data.user.id;
|
|
1281
|
-
}
|
|
1282
|
-
const { data: profileRow, error: profileError } = await supabase.from("user_profiles").select("id").eq("auth_id", authId).single();
|
|
1283
|
-
if (profileError || !profileRow?.id) {
|
|
1284
|
-
return { authId, profileId: null };
|
|
1285
|
-
}
|
|
1286
|
-
return { authId, profileId: profileRow.id };
|
|
1287
|
-
}
|
|
1288
|
-
async function fetchUsageRows(authToken, usageUserIds, startIso, endIso) {
|
|
1289
|
-
if (usageUserIds.length === 0) {
|
|
1290
|
-
return [];
|
|
1291
|
-
}
|
|
1292
|
-
const supabase = createAuthedSupabaseClient(SUPABASE_URL, SUPABASE_ANON_KEY, authToken);
|
|
1293
|
-
const usageQuery = supabase.from("token_usage").select("model, input_tokens, output_tokens, base_cost, created_at").gte("created_at", startIso).lte("created_at", endIso);
|
|
1294
|
-
const scopedQuery = usageUserIds.length === 1 ? usageQuery.eq("user_id", usageUserIds[0]) : usageQuery.in("user_id", usageUserIds);
|
|
1295
|
-
const { data, error } = await scopedQuery;
|
|
1296
|
-
if (error || !data) {
|
|
1297
|
-
return null;
|
|
1298
|
-
}
|
|
1299
|
-
return data;
|
|
1300
|
-
}
|
|
1301
|
-
function aggregateUsageRows(rows, start, end) {
|
|
1302
|
-
let totalInputTokens = 0;
|
|
1303
|
-
let totalOutputTokens = 0;
|
|
1304
|
-
let totalCost = 0;
|
|
1305
|
-
const byModelMap = /* @__PURE__ */ new Map();
|
|
1306
|
-
for (const row of rows) {
|
|
1307
|
-
const ts = new Date(row.created_at);
|
|
1308
|
-
if (ts < start || ts > end) continue;
|
|
1309
|
-
totalInputTokens += row.input_tokens;
|
|
1310
|
-
totalOutputTokens += row.output_tokens;
|
|
1311
|
-
totalCost += row.base_cost;
|
|
1312
|
-
const existing = byModelMap.get(row.model);
|
|
1313
|
-
if (existing) {
|
|
1314
|
-
existing.inputTokens += row.input_tokens;
|
|
1315
|
-
existing.outputTokens += row.output_tokens;
|
|
1316
|
-
existing.cost += row.base_cost;
|
|
1317
|
-
} else {
|
|
1318
|
-
byModelMap.set(row.model, {
|
|
1319
|
-
inputTokens: row.input_tokens,
|
|
1320
|
-
outputTokens: row.output_tokens,
|
|
1321
|
-
cost: row.base_cost
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
const byModel = Array.from(byModelMap.entries()).map(([model, stats]) => ({ model, ...stats })).sort((a, b) => b.cost - a.cost);
|
|
1326
|
-
return { totalInputTokens, totalOutputTokens, totalCost, byModel };
|
|
1327
|
-
}
|
|
1328
1154
|
async function showUsageDetails(options = {}) {
|
|
1329
1155
|
const { pauseForInput = false, debug = false } = options;
|
|
1330
1156
|
console.log(chalk.bold("\n-- Usage Details --\n"));
|
|
@@ -1337,131 +1163,54 @@ async function showUsageDetails(options = {}) {
|
|
|
1337
1163
|
}
|
|
1338
1164
|
}
|
|
1339
1165
|
const spinner = ora("Loading usage data...").start();
|
|
1340
|
-
const config = await loadConfig();
|
|
1341
|
-
const authToken = getAuthToken(config);
|
|
1342
|
-
const authId = config.userId;
|
|
1343
|
-
if (debug) {
|
|
1344
|
-
debugLog("usage", "start", "Usage command started", {
|
|
1345
|
-
authId: authId ?? null,
|
|
1346
|
-
hasToken: !!authToken
|
|
1347
|
-
});
|
|
1348
|
-
}
|
|
1349
|
-
if (!authToken) {
|
|
1350
|
-
spinner.fail("Not logged in");
|
|
1351
|
-
return;
|
|
1352
|
-
}
|
|
1353
|
-
const apiUrl = getApiUrl(config);
|
|
1354
1166
|
try {
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1167
|
+
spinner.stop();
|
|
1168
|
+
const now = /* @__PURE__ */ new Date();
|
|
1169
|
+
const yearStart = new Date(now.getFullYear(), 0, 1);
|
|
1170
|
+
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
1171
|
+
const startOf24h = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
|
|
1172
|
+
const startOf7d = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
|
|
1173
|
+
const startOf30d = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
|
|
1358
1174
|
if (debug) {
|
|
1359
|
-
debugLog("usage", "
|
|
1360
|
-
|
|
1175
|
+
debugLog("usage", "start", "Usage command started from local ledger", {
|
|
1176
|
+
periodStart: yearStart.toISOString(),
|
|
1177
|
+
periodEnd: now.toISOString()
|
|
1361
1178
|
});
|
|
1362
1179
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
}
|
|
1375
|
-
if (usageUserIds.length === 0) {
|
|
1376
|
-
console.log(chalk.yellow("Unable to resolve user ID for usage details."));
|
|
1377
|
-
return;
|
|
1378
|
-
}
|
|
1379
|
-
const now = /* @__PURE__ */ new Date();
|
|
1380
|
-
const yearStart = new Date(now.getFullYear(), 0, 1);
|
|
1381
|
-
const usageRows = await fetchUsageRows(authToken, usageUserIds, yearStart.toISOString(), now.toISOString());
|
|
1180
|
+
const periods = [
|
|
1181
|
+
{ label: "Today", start: startOfToday, end: now },
|
|
1182
|
+
{ label: "Last 24 Hours", start: startOf24h, end: now },
|
|
1183
|
+
{ label: "Last 7 Days", start: startOf7d, end: now },
|
|
1184
|
+
{ label: "Last 30 Days", start: startOf30d, end: now },
|
|
1185
|
+
{ label: "Year to Date", start: yearStart, end: now }
|
|
1186
|
+
];
|
|
1187
|
+
console.log(chalk.blue("Local BYOK Usage (local time):"));
|
|
1188
|
+
console.log(chalk.dim("Estimated provider spend from the local usage ledger. No usage data is sent to Archon-managed servers."));
|
|
1189
|
+
for (const period of periods) {
|
|
1190
|
+
const summary = await summarizeLocalUsage({ start: period.start, end: period.end });
|
|
1382
1191
|
if (debug) {
|
|
1383
|
-
debugLog("usage", "
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1192
|
+
debugLog("usage", "period.summary", "Computed local usage period", {
|
|
1193
|
+
label: period.label,
|
|
1194
|
+
totalInputTokens: summary.totalInputTokens,
|
|
1195
|
+
totalOutputTokens: summary.totalOutputTokens,
|
|
1196
|
+
totalBaseCost: summary.totalBaseCost,
|
|
1197
|
+
byModelCount: summary.byModel.length
|
|
1388
1198
|
});
|
|
1389
1199
|
}
|
|
1390
|
-
if (!usageRows) {
|
|
1391
|
-
console.log(chalk.yellow("Unable to fetch BYOK usage data."));
|
|
1392
|
-
return;
|
|
1393
|
-
}
|
|
1394
|
-
const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
1395
|
-
const startOf24h = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
|
|
1396
|
-
const startOf7d = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
|
|
1397
|
-
const startOf30d = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
|
|
1398
|
-
const periods = [
|
|
1399
|
-
{ label: "Today", start: startOfToday, end: now },
|
|
1400
|
-
{ label: "Last 24 Hours", start: startOf24h, end: now },
|
|
1401
|
-
{ label: "Last 7 Days", start: startOf7d, end: now },
|
|
1402
|
-
{ label: "Last 30 Days", start: startOf30d, end: now },
|
|
1403
|
-
{ label: "Year to Date", start: yearStart, end: now }
|
|
1404
|
-
];
|
|
1405
|
-
console.log(chalk.blue("BYOK Usage (local time):"));
|
|
1406
|
-
console.log(chalk.dim("Estimated provider spend by model (you are billed directly by provider)."));
|
|
1407
|
-
for (const period of periods) {
|
|
1408
|
-
const summary = aggregateUsageRows(usageRows, period.start, period.end);
|
|
1409
|
-
console.log();
|
|
1410
|
-
console.log(chalk.bold(`${period.label}:`));
|
|
1411
|
-
console.log(` ${period.start.toLocaleDateString()} \u2192 ${period.end.toLocaleDateString()}`);
|
|
1412
|
-
console.log(` Tokens: ${formatTokens(summary.totalInputTokens + summary.totalOutputTokens)} (in ${formatTokens(summary.totalInputTokens)} / out ${formatTokens(summary.totalOutputTokens)})`);
|
|
1413
|
-
console.log(` Estimated Spend: ${formatCost(summary.totalCost)} ${chalk.dim("(paid directly to provider)")}`);
|
|
1414
|
-
console.log(chalk.dim(" By Model:"));
|
|
1415
|
-
renderModelBreakdown(summary.byModel, { indent: " " });
|
|
1416
|
-
}
|
|
1417
|
-
} else {
|
|
1418
|
-
const periodLabel = formatUsagePeriodLabel(data.periodSource);
|
|
1419
|
-
const byModel = [...data.byModel ?? []].sort((a, b) => b.cost - a.cost);
|
|
1420
|
-
const modelBilledTotal = sumModelCost(byModel);
|
|
1421
|
-
const modelBaseTotal = data.totalBaseCost;
|
|
1422
|
-
const modelFeeTotal = Math.max(0, modelBilledTotal - modelBaseTotal);
|
|
1423
|
-
console.log(chalk.blue(`${periodLabel}:`));
|
|
1424
|
-
console.log(` ${formatLocalDateTime(data.periodStart)} \u2192 ${formatLocalDateTime(data.periodEnd)}`);
|
|
1425
|
-
console.log();
|
|
1426
|
-
console.log(chalk.blue("Token Usage:"));
|
|
1427
|
-
console.log(` Input: ${formatTokens(data.totalInputTokens)} tokens`);
|
|
1428
|
-
console.log(` Output: ${formatTokens(data.totalOutputTokens)} tokens`);
|
|
1429
|
-
console.log(` Total: ${formatTokens(data.totalInputTokens + data.totalOutputTokens)} tokens`);
|
|
1430
1200
|
console.log();
|
|
1431
|
-
console.log(chalk.
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
console.log(` Estimated Cost: ${formatCost(modelBaseTotal)}`);
|
|
1438
|
-
}
|
|
1439
|
-
if (byModel.length > 0) {
|
|
1440
|
-
console.log();
|
|
1441
|
-
console.log(chalk.blue("By Model:"));
|
|
1442
|
-
renderModelBreakdown(
|
|
1443
|
-
byModel.map((row) => ({
|
|
1444
|
-
model: row.model,
|
|
1445
|
-
inputTokens: row.inputTokens,
|
|
1446
|
-
outputTokens: row.outputTokens,
|
|
1447
|
-
cost: row.cost
|
|
1448
|
-
}))
|
|
1449
|
-
);
|
|
1450
|
-
}
|
|
1451
|
-
if (data.byOperation && data.byOperation.length > 0) {
|
|
1452
|
-
console.log();
|
|
1453
|
-
console.log(chalk.blue("By Operation:"));
|
|
1454
|
-
for (const stats of [...data.byOperation].sort((a, b) => b.cost - a.cost)) {
|
|
1455
|
-
console.log(` ${stats.operation}: ${formatTokens(stats.tokenCount)} tokens (${formatCost(stats.cost)})`);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1201
|
+
console.log(chalk.bold(`${period.label}:`));
|
|
1202
|
+
console.log(` ${period.start.toLocaleDateString()} \u2192 ${period.end.toLocaleDateString()}`);
|
|
1203
|
+
console.log(` Tokens: ${formatTokens(summary.totalInputTokens + summary.totalOutputTokens)} (in ${formatTokens(summary.totalInputTokens)} / out ${formatTokens(summary.totalOutputTokens)})`);
|
|
1204
|
+
console.log(` Estimated Spend: ${formatCost(summary.totalBaseCost)} ${chalk.dim("(paid directly to provider)")}`);
|
|
1205
|
+
console.log(chalk.dim(" By Model:"));
|
|
1206
|
+
renderModelBreakdown(summary.byModel, { indent: " " });
|
|
1458
1207
|
}
|
|
1459
1208
|
} catch {
|
|
1460
1209
|
if (debug) {
|
|
1461
|
-
debugLog("usage", "error", "Usage command threw exception");
|
|
1210
|
+
debugLog("usage", "error", "Usage command threw exception while reading local ledger");
|
|
1462
1211
|
}
|
|
1463
1212
|
spinner.stop();
|
|
1464
|
-
console.log(chalk.yellow("Error
|
|
1213
|
+
console.log(chalk.yellow("Error reading local usage data."));
|
|
1465
1214
|
}
|
|
1466
1215
|
if (pauseForInput) {
|
|
1467
1216
|
console.log();
|