axusage 3.1.0 → 3.3.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.
Files changed (88) hide show
  1. package/README.md +78 -194
  2. package/dist/adapters/claude.js +9 -8
  3. package/dist/adapters/coalesce-claude-usage-response.js +5 -7
  4. package/dist/adapters/{chatgpt.d.ts → codex.d.ts} +1 -1
  5. package/dist/adapters/{chatgpt.js → codex.js} +5 -5
  6. package/dist/adapters/copilot.d.ts +7 -0
  7. package/dist/adapters/copilot.js +58 -0
  8. package/dist/adapters/{parse-chatgpt-usage.d.ts → parse-codex-usage.d.ts} +3 -3
  9. package/dist/adapters/parse-copilot-usage.d.ts +15 -0
  10. package/dist/adapters/parse-copilot-usage.js +61 -0
  11. package/dist/cli.js +4 -21
  12. package/dist/commands/auth-setup-command.d.ts +1 -2
  13. package/dist/commands/auth-setup-command.js +44 -67
  14. package/dist/commands/auth-status-command.js +9 -40
  15. package/dist/commands/fetch-service-usage.d.ts +0 -1
  16. package/dist/commands/fetch-service-usage.js +1 -2
  17. package/dist/commands/run-auth-setup.d.ts +0 -10
  18. package/dist/commands/run-auth-setup.js +3 -80
  19. package/dist/commands/usage-command.d.ts +2 -7
  20. package/dist/commands/usage-command.js +7 -39
  21. package/dist/config/credential-sources.d.ts +3 -11
  22. package/dist/config/credential-sources.js +1 -1
  23. package/dist/services/get-service-access-token.d.ts +3 -3
  24. package/dist/services/get-service-access-token.js +11 -11
  25. package/dist/services/service-adapter-registry.d.ts +2 -2
  26. package/dist/services/service-adapter-registry.js +4 -4
  27. package/dist/services/service-diagnostics.d.ts +11 -0
  28. package/dist/services/service-diagnostics.js +29 -0
  29. package/dist/services/supported-service.d.ts +6 -2
  30. package/dist/services/supported-service.js +2 -6
  31. package/dist/types/{chatgpt.d.ts → codex.d.ts} +4 -4
  32. package/dist/types/{chatgpt.js → codex.js} +6 -6
  33. package/dist/types/copilot.d.ts +14 -0
  34. package/dist/types/copilot.js +21 -0
  35. package/dist/utils/check-cli-dependency.d.ts +2 -4
  36. package/dist/utils/check-cli-dependency.js +7 -4
  37. package/dist/utils/copilot-gh-token.d.ts +1 -0
  38. package/dist/utils/copilot-gh-token.js +38 -0
  39. package/dist/utils/format-requires-help-text.d.ts +17 -0
  40. package/dist/utils/format-requires-help-text.js +62 -0
  41. package/dist/utils/validate-root-options.d.ts +0 -3
  42. package/dist/utils/validate-root-options.js +2 -6
  43. package/package.json +15 -19
  44. package/dist/adapters/github-copilot.d.ts +0 -6
  45. package/dist/adapters/github-copilot.js +0 -57
  46. package/dist/adapters/parse-github-copilot-usage.d.ts +0 -23
  47. package/dist/adapters/parse-github-copilot-usage.js +0 -78
  48. package/dist/commands/auth-clear-command.d.ts +0 -7
  49. package/dist/commands/auth-clear-command.js +0 -84
  50. package/dist/commands/fetch-service-usage-with-reauth.d.ts +0 -7
  51. package/dist/commands/fetch-service-usage-with-reauth.js +0 -45
  52. package/dist/services/app-paths.d.ts +0 -9
  53. package/dist/services/app-paths.js +0 -39
  54. package/dist/services/auth-storage-path.d.ts +0 -3
  55. package/dist/services/auth-storage-path.js +0 -7
  56. package/dist/services/auth-timeouts.d.ts +0 -4
  57. package/dist/services/auth-timeouts.js +0 -4
  58. package/dist/services/browser-auth-manager.d.ts +0 -49
  59. package/dist/services/browser-auth-manager.js +0 -113
  60. package/dist/services/create-auth-context.d.ts +0 -8
  61. package/dist/services/create-auth-context.js +0 -35
  62. package/dist/services/do-setup-auth.d.ts +0 -3
  63. package/dist/services/do-setup-auth.js +0 -19
  64. package/dist/services/fetch-json-with-context.d.ts +0 -5
  65. package/dist/services/fetch-json-with-context.js +0 -37
  66. package/dist/services/launch-chromium.d.ts +0 -6
  67. package/dist/services/launch-chromium.js +0 -20
  68. package/dist/services/persist-storage-state.d.ts +0 -6
  69. package/dist/services/persist-storage-state.js +0 -16
  70. package/dist/services/request-service.d.ts +0 -3
  71. package/dist/services/request-service.js +0 -4
  72. package/dist/services/service-auth-configs.d.ts +0 -15
  73. package/dist/services/service-auth-configs.js +0 -26
  74. package/dist/services/setup-auth-flow.d.ts +0 -3
  75. package/dist/services/setup-auth-flow.js +0 -67
  76. package/dist/services/shared-browser-auth-manager.d.ts +0 -4
  77. package/dist/services/shared-browser-auth-manager.js +0 -87
  78. package/dist/services/verify-session.d.ts +0 -2
  79. package/dist/services/verify-session.js +0 -27
  80. package/dist/services/wait-for-login.d.ts +0 -6
  81. package/dist/services/wait-for-login.js +0 -115
  82. package/dist/types/github-copilot.d.ts +0 -21
  83. package/dist/types/github-copilot.js +0 -27
  84. package/dist/utils/resolve-prompt-capability.d.ts +0 -1
  85. package/dist/utils/resolve-prompt-capability.js +0 -3
  86. package/dist/utils/write-atomic-json.d.ts +0 -1
  87. package/dist/utils/write-atomic-json.js +0 -56
  88. /package/dist/adapters/{parse-chatgpt-usage.js → parse-codex-usage.js} +0 -0
