archondev 2.19.9 → 2.19.11

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.
Files changed (2) hide show
  1. package/dist/index.js +188 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2844,6 +2844,55 @@ async function start(options = {}) {
2844
2844
  } catch {
2845
2845
  }
2846
2846
  }
2847
+ if (currentTier === "BYOK" && config.accessToken) {
2848
+ try {
2849
+ let usageStats = await fetchByokUsageStats(config.accessToken);
2850
+ const usageStatsUnavailable = !usageStats;
2851
+ if (!usageStats) {
2852
+ usageStats = {
2853
+ totalInputTokens: 0,
2854
+ totalOutputTokens: 0,
2855
+ totalBaseCost: 0,
2856
+ byModel: []
2857
+ };
2858
+ }
2859
+ console.log();
2860
+ console.log(chalk6.bold("\u{1F4CA} BYOK Usage"));
2861
+ console.log(chalk6.dim("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2862
+ if (usageStats.periodStart) {
2863
+ const periodStart = new Date(usageStats.periodStart);
2864
+ const periodEnd = usageStats.periodEnd ? new Date(usageStats.periodEnd) : null;
2865
+ const formattedStart = isNaN(periodStart.getTime()) ? usageStats.periodStart : periodStart.toLocaleDateString();
2866
+ const formattedEnd = periodEnd && !isNaN(periodEnd.getTime()) ? periodEnd.toLocaleDateString() : void 0;
2867
+ if (formattedEnd) {
2868
+ console.log(chalk6.dim(` Period: ${formattedStart} \u2192 ${formattedEnd}`));
2869
+ } else {
2870
+ console.log(chalk6.dim(` Period start: ${formattedStart}`));
2871
+ }
2872
+ } else {
2873
+ console.log(chalk6.dim(" Period: Current month to date"));
2874
+ }
2875
+ const totalTokens = usageStats.totalInputTokens + usageStats.totalOutputTokens;
2876
+ console.log(` Tokens: ${chalk6.dim(totalTokens.toLocaleString())}`);
2877
+ console.log(` Estimated provider spend: ${chalk6.dim(`$${usageStats.totalBaseCost.toFixed(4)}`)}`);
2878
+ console.log();
2879
+ console.log(chalk6.dim(" Model Usage:"));
2880
+ if (usageStats.byModel.length > 0) {
2881
+ for (const model of usageStats.byModel) {
2882
+ const modelName = model.model.length > 32 ? model.model.slice(0, 29) + "..." : model.model;
2883
+ console.log(chalk6.dim(` ${modelName.padEnd(34)} $${model.cost.toFixed(4)}`));
2884
+ }
2885
+ } else {
2886
+ console.log(chalk6.dim(` ${"No usage yet".padEnd(34)} $0.0000`));
2887
+ }
2888
+ console.log(chalk6.dim("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
2889
+ if (usageStatsUnavailable) {
2890
+ console.log(chalk6.dim("Usage details may be delayed. Run `archon usage` to refresh."));
2891
+ }
2892
+ console.log(chalk6.dim("View details: archon usage | Models: archon preferences | Switch tier: archon upgrade"));
2893
+ } catch {
2894
+ }
2895
+ }
2847
2896
  if (currentTier === "BYOK") {
2848
2897
  const { keyManager } = await import("./keys-THCHXIFD.js");
2849
2898
  const hasKeys = await keyManager.hasAnyKey();
@@ -2988,6 +3037,38 @@ async function fetchCreditsUsageStats(accessToken, authId) {
2988
3037
  }
2989
3038
  return fetchCreditsUsageStatsFromSupabase(accessToken, authId);
2990
3039
  }
3040
+ async function fetchByokUsageStats(accessToken) {
3041
+ try {
3042
+ const { API_URL: API_URL3 } = await import("./constants-XDIWFFPN.js");
3043
+ const response = await fetch(`${API_URL3}/api/usage`, {
3044
+ headers: {
3045
+ "Authorization": `Bearer ${accessToken}`
3046
+ }
3047
+ });
3048
+ if (!response.ok) {
3049
+ return null;
3050
+ }
3051
+ const data = await response.json();
3052
+ if (data.tier && data.tier !== "BYOK") {
3053
+ return null;
3054
+ }
3055
+ const byModel = [...data.byModel ?? []].map((row) => ({
3056
+ model: row.model,
3057
+ cost: typeof row.cost === "number" ? row.cost : 0
3058
+ })).sort((a, b) => b.cost - a.cost);
3059
+ return {
3060
+ totalInputTokens: data.totalInputTokens ?? 0,
3061
+ totalOutputTokens: data.totalOutputTokens ?? 0,
3062
+ totalBaseCost: data.totalBaseCost ?? 0,
3063
+ byModel,
3064
+ periodStart: data.periodStart,
3065
+ periodEnd: data.periodEnd,
3066
+ periodSource: data.periodSource
3067
+ };
3068
+ } catch {
3069
+ return null;
3070
+ }
3071
+ }
2991
3072
  async function fetchCreditsUsageStatsFromSupabase(accessToken, authId) {
2992
3073
  try {
2993
3074
  const { SUPABASE_URL: SUPABASE_URL2, SUPABASE_ANON_KEY: SUPABASE_ANON_KEY2 } = await import("./constants-XDIWFFPN.js");
@@ -3496,7 +3577,7 @@ async function runAIInterview(cwd, initialMessage, agent) {
3496
3577
  console.log(chalk6.dim(`
3497
3578
  (Interview used ${usage.totalTokens} tokens, $${usage.baseCost.toFixed(4)})`));
3498
3579
  }
3499
- await finishInterview(cwd, state);
3580
+ await finishInterview(cwd, state, initialMessage);
3500
3581
  } catch (error) {
3501
3582
  console.log(chalk6.yellow("\n[!] AI interview unavailable, using simple setup.\n"));
3502
3583
  await runSimpleInterview(cwd, initialMessage);
@@ -3524,46 +3605,17 @@ async function runSimpleInterview(cwd, initialMessage) {
3524
3605
  }
3525
3606
  }
3526
3607
  if (!state.audience) {
3527
- console.log();
3528
- const audience = await prompt("Who is this for? (me / team / public)");
3529
- if (!wantsToSkip(audience)) {
3530
- const lower = audience.toLowerCase().trim();
3531
- if (lower.includes("me") || lower.includes("personal") || lower.includes("myself")) {
3532
- state.audience = "personal";
3533
- state.posture = "prototype";
3534
- } else if (lower.includes("team") || lower.includes("internal")) {
3535
- state.audience = "team";
3536
- state.posture = "production";
3537
- } else if (lower.includes("public") || lower.includes("user") || lower.includes("customer")) {
3538
- state.audience = "endusers";
3539
- state.posture = "production";
3540
- }
3541
- }
3608
+ state.audience = inferAudienceFromMessage(initialMessage);
3542
3609
  }
3543
3610
  if (!state.language) {
3544
- console.log();
3545
- const lang = await prompt("What language? (typescript / python / go / rust / other)");
3546
- if (!wantsToSkip(lang)) {
3547
- const lower = lang.toLowerCase().trim();
3548
- if (lower.includes("typescript") || lower.includes("ts") || lower.includes("javascript") || lower.includes("js")) {
3549
- state.language = "typescript";
3550
- } else if (lower.includes("python") || lower.includes("py")) {
3551
- state.language = "python";
3552
- } else if (lower.includes("go") || lower.includes("golang")) {
3553
- state.language = "go";
3554
- } else if (lower.includes("rust") || lower.includes("rs")) {
3555
- state.language = "rust";
3556
- } else if (lang.trim()) {
3557
- state.language = lang.trim();
3558
- }
3559
- }
3611
+ state.language = inferLanguageFromProjectFiles(cwd) ?? "typescript";
3560
3612
  }
3561
3613
  if (!state.posture) {
3562
3614
  state.posture = inferPosture(state) ?? "production";
3563
3615
  }
3564
- await finishInterview(cwd, state);
3616
+ await finishInterview(cwd, state, initialMessage);
3565
3617
  }
3566
- async function finishInterview(cwd, state) {
3618
+ async function finishInterview(cwd, state, initialTaskHint) {
3567
3619
  console.log(chalk6.blue("\n-- Recording Project Details --\n"));
3568
3620
  const posture = state.posture === "enterprise" ? "enterprise" : state.posture === "prototype" ? "prototype" : "production";
3569
3621
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -3609,14 +3661,110 @@ ${state.forbiddenPatterns?.length ? `- **Forbidden patterns:** ${state.forbidden
3609
3661
  console.log(` 1. ${chalk6.cyan("Review")} ARCHITECTURE.md and customize if needed`);
3610
3662
  console.log(` 2. ${chalk6.cyan("Run")} ${chalk6.dim('archon plan "your first task"')} to create an atom`);
3611
3663
  console.log();
3612
- const continueChoice = await promptYesNo("Would you like to plan your first task now?", true);
3613
- if (continueChoice) {
3614
- const description = await promptWithCommands("Describe what you want to build first", { allowMultiline: true });
3615
- if (description.trim()) {
3616
- const { plan: plan2 } = await import("./plan-AR6Y4QUD.js");
3617
- await plan2(description, {});
3664
+ const hintedTask = initialTaskHint?.trim() ?? "";
3665
+ if (hintedTask) {
3666
+ console.log(chalk6.dim("Using your request above as the first task.\n"));
3667
+ const { plan: plan2 } = await import("./plan-AR6Y4QUD.js");
3668
+ await plan2(hintedTask, {});
3669
+ return;
3670
+ }
3671
+ const continueAnswer = await prompt("Would you like to plan your first task now? (Y/n)");
3672
+ const normalized = continueAnswer.trim().toLowerCase();
3673
+ const useDefault = normalized === "";
3674
+ const isYes = normalized === "y" || normalized === "yes";
3675
+ const isNo = normalized === "n" || normalized === "no";
3676
+ if (isNo) {
3677
+ return;
3678
+ }
3679
+ let description = "";
3680
+ if (useDefault || isYes) {
3681
+ const hinted = initialTaskHint?.trim() ?? "";
3682
+ if (hinted) {
3683
+ description = hinted;
3684
+ console.log(chalk6.dim("\nUsing your request above as the first task.\n"));
3685
+ } else {
3686
+ description = await promptWithCommands("Describe what you want to build first", { allowMultiline: true });
3687
+ }
3688
+ } else {
3689
+ description = continueAnswer.trim();
3690
+ }
3691
+ if (description.trim()) {
3692
+ const { plan: plan2 } = await import("./plan-AR6Y4QUD.js");
3693
+ await plan2(description, {});
3694
+ }
3695
+ }
3696
+ function inferAudienceFromMessage(message) {
3697
+ const lower = message.toLowerCase();
3698
+ if (/\b(i|me|my|myself)\b/.test(lower) && !/\b(users?|customers?|public|team|internal)\b/.test(lower)) {
3699
+ return "personal";
3700
+ }
3701
+ if (/\bteam|internal|coworkers?|org\b/.test(lower)) {
3702
+ return "team";
3703
+ }
3704
+ return "endusers";
3705
+ }
3706
+ function inferLanguageFromProjectFiles(cwd) {
3707
+ const extToLanguage = /* @__PURE__ */ new Map([
3708
+ [".ts", "typescript"],
3709
+ [".tsx", "typescript"],
3710
+ [".js", "javascript"],
3711
+ [".jsx", "javascript"],
3712
+ [".py", "python"],
3713
+ [".go", "go"],
3714
+ [".rs", "rust"],
3715
+ [".java", "java"],
3716
+ [".kt", "kotlin"],
3717
+ [".swift", "swift"],
3718
+ [".rb", "ruby"],
3719
+ [".php", "php"],
3720
+ [".cs", "csharp"]
3721
+ ]);
3722
+ const counts = /* @__PURE__ */ new Map();
3723
+ const rootDirs = ["src", "app", "lib", "server", "backend", "frontend", "services"];
3724
+ for (const root of rootDirs) {
3725
+ const rootPath = join6(cwd, root);
3726
+ if (!existsSync6(rootPath)) {
3727
+ continue;
3728
+ }
3729
+ try {
3730
+ const stack = [rootPath];
3731
+ while (stack.length > 0) {
3732
+ const current = stack.pop();
3733
+ if (!current) {
3734
+ continue;
3735
+ }
3736
+ const entries = readdirSync3(current, { withFileTypes: true });
3737
+ for (const entry of entries) {
3738
+ if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
3739
+ continue;
3740
+ }
3741
+ const fullPath = join6(current, entry.name);
3742
+ if (entry.isDirectory()) {
3743
+ stack.push(fullPath);
3744
+ continue;
3745
+ }
3746
+ const dotIndex = entry.name.lastIndexOf(".");
3747
+ if (dotIndex === -1) {
3748
+ continue;
3749
+ }
3750
+ const ext = entry.name.slice(dotIndex);
3751
+ const language = extToLanguage.get(ext);
3752
+ if (!language) {
3753
+ continue;
3754
+ }
3755
+ counts.set(language, (counts.get(language) ?? 0) + 1);
3756
+ }
3757
+ }
3758
+ } catch {
3759
+ }
3760
+ }
3761
+ let best;
3762
+ for (const [language, count] of counts.entries()) {
3763
+ if (!best || count > best.count) {
3764
+ best = { language, count };
3618
3765
  }
3619
3766
  }
3767
+ return best?.language;
3620
3768
  }
3621
3769
  async function quickStart(cwd) {
3622
3770
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archondev",
3
- "version": "2.19.9",
3
+ "version": "2.19.11",
4
4
  "description": "Local-first AI-powered development governance system",
5
5
  "main": "dist/index.js",
6
6
  "bin": {