Selaa lähdekoodia

feat(cli): add `codegraph usage` command to show AI balance and recent usage

Adds a `usage` subcommand that pings `/v1/usage` with the stored token and
displays balance, plan, 30-day explore/token counts, and allowance reset date.

Degrades quietly in all non-happy-path states — signed out, BYO endpoint, or
unreachable server — so managed reasoning remaining optional doesn't change.

Also extends `OffloadUsage` with the fields the endpoint already returns
(`unlimited`, `banned`, `tokensLast30`, `callsLast30`, `creditsLast30`) that
were previously untyped.
Colby McHenry 5 päivää sitten
vanhempi
sitoutus
c9e207a0f2
2 muutettua tiedostoa jossa 49 lisäystä ja 1 poistoa
  1. 44 1
      src/bin/codegraph.ts
  2. 5 0
      src/reasoning/reasoner.ts

+ 44 - 1
src/bin/codegraph.ts

@@ -36,7 +36,7 @@ import { installFatalHandlers } from './fatal-handler';
 import { relaunchWithWasmRuntimeFlagsIfNeeded } from '../extraction/wasm-runtime-flags';
 import { EXTRACTION_VERSION } from '../extraction/extraction-version';
 import { getTelemetry, TELEMETRY_DOCS, recordIndexEvent } from '../telemetry';
-import { writeOffloadConfig } from '../reasoning/config';
+import { writeOffloadConfig, resolveOffload } from '../reasoning/config';
 import { writeOffloadToken } from '../reasoning/credentials';
 import { startDeviceLogin, pollForToken, openBrowser } from '../reasoning/login';
 import { fetchUsage } from '../reasoning/reasoner';
@@ -1404,6 +1404,49 @@ program
     success('Signed out of CodeGraph AI.');
   });
 
+/**
+ * codegraph usage — show the CodeGraph AI balance + recent usage (the server is the source of
+ * truth; this just pings /v1/usage with the stored token). Degrades quietly when signed out or
+ * unreachable — managed reasoning is optional, so this command never errors hard.
+ */
+program
+  .command('usage')
+  .description('Show your CodeGraph AI balance and recent usage')
+  .action(async () => {
+    const cfg = resolveOffload();
+
+    if (!cfg.apiKey) {
+      if (cfg.url && cfg.managed) {
+        info('Signed out of CodeGraph AI. Run `codegraph login` to sign in.');
+      } else {
+        info('Not signed in to CodeGraph AI — codegraph_explore runs locally.');
+        info('Run `codegraph login` to use managed reasoning with your credits.');
+      }
+      return;
+    }
+
+    const usage = await fetchUsage();
+    if (!usage) {
+      if (cfg.managed) warn('Could not reach CodeGraph AI to read your balance — try again in a moment.');
+      else info(`Reasoning offload: your own endpoint (${cfg.url}) — no CodeGraph AI balance to show.`);
+      info('  (codegraph_explore still works locally regardless.)');
+      return;
+    }
+
+    success('CodeGraph AI');
+    if (usage.banned) warn('  Account suspended — contact support.');
+    else if (usage.unlimited) info('  Balance:  unlimited');
+    else if (typeof usage.remaining === 'number')
+      info(`  Balance:  ${usage.remaining.toLocaleString()} credits  ($${(usage.remaining / 100_000).toFixed(2)})`);
+    if (usage.plan) info(`  Plan:     ${usage.plan === 'payg' ? 'pay-as-you-go' : usage.plan}`);
+    if (typeof usage.tokensLast30 === 'number' || typeof usage.callsLast30 === 'number')
+      info(`  30 days:  ${(usage.callsLast30 ?? 0).toLocaleString()} explores · ${(usage.tokensLast30 ?? 0).toLocaleString()} tokens`);
+    // Only a subscription allowance resets each period; pay-as-you-go credits don't expire, so there's
+    // nothing to renew. Show a reset date only when there's an actual recurring allowance.
+    if (usage.periodEnd && (usage.allowance ?? 0) > 0)
+      info(`  Allowance resets: ${new Date(usage.periodEnd).toISOString().slice(0, 10)}`);
+  });
+
 /**
  * codegraph serve
  */

+ 5 - 0
src/reasoning/reasoner.ts

@@ -47,6 +47,11 @@ export interface OffloadUsage {
   overage?: number;
   remaining?: number;
   periodEnd?: number;
+  unlimited?: boolean;
+  banned?: boolean;
+  tokensLast30?: number;
+  callsLast30?: number;
+  creditsLast30?: number;
   models?: string[];
 }