@@ -1,14 +1,14 @@
1
- import { chatGPTAdapter } from "../adapters/chatgpt.js";
1
+ import { codexAdapter } from "../adapters/codex.js";
2
2
  import { claudeAdapter } from "../adapters/claude.js";
3
3
  import { geminiAdapter } from "../adapters/gemini.js";
4
- import { githubCopilotAdapter } from "../adapters/github-copilot.js";
4
+ import { copilotAdapter } from "../adapters/copilot.js";
5
5
  /**
6
6
  * Registry of available service adapters
7
7
  */
8
8
  export const SERVICE_ADAPTERS = {
9
9
  claude: claudeAdapter,
10
- chatgpt: chatGPTAdapter,
11
- "github-copilot": githubCopilotAdapter,
10
+ codex: codexAdapter,
11
+ copilot: copilotAdapter,
12
12
  gemini: geminiAdapter,
13
13
  };
14
14
  /**
@@ -0,0 +1,11 @@
1
+ import type { SupportedService } from "./supported-service.js";
2
+ type ServiceDiagnostic = {
3
+ readonly service: SupportedService;
4
+ readonly cliAvailable: boolean;
5
+ readonly cliPath: string;
6
+ readonly authenticated: boolean;
7
+ readonly authMethod: string | undefined;
8
+ };
9
+ export type { ServiceDiagnostic };
10
+ export declare function getServiceDiagnostic(service: SupportedService): ServiceDiagnostic;
11
+ export declare function getAllServiceDiagnostics(): ServiceDiagnostic[];
@@ -0,0 +1,29 @@
1
+ import { checkAuth } from "axauth";
2
+ import { checkCliDependency, getAuthCliDependency, } from "../utils/check-cli-dependency.js";
3
+ import { getCopilotTokenFromCustomGhPath } from "../utils/copilot-gh-token.js";
4
+ import { SUPPORTED_SERVICES } from "./supported-service.js";
5
+ export function getServiceDiagnostic(service) {
6
+ const dependency = getAuthCliDependency(service);
7
+ const cliResult = checkCliDependency(dependency);
8
+ let authResult = checkAuth(service);
9
+ if (service === "copilot" && !authResult.authenticated) {
10
+ const tokenFromOverride = getCopilotTokenFromCustomGhPath();
11
+ if (tokenFromOverride) {
12
+ authResult = {
13
+ ...authResult,
14
+ authenticated: true,
15
+ method: "GitHub CLI (AXUSAGE_GH_PATH)",
16
+ };
17
+ }
18
+ }
19
+ return {
20
+ service,
21
+ cliAvailable: cliResult.ok,
22
+ cliPath: cliResult.path,
23
+ authenticated: authResult.authenticated,
24
+ authMethod: authResult.method,
25
+ };
26
+ }
27
+ export function getAllServiceDiagnostics() {
28
+ return SUPPORTED_SERVICES.map((service) => getServiceDiagnostic(service));
29
+ }
@@ -1,6 +1,10 @@
1
+ import type { AgentCli } from "axauth";
1
2
  /**
2
- * Supported service names for usage tracking
3
+ * Supported service names for usage tracking.
4
+ *
5
+ * Derived from the canonical AGENT_CLIS list, excluding agents
6
+ * that axusage doesn't yet support (opencode).
3
7
  */
