@ashx-j/lunr 0.1.1 → 0.1.2

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 (35) hide show
  1. package/dist/catalog/models.json +1 -1
  2. package/dist/catalog/providers/opencode-go.json +1 -1
  3. package/dist/catalog/providers/openrouter.json +1 -1
  4. package/dist/catalog/providers/qwen-token-plan-cn.json +1 -1
  5. package/dist/catalog/providers/qwen-token-plan.json +1 -1
  6. package/dist/catalog/publication.json +3 -3
  7. package/dist/core/catalog-merge.d.ts.map +1 -1
  8. package/dist/core/catalog-merge.js +7 -1
  9. package/dist/core/catalog-merge.js.map +1 -1
  10. package/dist/core/grok-cli-auth.d.ts +32 -0
  11. package/dist/core/grok-cli-auth.d.ts.map +1 -0
  12. package/dist/core/grok-cli-auth.js +218 -0
  13. package/dist/core/grok-cli-auth.js.map +1 -0
  14. package/dist/core/model-runtime.d.ts +9 -0
  15. package/dist/core/model-runtime.d.ts.map +1 -1
  16. package/dist/core/model-runtime.js +22 -3
  17. package/dist/core/model-runtime.js.map +1 -1
  18. package/dist/core/usage-adapters/xai.d.ts.map +1 -1
  19. package/dist/core/usage-adapters/xai.js +4 -0
  20. package/dist/core/usage-adapters/xai.js.map +1 -1
  21. package/dist/core/usage-service.d.ts +11 -1
  22. package/dist/core/usage-service.d.ts.map +1 -1
  23. package/dist/core/usage-service.js +45 -9
  24. package/dist/core/usage-service.js.map +1 -1
  25. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  26. package/dist/modes/interactive/interactive-mode.js +28 -3
  27. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  28. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  29. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  30. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  31. package/examples/extensions/gondolin/package-lock.json +2 -2
  32. package/examples/extensions/gondolin/package.json +1 -1
  33. package/examples/extensions/with-deps/package-lock.json +2 -2
  34. package/examples/extensions/with-deps/package.json +1 -1
  35. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/core/usage-adapters/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI Grok (SuperGrok / X Premium) weekly plan usage.\n *\n * `GET https://cli-chat-proxy.grok.com/v1/billing?format=credits` with the\n * OAuth access token (Grok CLI identity header required). Official Grok\n * Build `/usage` and grok.com Settings → Usage read the same weekly pool:\n * config.creditUsagePercent + config.currentPeriod.end\n *\n * Extra Usage Credits (`onDemandCap` > 0) are a secondary window only.\n * `monthlyLimit` / `includedUsed` / `billingPeriodEnd` are the old monthly\n * Extra Usage envelope — never treated as the subscription plan.\n *\n * Pay-as-you-go API keys have no quota endpoint. OAuth-only; any failure\n * or shape mismatch resolves to `undefined` (caller hides the plan section).\n * First-party undocumented protocol — re-smoke against a real OAuth token\n * after xAI changes the billing payload.\n */\n\nimport type { ModelRuntime } from \"../model-runtime.ts\";\nimport type { PlanUsage, PlanUsageWindow } from \"../usage-service.ts\";\nimport {\n\tasObject,\n\tasString,\n\tclampPercent,\n\tfetchWithTimeout,\n\ttoEpochMs,\n\tunwrapVal,\n\tusedPercentFromUsed,\n} from \"./shared.ts\";\n\nconst XAI_PROVIDER_ID = \"xai\";\nconst XAI_BILLING_URL = \"https://cli-chat-proxy.grok.com/v1/billing?format=credits\";\n\nfunction currentPeriod(config: Record<string, unknown>): Record<string, unknown> | undefined {\n\treturn asObject(config.currentPeriod) ?? asObject(config.current_period);\n}\n\nfunction weeklyWindow(config: Record<string, unknown>): PlanUsageWindow | undefined {\n\tconst period = currentPeriod(config);\n\tconst raw = unwrapVal(config.creditUsagePercent ?? config.credit_usage_percent);\n\t// Omitted proto3 percent + a live currentPeriod means 0% used (CodexBar).\n\tif (raw === undefined && !period) return undefined;\n\tconst usedPercent = raw === undefined ? 0 : clampPercent(raw);\n\treturn {\n\t\tlabel: \"Weekly\",\n\t\tusedPercent,\n\t\tresetsAt: toEpochMs(period?.end),\n\t};\n}\n\nexport async function fetchXaiPlanUsage(runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\tif (!runtime.isUsingOAuth(XAI_PROVIDER_ID)) return undefined;\n\n\tconst resolution = await runtime.getAuth(XAI_PROVIDER_ID);\n\tconst accessToken = resolution?.auth.apiKey;\n\tif (!accessToken) return undefined;\n\n\tconst response = await fetchWithTimeout(XAI_BILLING_URL, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\tAccept: \"application/json\",\n\t\t\t\"x-xai-token-auth\": \"xai-grok-cli\",\n\t\t},\n\t});\n\tif (!response.ok) return undefined;\n\tconst payload = asObject(await response.json());\n\tif (!payload) return undefined;\n\tconst config = asObject(payload.config) ?? payload;\n\n\tconst windows: PlanUsageWindow[] = [];\n\tconst weekly = weeklyWindow(config);\n\tif (weekly) windows.push(weekly);\n\n\tconst onDemandCap = unwrapVal(config.onDemandCap);\n\tif (onDemandCap !== undefined && onDemandCap > 0) {\n\t\tconst usedPercent = usedPercentFromUsed(onDemandCap, unwrapVal(config.onDemandUsed) ?? 0);\n\t\tif (usedPercent !== undefined) {\n\t\t\twindows.push({\n\t\t\t\tlabel: \"Extra\",\n\t\t\t\tusedPercent,\n\t\t\t\tresetsAt: weekly?.resetsAt,\n\t\t\t});\n\t\t}\n\t}\n\n\tif (windows.length === 0) return undefined;\n\tconst planLabel = asString(config.subscriptionTier) ?? asString(config.subscription_tier);\n\treturn { provider: XAI_PROVIDER_ID, planLabel, windows };\n}\n"]}
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/core/usage-adapters/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI Grok (SuperGrok / X Premium) weekly plan usage.\n *\n * `GET https://cli-chat-proxy.grok.com/v1/billing?format=credits` with the\n * OAuth access token (Grok CLI identity header required). Official Grok\n * Build `/usage` and grok.com Settings → Usage read the same weekly pool:\n * config.creditUsagePercent + config.currentPeriod.end\n *\n * Extra Usage Credits (`onDemandCap` > 0) are a secondary window only.\n * `monthlyLimit` / `includedUsed` / `billingPeriodEnd` are the old monthly\n * Extra Usage envelope — never treated as the subscription plan.\n *\n * Pay-as-you-go API keys have no quota endpoint. OAuth-only; any failure\n * or shape mismatch resolves to `undefined` (caller hides the plan section).\n * First-party undocumented protocol — re-smoke against a real OAuth token\n * after xAI changes the billing payload.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"../model-runtime.ts\";\nimport type { PlanUsage, PlanUsageWindow } from \"../usage-service.ts\";\nimport {\n\tasObject,\n\tasString,\n\tclampPercent,\n\tfetchWithTimeout,\n\ttoEpochMs,\n\tunwrapVal,\n\tusedPercentFromUsed,\n} from \"./shared.ts\";\n\nconst XAI_PROVIDER_ID = \"xai\";\nconst XAI_BILLING_URL = \"https://cli-chat-proxy.grok.com/v1/billing?format=credits\";\n\nfunction currentPeriod(config: Record<string, unknown>): Record<string, unknown> | undefined {\n\treturn asObject(config.currentPeriod) ?? asObject(config.current_period);\n}\n\nfunction weeklyWindow(config: Record<string, unknown>): PlanUsageWindow | undefined {\n\tconst period = currentPeriod(config);\n\tconst raw = unwrapVal(config.creditUsagePercent ?? config.credit_usage_percent);\n\t// Omitted proto3 percent + a live currentPeriod means 0% used (CodexBar).\n\tif (raw === undefined && !period) return undefined;\n\tconst usedPercent = raw === undefined ? 0 : clampPercent(raw);\n\treturn {\n\t\tlabel: \"Weekly\",\n\t\tusedPercent,\n\t\tresetsAt: toEpochMs(period?.end),\n\t};\n}\n\nexport async function fetchXaiPlanUsage(runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\tif (!runtime.isUsingOAuth(XAI_PROVIDER_ID)) return undefined;\n\n\tconst resolution = await runtime.getAuth(XAI_PROVIDER_ID);\n\tconst accessToken = resolution?.auth.apiKey;\n\tif (!accessToken) return undefined;\n\n\tconst response = await fetchWithTimeout(XAI_BILLING_URL, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\tAccept: \"application/json\",\n\t\t\t\"x-xai-token-auth\": \"xai-grok-cli\",\n\t\t},\n\t});\n\tif (response.status === 401 || response.status === 403) {\n\t\tthrow new ModelsError(\"oauth\", `xAI billing rejected the session (HTTP ${response.status})`);\n\t}\n\tif (!response.ok) return undefined;\n\tconst payload = asObject(await response.json());\n\tif (!payload) return undefined;\n\tconst config = asObject(payload.config) ?? payload;\n\n\tconst windows: PlanUsageWindow[] = [];\n\tconst weekly = weeklyWindow(config);\n\tif (weekly) windows.push(weekly);\n\n\tconst onDemandCap = unwrapVal(config.onDemandCap);\n\tif (onDemandCap !== undefined && onDemandCap > 0) {\n\t\tconst usedPercent = usedPercentFromUsed(onDemandCap, unwrapVal(config.onDemandUsed) ?? 0);\n\t\tif (usedPercent !== undefined) {\n\t\t\twindows.push({\n\t\t\t\tlabel: \"Extra\",\n\t\t\t\tusedPercent,\n\t\t\t\tresetsAt: weekly?.resetsAt,\n\t\t\t});\n\t\t}\n\t}\n\n\tif (windows.length === 0) return undefined;\n\tconst planLabel = asString(config.subscriptionTier) ?? asString(config.subscription_tier);\n\treturn { provider: XAI_PROVIDER_ID, planLabel, windows };\n}\n"]}
@@ -9,7 +9,8 @@
9
9
  * fall back to hiding the cost meter.
10
10
  * - ollama-cloud: no usage API exists.
11
11
  *
12
- * All adapter/network errors resolve to `undefined` callers omit the UI.
12
+ * Adapter/network errors resolve to `undefined` (callers omit the plan UI).
13
+ * Auth failures are different: they return `error` and are not cached as empty.
13
14
  */
14
15
  import type { ModelRuntime } from "./model-runtime.ts";
15
16
  export interface PlanUsageWindow {
@@ -23,11 +24,20 @@ export interface PlanUsage {
23
24
  planLabel?: string;
24
25
  windows: PlanUsageWindow[];
25
26
  }
27
+ export interface PlanUsageResult {
28
+ usage?: PlanUsage;
29
+ /** Actionable auth failure. Not cached as an empty success. */
30
+ error?: string;
31
+ }
32
+ /** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */
33
+ export declare function planUsageAuthError(error: unknown): string | undefined;
26
34
  export declare const PLAN_USAGE_CACHE_TTL_MS: number;
27
35
  /** Whether a plan-usage adapter exists for this provider. */
28
36
  export declare function hasPlanUsageAdapter(providerId: string): boolean;
29
37
  /** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */
30
38
  export declare function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined>;
39
+ /** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */
40
+ export declare function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult>;
31
41
  /** Clear the adapter cache (tests, /login changes). */
32
42
  export declare function clearPlanUsageCache(): void;
33
43
  //# sourceMappingURL=usage-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAWD,eAAO,MAAM,uBAAuB,QAAgB,CAAC;AAIrD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAc5G;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (5-minute cache each) so /usage can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * All adapter/network errors resolve to `undefined` callers omit the UI.\n */\n\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return undefined;\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return cached.value;\n\tlet value: PlanUsage | undefined;\n\ttry {\n\t\tvalue = await adapter(runtime);\n\t} catch {\n\t\tvalue = undefined;\n\t}\n\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });\n\treturn value;\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n"]}
1
+ {"version":3,"file":"usage-service.d.ts","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAoBD,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASrE;AAWD,eAAO,MAAM,uBAAuB,QAAgB,CAAC;AAIrD,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,0FAA0F;AAC1F,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAE5G;AAED,sFAAsF;AACtF,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAgB5G;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (5-minute cache each) so /usage can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/invalid_grant|oauth refresh failed for xai|xai billing rejected/i.test(chain)) {\n\t\treturn XAI_RELOGIN;\n\t}\n\tif (error instanceof ModelsError && (error.code === \"oauth\" || error.code === \"auth\") && /xai/i.test(chain)) {\n\t\treturn XAI_RELOGIN;\n\t}\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\ttry {\n\t\tconst value = await adapter(runtime);\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\treturn { usage: value };\n\t} catch (error) {\n\t\tconst authError = planUsageAuthError(error);\n\t\tif (authError) return { error: authError };\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\treturn {};\n\t}\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n"]}
@@ -9,12 +9,41 @@
9
9
  * fall back to hiding the cost meter.