4
- export type SupportedService = "claude" | "chatgpt" | "github-copilot" | "gemini";
8
+ export type SupportedService = Exclude<AgentCli, "opencode">;
5
9
  export declare const SUPPORTED_SERVICES: SupportedService[];
6
10
  export declare function validateService(service: string | undefined): SupportedService;
@@ -1,9 +1,5 @@
1
- export const SUPPORTED_SERVICES = [
2
- "claude",
3
- "chatgpt",
4
- "github-copilot",
5
- "gemini",
6
- ];
1
+ import { AGENT_CLIS } from "axauth";
2
+ export const SUPPORTED_SERVICES = AGENT_CLIS.filter((cli) => cli !== "opencode");
7
3
  export function validateService(service) {
8
4
  if (!service) {
9
5
  throw new Error(`Service is required. Supported services: ${SUPPORTED_SERVICES.join(", ")}. ` +
@@ -2,14 +2,14 @@ import { z } from "zod";
2
2
  /**
3
3
  * ChatGPT API response schemas
4
4
  */
5
- export declare const ChatGPTRateLimitWindow: z.ZodObject<{
5
+ export declare const CodexRateLimitWindow: z.ZodObject<{
6
6
  used_percent: z.ZodNumber;
7
7
  limit_window_seconds: z.ZodNumber;
8
8
  reset_after_seconds: z.ZodNumber;
9
9
  reset_at: z.ZodNumber;
10
10
  }, z.core.$strip>;
11
- export type ChatGPTRateLimitWindow = z.infer<typeof ChatGPTRateLimitWindow>;
12
- export declare const ChatGPTUsageResponse: z.ZodObject<{
11
+ export type CodexRateLimitWindow = z.infer<typeof CodexRateLimitWindow>;
12
+ export declare const CodexUsageResponse: z.ZodObject<{
13
13
  plan_type: z.ZodString;
14
14
  rate_limit: z.ZodObject<{
15
15
  allowed: z.ZodBoolean;
@@ -29,4 +29,4 @@ export declare const ChatGPTUsageResponse: z.ZodObject<{
29
29
  }, z.core.$strip>;
30
30
  credits: z.ZodNullable<z.ZodUnknown>;
31
31
  }, z.core.$strip>;
32
- export type ChatGPTUsageResponse = z.infer<typeof ChatGPTUsageResponse>;
32
+ export type CodexUsageResponse = z.infer<typeof CodexUsageResponse>;
@@ -2,20 +2,20 @@ import { z } from "zod";
2
2
  /**
3
3
  * ChatGPT API response schemas
4
4
  */
5
- export const ChatGPTRateLimitWindow = z.object({
5
+ export const CodexRateLimitWindow = z.object({
6
6
  used_percent: z.number(),
7
7
  limit_window_seconds: z.number(),
8
8
  reset_after_seconds: z.number(),
9
9
  reset_at: z.number(), // Unix timestamp
10
10
  });
11
- const ChatGPTRateLimit = z.object({
11
+ const CodexRateLimit = z.object({
12
12
  allowed: z.boolean(),
13
13
  limit_reached: z.boolean(),
14
- primary_window: ChatGPTRateLimitWindow,
15
- secondary_window: ChatGPTRateLimitWindow,
14
+ primary_window: CodexRateLimitWindow,
15
+ secondary_window: CodexRateLimitWindow,
16
16
  });
17
- export const ChatGPTUsageResponse = z.object({
17
+ export const CodexUsageResponse = z.object({
18
18
  plan_type: z.string(),
19
- rate_limit: ChatGPTRateLimit,
19
+ rate_limit: CodexRateLimit,
20
20
  credits: z.unknown().nullable(),
21
21
  });
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export declare const CopilotUsageResponse: z.ZodObject<{
3
+ quota_reset_date_utc: z.ZodString;
4
+ copilot_plan: z.ZodString;
5
+ quota_snapshots: z.ZodObject<{
6
+ premium_interactions: z.ZodObject<{
7
+ entitlement: z.ZodNumber;
8
+ remaining: z.ZodNumber;
9
+ percent_remaining: z.ZodNumber;
10
+ unlimited: z.ZodOptional<z.ZodBoolean>;
11
+ }, z.core.$strip>;
12
+ }, z.core.$strip>;
13
+ }, z.core.$strip>;
14
+ export type CopilotUsageResponse = z.infer<typeof CopilotUsageResponse>;
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * GitHub Copilot internal API response schema
4
+ * Endpoint: GET https://api.github.com/copilot_internal/user
5
+ */
6
+ const PremiumInteractionsSnapshot = z.object({
7
+ entitlement: z.number(),
8
+ remaining: z.number(),
9
+ percent_remaining: z.number(),
10
+ unlimited: z.boolean().optional(),
11
+ });
12
+ const QuotaSnapshots = z.object({
13
+ premium_interactions: PremiumInteractionsSnapshot,
14
+ });
15
+ export const CopilotUsageResponse = z.object({
16
+ quota_reset_date_utc: z
17
+ .string()
18
+ .refine((s) => !Number.isNaN(new Date(s).getTime()), "Invalid date"),
19
+ copilot_plan: z.string(),
20
+ quota_snapshots: QuotaSnapshots,
21
+ });
@@ -3,8 +3,7 @@ type CliDependency = {
3
3
  readonly envVar: string;
4
4
  readonly installHint: string;
5
5
  };
6
- declare const AUTH_CLI_SERVICES: readonly ["claude", "chatgpt", "gemini"];
7
- type AuthCliService = (typeof AUTH_CLI_SERVICES)[number];
6
+ type AuthCliService = "claude" | "codex" | "copilot" | "gemini";
8
7
  export declare function getAuthCliDependency(service: AuthCliService): CliDependency;
9
8
  export declare function checkCliDependency(dep: CliDependency): {
10
9
  ok: boolean;
@@ -21,5 +20,4 @@ export declare function ensureAuthCliDependency(service: AuthCliService): {
21
20
  export declare function resolveAuthCliDependencyOrReport(service: AuthCliService, options?: {
22
21
  readonly setExitCode?: boolean;
23
22
  }): string | undefined;
24
- export { AUTH_CLI_SERVICES };
25
- export type { AuthCliService };
23
+ export {};
@@ -11,13 +11,17 @@ const CLI_DEPENDENCIES = {
11
11
  envVar: "AXUSAGE_CODEX_PATH",
12
12
  installHint: "npm install -g @openai/codex",
13
13
  },
14
+ gh: {
15
+ command: "gh",
16
+ envVar: "AXUSAGE_GH_PATH",
17
+ installHint: "https://cli.github.com/ or brew install gh",
18
+ },
14
19
  gemini: {
15
20
  command: "gemini",
16
21
  envVar: "AXUSAGE_GEMINI_PATH",
17
22
  installHint: "npm install -g @google/gemini-cli",
18
23
  },
19
24
  };
20
- const AUTH_CLI_SERVICES = ["claude", "chatgpt", "gemini"];
21
25
  function resolveCliDependencyTimeout() {
22
26
  const raw = process.env.AXUSAGE_CLI_TIMEOUT_MS;
23
27
  if (!raw)
@@ -28,8 +32,8 @@ function resolveCliDependencyTimeout() {
28
32
  return Math.round(parsed);
29
33
  }
30
34
  export function getAuthCliDependency(service) {
31
- if (service === "chatgpt")
32
- return CLI_DEPENDENCIES.codex;
35
+ if (service === "copilot")
36
+ return CLI_DEPENDENCIES.gh;
33
37
  return CLI_DEPENDENCIES[service];
34
38
  }
35
39
  function resolveCliDependencyPath(dep) {
@@ -78,4 +82,3 @@ function reportMissingCliDependency(dependency, path) {
78
82
  console.error(chalk.gray(` 2. Set ${dependency.envVar}=/path/to/${dependency.command}`));
79
83
  console.error(chalk.gray("Try 'axusage --help' for requirements and overrides."));
80
84
  }
81
- export { AUTH_CLI_SERVICES };
@@ -0,0 +1 @@
1
+ export declare function getCopilotTokenFromCustomGhPath(): string | undefined;
@@ -0,0 +1,38 @@
1
+ import { execFileSync } from "node:child_process";
2
+ const GH_PATH_OVERRIDE_ENV = "AXUSAGE_GH_PATH";
3
+ const DEFAULT_TIMEOUT_MS = 5000;
4
+ function resolveCliTimeoutMs() {
5
+ const rawValue = process.env.AXUSAGE_CLI_TIMEOUT_MS;
6
+ if (!rawValue)
7
+ return DEFAULT_TIMEOUT_MS;
8
+ const parsed = Number(rawValue);
9
+ if (!Number.isFinite(parsed) || parsed <= 0)
10
+ return DEFAULT_TIMEOUT_MS;
11
+ return Math.round(parsed);
12
+ }
13
+ function resolveGhOverridePath() {
14
+ const value = process.env[GH_PATH_OVERRIDE_ENV]?.trim();
15
+ if (!value)
16
+ return undefined;
17
+ return value;
18
+ }
19
+ export function getCopilotTokenFromCustomGhPath() {
20
+ const path = resolveGhOverridePath();
21
+ if (!path)
22
+ return undefined;
23
+ try {
24
+ const token = execFileSync(path, ["auth", "token"], {
25
+ encoding: "utf8",
26
+ stdio: ["pipe", "pipe", "pipe"],
27
+ timeout: resolveCliTimeoutMs(),
28
+ }).trim();
29
+ // Copilot requires fine-grained tokens; reject classic PATs.
30
+ if (token && !token.startsWith("ghp_")) {
31
+ return token;
32
+ }
33
+ }
34
+ catch {
35
+ // Ignore command failures and fall back to other auth sources.
36
+ }
37
+ return undefined;
38
+ }
@@ -0,0 +1,17 @@
1
+ type RuntimeRequirement = {
2
+ readonly label: string;
3
+ readonly status: "ok";
4
+ } | {
5
+ readonly label: string;
6
+ readonly status: "missing" | "not-authorized";
7
+ readonly fix: string;
8
+ };
9
+ export type { RuntimeRequirement };
10
+ /**
11
+ * Formats a list of runtime requirements into a compact or detailed string.
12
+ *
13
+ * All-ok → single line: `Requires: claude, codex (ChatGPT), gemini, gh (Copilot)`
14
+ * Any non-ok → multi-line with inline remediation per requirement.
15
+ */
16
+ export declare function formatRequiresSection(requirements: readonly RuntimeRequirement[]): string;
17
+ export declare function formatRequiresHelpText(): string;
@@ -0,0 +1,62 @@
1
+ import { getAllServiceDiagnostics } from "../services/service-diagnostics.js";
2
+ import { getAuthCliDependency } from "./check-cli-dependency.js";
3
+ const SERVICE_LABELS = {
4
+ claude: "claude",
5
+ codex: "codex (ChatGPT)",
6
+ gemini: "gemini",
7
+ copilot: "gh (Copilot)",
8
+ };
9
+ const AUTH_FIX_COMMANDS = {
10
+ claude: "Run: claude",
11
+ codex: "Run: codex",
12
+ gemini: "Run: gemini",
13
+ copilot: "Run: gh auth login",
14
+ };
15
+ function diagnosticToRequirement(diagnostic) {
16
+ const label = SERVICE_LABELS[diagnostic.service];
17
+ if (!diagnostic.cliAvailable) {
18
+ const dependency = getAuthCliDependency(diagnostic.service);
19
+ return {
20
+ label,
21
+ status: "missing",
22
+ fix: `Install: ${dependency.installHint}. ` +
23
+ `Or set ${dependency.envVar}=/path/to/${dependency.command}`,
24
+ };
25
+ }
26
+ if (!diagnostic.authenticated) {
27
+ return {
28
+ label,
29
+ status: "not-authorized",
30
+ fix: AUTH_FIX_COMMANDS[diagnostic.service],
31
+ };
32
+ }
33
+ return { label, status: "ok" };
34
+ }
35
+ let cachedRequirements;
36
+ function getRuntimeRequirementsStatus() {
37
+ if (cachedRequirements)
38
+ return cachedRequirements;
39
+ cachedRequirements = getAllServiceDiagnostics().map((d) => diagnosticToRequirement(d));
40
+ return cachedRequirements;
41
+ }
42
+ /**
43
+ * Formats a list of runtime requirements into a compact or detailed string.
44
+ *
45
+ * All-ok → single line: `Requires: claude, codex (ChatGPT), gemini, gh (Copilot)`
46
+ * Any non-ok → multi-line with inline remediation per requirement.
47
+ */
48
+ export function formatRequiresSection(requirements) {
49
+ if (requirements.every((r) => r.status === "ok")) {
50
+ return `Requires: ${requirements.map((r) => r.label).join(", ")}`;
51
+ }
52
+ const lines = requirements.map((r) => {
53
+ if (r.status === "ok")
54
+ return ` - ${r.label}`;
55
+ const tag = r.status === "missing" ? "MISSING" : "NOT AUTHORIZED";
56
+ return ` - ${r.label} - ${tag}! ${r.fix}`;
57
+ });
58
+ return `Requires:\n${lines.join("\n")}`;
59
+ }
60
+ export function formatRequiresHelpText() {
61
+ return formatRequiresSection(getRuntimeRequirementsStatus());
62
+ }
@@ -2,10 +2,7 @@ import type { UsageCommandOptions } from "../commands/fetch-service-usage.js";
2
2
  export type RootOptions = {
3
3
  readonly authSetup?: string;
4
4
  readonly authStatus?: string | boolean;
5
- readonly authClear?: string;
6
- readonly force?: boolean;
7
5
  readonly service?: UsageCommandOptions["service"];
8
6
  readonly format?: UsageCommandOptions["format"];
9
- readonly interactive?: UsageCommandOptions["interactive"];
10
7
  };
11
8
  export declare function getRootOptionsError(options: RootOptions, formatSource?: string): string | undefined;
@@ -1,13 +1,9 @@
1
1
  export function getRootOptionsError(options, formatSource) {
2
2
  // Commander sets optional args to `true` when provided without a value.
3
3
  const authSelectionCount = Number(Boolean(options.authSetup)) +
4
- Number(options.authStatus !== undefined) +
5
- Number(Boolean(options.authClear));
4
+ Number(options.authStatus !== undefined);
6
5
  if (authSelectionCount > 1) {
7
- return "Use only one of --auth-setup, --auth-status, or --auth-clear.";
8
- }
9
- if (options.force && !options.authClear) {
10
- return "--force is only supported with --auth-clear.";
6
+ return "Use only one of --auth-setup or --auth-status.";
11
7
  }
12
8
  const hasExplicitFormat = formatSource === "cli";
13
9
  const hasUsageOptions = Boolean(options.service) || hasExplicitFormat;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "axusage",
3
3
  "author": "Łukasz Jerciński",
4
4
  "license": "MIT",
5
- "version": "3.1.0",
5
+ "version": "3.3.0",
6
6
  "description": "Monitor API usage across Claude, ChatGPT, GitHub Copilot, and Gemini from a single CLI",
7
7
  "repository": {
8
8
  "type": "git",
@@ -19,7 +19,6 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "scripts": {
22
- "postinstall": "playwright install chromium",
23
22
  "prepare": "git config core.hooksPath .githooks",
24
23
  "prepublishOnly": "pnpm run rebuild",
25
24
  "build": "tsc -p tsconfig.app.json",
@@ -48,35 +47,32 @@
48
47
  "llm",
49
48
  "monitoring"
50
49
  ],
51
- "packageManager": "pnpm@10.25.0",
50
+ "packageManager": "pnpm@10.30.1",
52
51
  "engines": {
53
52
  "node": ">=22.14.0"
54
53
  },
55
54
  "dependencies": {
56
55
  "@commander-js/extra-typings": "^14.0.0",
57
- "@inquirer/prompts": "^8.2.0",
58
- "axauth": "^2.1.0",
56
+ "axauth": "^3.1.6",
59
57
  "chalk": "^5.6.2",
60
- "commander": "^14.0.2",
61
- "conf": "^15.0.2",
62
- "env-paths": "^3.0.0",
63
- "playwright": "^1.57.0",
58
+ "commander": "^14.0.3",
59
+ "conf": "^15.1.0",
60
+ "env-paths": "^4.0.0",
64
61
  "prom-client": "^15.1.3",
65
- "trash": "^10.0.1",
66
- "zod": "^4.3.5"
62
+ "zod": "^4.3.6"
67
63
  },
68
64
  "devDependencies": {
69
65
  "@total-typescript/ts-reset": "^0.6.1",
70
- "@types/node": "^25.0.9",
71
- "@vitest/coverage-v8": "^4.0.17",
72
- "eslint": "^9.39.2",
73
- "eslint-config-axkit": "^1.1.0",
66
+ "@types/node": "^25.3.0",
67
+ "@vitest/coverage-v8": "^4.0.18",
68
+ "eslint": "^10.0.1",
69
+ "eslint-config-axkit": "^1.2.1",
74
70
  "fta-check": "^1.5.1",
75
71
  "fta-cli": "^3.0.0",
76
- "knip": "^5.81.0",
77
- "prettier": "3.8.0",
78
- "semantic-release": "^25.0.2",
72
+ "knip": "^5.85.0",
73
+ "prettier": "3.8.1",
74
+ "semantic-release": "^25.0.3",
79
75
  "typescript": "^5.9.3",
80
- "vitest": "^4.0.17"
76
+ "vitest": "^4.0.18"
81
77
  }
82
78
  }
@@ -1,6 +0,0 @@
1
- import type { ServiceAdapter } from "../types/domain.js";
2
- /** Functional core is extracted to ./parse-github-copilot-usage.ts */
3
- /**
4
- * GitHub Copilot service adapter
5
- */
6
- export declare const githubCopilotAdapter: ServiceAdapter;
@@ -1,57 +0,0 @@
1
- import { ApiError } from "../types/domain.js";
2
- import { GitHubCopilotUsageResponse as GitHubCopilotUsageResponseSchema } from "../types/github-copilot.js";
3
- import { toServiceUsageData } from "./parse-github-copilot-usage.js";
4
- import { acquireAuthManager, releaseAuthManager, } from "../services/shared-browser-auth-manager.js";
5
- // Copilot web fetches entitlements from this endpoint (requires GitHub session cookies)
6
- const API_URL = "https://github.com/github-copilot/chat/entitlement";
7
- /** Functional core is extracted to ./parse-github-copilot-usage.ts */
8
- /**
9
- * GitHub Copilot service adapter
10
- */
11
- export const githubCopilotAdapter = {
12
- name: "GitHub Copilot",
13
- async fetchUsage() {
14
- const manager = acquireAuthManager();
15
- try {
16
- if (!manager.hasAuth("github-copilot")) {
17
- return {
18
- ok: false,
19
- error: new ApiError("No saved authentication for github-copilot. " +
20
- "Run 'axusage --auth-setup github-copilot --interactive' first."),
21
- };
22
- }
23
- const body = await manager.makeAuthenticatedRequest("github-copilot", API_URL);
24
- const data = JSON.parse(body);
25
- const parseResult = GitHubCopilotUsageResponseSchema.safeParse(data);
26
- if (!parseResult.success) {
27
- return {
28
- ok: false,
29
- error: new ApiError(`Invalid response format: ${parseResult.error.message}`, undefined, data),
30
- };
31
- }
32
- try {
33
- return {
34
- ok: true,
35
- value: toServiceUsageData(parseResult.data),
36
- };
37
- }
38
- catch (error) {
39
- return {
40
- ok: false,
41
- error: new ApiError(error instanceof Error
42
- ? error.message
43
- : "Unable to parse GitHub Copilot reset date", undefined, parseResult.data.quotas.resetDate),
44
- };
45
- }
46
- }
47
- catch (error) {
48
- return {
49
- ok: false,
50
- error: new ApiError(`Browser authentication failed: ${error instanceof Error ? error.message : String(error)}`),
51
- };
52
- }
53
- finally {
54
- await releaseAuthManager();
55
- }
56
- },
57
- };
@@ -1,23 +0,0 @@
1
- import type { ServiceUsageData } from "../types/domain.js";
2
- import type { GitHubCopilotUsageResponse } from "../types/github-copilot.js";
3
- /**
4
- * Parses GitHub reset date (YYYY-MM-DD) into a UTC Date
5
- */
6
- export declare function parseResetDate(resetDateString: string): Date;
7
- /**
8
- * Calculates monthly period duration ending at the reset date
9
- *
10
- * Determines the period start by going back one month from the reset
11
- * date and clamping the day to the last valid day of that previous
12
- * month. This handles edge cases like Jan 31 → Feb 28/29 where the
13
- * target month has fewer days than the reset date's day component.
14
- *
15
- * Example:
16
- * For resetDate = 2025-03-31, calculates duration from 2025-02-28 (clamped)
17
- * to 2025-03-31.
18
- */
19
- export declare function calculatePeriodDuration(resetDate: Date): number;
20
- /**
21
- * Converts GitHub Copilot response to common domain model
22
- */
23
- export declare function toServiceUsageData(response: GitHubCopilotUsageResponse): ServiceUsageData;
@@ -1,78 +0,0 @@
1
- const MS_PER_DAY = 24 * 60 * 60 * 1000;
2
- /**
3
- * Parses GitHub reset date (YYYY-MM-DD) into a UTC Date
4
- */
5
- export function parseResetDate(resetDateString) {
6
- const parts = resetDateString.split("-");
7
- if (parts.length !== 3) {
8
- throw new Error(`Invalid reset date format: ${resetDateString}`);
9
- }
10
- const [yearString, monthString, dayString] = parts;
11
- if (!yearString || !monthString || !dayString) {
12
- throw new Error(`Invalid reset date components: ${resetDateString}`);
13
- }
14
- const year = Number(yearString);
15
- const month = Number(monthString);
16
- const day = Number(dayString);
17
- if (Number.isNaN(year) ||
18
- Number.isNaN(month) ||
19
- Number.isNaN(day) ||
20
- month < 1 ||
21
- month > 12 ||
22
- day < 1 ||
23
- day > 31) {
24
- throw new Error(`Invalid reset date components: ${resetDateString}`);
25
- }
26
- return new Date(Date.UTC(year, month - 1, day, 0, 0, 0));
27
- }
28
- /**
29
- * Calculates monthly period duration ending at the reset date
30
- *
31
- * Determines the period start by going back one month from the reset
32
- * date and clamping the day to the last valid day of that previous
33
- * month. This handles edge cases like Jan 31 → Feb 28/29 where the
34
- * target month has fewer days than the reset date's day component.
35
- *
36
- * Example:
37
- * For resetDate = 2025-03-31, calculates duration from 2025-02-28 (clamped)
38
- * to 2025-03-31.
39
- */
40
- export function calculatePeriodDuration(resetDate) {
41
- const periodEnd = resetDate.getTime();
42
- // Determine previous month and clamp day to its last day
43
- const year = resetDate.getUTCFullYear();
44
- const month = resetDate.getUTCMonth(); // 0-based
45
- const day = resetDate.getUTCDate();
46
- // First day of current month in UTC
47
- const firstOfCurrentMonth = Date.UTC(year, month, 1, 0, 0, 0);
48
- // Last day of previous month: subtract 1 day from first of current month
49
- const lastPreviousMonthDate = new Date(firstOfCurrentMonth - MS_PER_DAY);
50
- const lastPreviousMonthDay = lastPreviousMonthDate.getUTCDate();
51
- const previousMonth = lastPreviousMonthDate.getUTCMonth();
52
- const previousYear = lastPreviousMonthDate.getUTCFullYear();
53
- const targetDay = Math.min(day, lastPreviousMonthDay);
54
- const periodStart = Date.UTC(previousYear, previousMonth, targetDay, 0, 0, 0);
55
- return Math.max(periodEnd - periodStart, 0);
56
- }
57
- /**
58
- * Converts GitHub Copilot response to common domain model
59
- */
60
- export function toServiceUsageData(response) {
61
- const resetDate = parseResetDate(response.quotas.resetDate);
62
- const periodDurationMs = calculatePeriodDuration(resetDate);
63
- const used = response.quotas.limits.premiumInteractions -
64
- response.quotas.remaining.premiumInteractions;
65
- const utilization = (used / response.quotas.limits.premiumInteractions) * 100;
66
- return {
67
- service: "GitHub Copilot",
68
- planType: response.plan,
69
- windows: [
70
- {
71
- name: "Monthly Premium Interactions",
72
- utilization: Math.round(utilization * 100) / 100,
73
- resetsAt: resetDate,
74
- periodDurationMs,
75
- },
76
- ],
77
- };
78
- }
@@ -1,7 +0,0 @@
1
- type AuthClearOptions = {
2
- readonly service?: string;
3
- readonly interactive?: boolean;
4
- readonly force?: boolean;
5
- };
6
- export declare function authClearCommand(options: AuthClearOptions): Promise<void>;
7
- export {};