10
10
  * - ollama-cloud: no usage API exists.
11
11
  *
12
- * All adapter/network errors resolve to `undefined` callers omit the UI.
12
+ * Adapter/network errors resolve to `undefined` (callers omit the plan UI).
13
+ * Auth failures are different: they return `error` and are not cached as empty.
13
14
  */
15
+ import { ModelsError } from "@ashx-j/lunr-ai";
14
16
  import { fetchKimiPlanUsage } from "./usage-adapters/kimi-coding.js";
15
17
  import { fetchCodexPlanUsage } from "./usage-adapters/openai-codex.js";
16
18
  import { fetchXaiPlanUsage } from "./usage-adapters/xai.js";
17
19
  import { fetchZaiPlanUsage } from "./usage-adapters/zai.js";
20
+ const XAI_RELOGIN = "xAI login expired. Run /login xai.";
21
+ function errorChain(error) {
22
+ const parts = [];
23
+ let current = error;
24
+ const seen = new Set();
25
+ while (current && typeof current === "object" && !seen.has(current)) {
26
+ seen.add(current);
27
+ if (current instanceof Error) {
28
+ parts.push(current.message);
29
+ current = current.cause;
30
+ continue;
31
+ }
32
+ break;
33
+ }
34
+ return parts.join(" ");
35
+ }
36
+ /** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */
37
+ export function planUsageAuthError(error) {
38
+ const chain = errorChain(error);
39
+ if (/invalid_grant|oauth refresh failed for xai|xai billing rejected/i.test(chain)) {
40
+ return XAI_RELOGIN;
41
+ }
42
+ if (error instanceof ModelsError && (error.code === "oauth" || error.code === "auth") && /xai/i.test(chain)) {
43
+ return XAI_RELOGIN;
44
+ }
45
+ return undefined;
46
+ }
18
47
  const ADAPTERS = {
19
48
  "openai-codex": fetchCodexPlanUsage,
20
49
  "kimi-coding": fetchKimiPlanUsage,
@@ -29,22 +58,29 @@ export function hasPlanUsageAdapter(providerId) {
29
58
  }
30
59
  /** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */
31
60
  export async function getPlanUsage(providerId, runtime) {
61
+ return (await getPlanUsageResult(providerId, runtime)).usage;
62
+ }
63
+ /** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */
64
+ export async function getPlanUsageResult(providerId, runtime) {
32
65
  const adapter = ADAPTERS[providerId];
33
66
  if (!adapter)
34
- return undefined;
67
+ return {};
35
68
  const now = Date.now();
36
69
  const cached = cache.get(providerId);
37
70
  if (cached && cached.expiresAt > now)
38
- return cached.value;
39
- let value;
71
+ return { usage: cached.value };
40
72
  try {
41
- value = await adapter(runtime);
73
+ const value = await adapter(runtime);
74
+ cache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });
75
+ return { usage: value };
42
76
  }
43
- catch {
44
- value = undefined;
77
+ catch (error) {
78
+ const authError = planUsageAuthError(error);
79
+ if (authError)
80
+ return { error: authError };
81
+ cache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value: undefined });
82
+ return {};
45
83
  }
46
- cache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });
47
- return value;
48
84
  }
49
85
  /** Clear the adapter cache (tests, /login changes). */
50
86
  export function clearPlanUsageCache() {
@@ -1 +1 @@
1
- {"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAiB5D,MAAM,QAAQ,GAA2C;IACxD,cAAc,EAAE,mBAAmB;IACnC,aAAa,EAAE,kBAAkB;IACjC,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAErD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+D,CAAC;AAErF,6DAA6D;AAC7D,MAAM,UAAU,mBAAmB,CAAC,UAAkB,EAAW;IAChE,OAAO,UAAU,IAAI,QAAQ,CAAC;AAAA,CAC9B;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB,EAAE,OAAqB,EAAkC;IAC7G,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,MAAM,IAAI,MAAM,CAAC,SAAS,GAAG,GAAG;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC;IAC1D,IAAI,KAA4B,CAAC;IACjC,IAAI,CAAC;QACJ,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACR,KAAK,GAAG,SAAS,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,GAAG,GAAG,uBAAuB,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC;AAAA,CACb;AAED,uDAAuD;AACvD,MAAM,UAAU,mBAAmB,GAAS;IAC3C,KAAK,CAAC,KAAK,EAAE,CAAC;AAAA,CACd;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (5-minute cache each) so /usage can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * All adapter/network errors resolve to `undefined` callers omit the UI.\n */\n\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return undefined;\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return cached.value;\n\tlet value: PlanUsage | undefined;\n\ttry {\n\t\tvalue = await adapter(runtime);\n\t} catch {\n\t\tvalue = undefined;\n\t}\n\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });\n\treturn value;\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n"]}
1
+ {"version":3,"file":"usage-service.js","sourceRoot":"","sources":["../../src/core/usage-service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan/subscription usage service. Per-provider adapters query provider quota\n * endpoints (5-minute cache each) so /usage can show subscription windows\n * alongside session/context totals.\n *\n * Deliberately absent adapters:\n * - anthropic: Anthropic policy prohibits subscription usage tracking in\n * third-party coding agents (2026-07-18 decision). OAuth Anthropic sessions\n * fall back to hiding the cost meter.\n * - ollama-cloud: no usage API exists.\n *\n * Adapter/network errors resolve to `undefined` (callers omit the plan UI).\n * Auth failures are different: they return `error` and are not cached as empty.\n */\n\nimport { ModelsError } from \"@ashx-j/lunr-ai\";\nimport type { ModelRuntime } from \"./model-runtime.ts\";\nimport { fetchKimiPlanUsage } from \"./usage-adapters/kimi-coding.ts\";\nimport { fetchCodexPlanUsage } from \"./usage-adapters/openai-codex.ts\";\nimport { fetchXaiPlanUsage } from \"./usage-adapters/xai.ts\";\nimport { fetchZaiPlanUsage } from \"./usage-adapters/zai.ts\";\n\nexport interface PlanUsageWindow {\n\tlabel: string;\n\tusedPercent: number;\n\t/** Epoch ms when the window resets. */\n\tresetsAt?: number;\n}\n\nexport interface PlanUsage {\n\tprovider: string;\n\tplanLabel?: string;\n\twindows: PlanUsageWindow[];\n}\n\nexport interface PlanUsageResult {\n\tusage?: PlanUsage;\n\t/** Actionable auth failure. Not cached as an empty success. */\n\terror?: string;\n}\n\nconst XAI_RELOGIN = \"xAI login expired. Run /login xai.\";\n\nfunction errorChain(error: unknown): string {\n\tconst parts: string[] = [];\n\tlet current: unknown = error;\n\tconst seen = new Set<unknown>();\n\twhile (current && typeof current === \"object\" && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (current instanceof Error) {\n\t\t\tparts.push(current.message);\n\t\t\tcurrent = current.cause;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn parts.join(\" \");\n}\n\n/** Classify adapter/getAuth failures that mean the SuperGrok session is dead. */\nexport function planUsageAuthError(error: unknown): string | undefined {\n\tconst chain = errorChain(error);\n\tif (/invalid_grant|oauth refresh failed for xai|xai billing rejected/i.test(chain)) {\n\t\treturn XAI_RELOGIN;\n\t}\n\tif (error instanceof ModelsError && (error.code === \"oauth\" || error.code === \"auth\") && /xai/i.test(chain)) {\n\t\treturn XAI_RELOGIN;\n\t}\n\treturn undefined;\n}\n\ntype UsageAdapter = (runtime: ModelRuntime) => Promise<PlanUsage | undefined>;\n\nconst ADAPTERS: Readonly<Record<string, UsageAdapter>> = {\n\t\"openai-codex\": fetchCodexPlanUsage,\n\t\"kimi-coding\": fetchKimiPlanUsage,\n\tzai: fetchZaiPlanUsage,\n\txai: fetchXaiPlanUsage,\n};\n\nexport const PLAN_USAGE_CACHE_TTL_MS = 5 * 60 * 1000;\n\nconst cache = new Map<string, { expiresAt: number; value: PlanUsage | undefined }>();\n\n/** Whether a plan-usage adapter exists for this provider. */\nexport function hasPlanUsageAdapter(providerId: string): boolean {\n\treturn providerId in ADAPTERS;\n}\n\n/** Plan usage for a provider, or undefined when unsupported/unavailable. Never throws. */\nexport async function getPlanUsage(providerId: string, runtime: ModelRuntime): Promise<PlanUsage | undefined> {\n\treturn (await getPlanUsageResult(providerId, runtime)).usage;\n}\n\n/** Like getPlanUsage, but surfaces SuperGrok/auth failures instead of hiding them. */\nexport async function getPlanUsageResult(providerId: string, runtime: ModelRuntime): Promise<PlanUsageResult> {\n\tconst adapter = ADAPTERS[providerId];\n\tif (!adapter) return {};\n\tconst now = Date.now();\n\tconst cached = cache.get(providerId);\n\tif (cached && cached.expiresAt > now) return { usage: cached.value };\n\ttry {\n\t\tconst value = await adapter(runtime);\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value });\n\t\treturn { usage: value };\n\t} catch (error) {\n\t\tconst authError = planUsageAuthError(error);\n\t\tif (authError) return { error: authError };\n\t\tcache.set(providerId, { expiresAt: now + PLAN_USAGE_CACHE_TTL_MS, value: undefined });\n\t\treturn {};\n\t}\n}\n\n/** Clear the adapter cache (tests, /login changes). */\nexport function clearPlanUsageCache(): void {\n\tcache.clear();\n}\n\n// ---------------------------------------------------------------------------\n// Extension bridge\n// ---------------------------------------------------------------------------\n"]}