@howaboua/opencode-usage-plugin 0.1.0 → 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.
package/README.md CHANGED
@@ -6,6 +6,7 @@ Track AI provider rate limits and quotas in real-time.
6
6
 
7
7
  - **Live rate limits** – See Codex/OpenAI hourly/weekly limits at a glance
8
8
  - **Proxy quota stats** – Monitor Mirrowel Proxy credentials and tier usage
9
+ - **Copilot usage** – Track GitHub Copilot chat + completions quotas
9
10
  - **Inline status** – Results appear directly in your chat, no context switching
10
11
  - **Zero setup** – Auto-detects providers from your existing config
11
12
 
@@ -18,7 +19,7 @@ Add to your `opencode.json`:
18
19
  ```json
19
20
  {
20
21
  "$schema": "https://opencode.ai/config.json",
21
- "plugins": ["@howaboua/opencode-usage-plugin"]
22
+ "plugin": ["@howaboua/opencode-usage-plugin"]
22
23
  }
23
24
  ```
24
25
 
@@ -37,6 +38,7 @@ OpenCode installs dependencies automatically on next launch.
37
38
  ```
38
39
  /usage codex
39
40
  /usage proxy
41
+ /usage copilot
40
42
  ```
41
43
 
42
44
  ### Support the proxy
@@ -51,6 +53,7 @@ OpenCode installs dependencies automatically on next launch.
51
53
  |----------|--------|
52
54
  | **Codex / OpenAI** | Auth tokens + `/wham/usage` endpoint |
53
55
  | **Mirrowel Proxy** | Local `/v1/quota-stats` endpoint |
56
+ | **GitHub Copilot** | GitHub internal usage APIs |
54
57
 
55
58
  ## Configuration
56
59
 
@@ -70,21 +73,20 @@ Optional config at `~/.config/opencode/usage-config.jsonc`:
70
73
  // Show/hide providers in /usage output
71
74
  "providers": {
72
75
  "openai": true,
73
- "proxy": true
76
+ "proxy": true,
77
+ "copilot": true
74
78
  }
75
79
  }
76
80
  ```
77
81
 
78
82
  If missing, the plugin creates a default template on first run.
79
83
 
80
- ## Development
84
+ ### Copilot auth
81
85
 
82
- ```bash
83
- # Check DB contents
84
- bun run debug-db.ts
86
+ Copilot is detected from either of these locations:
85
87
 
86
- # Verify path resolution
87
- bun run debug-path.ts
88
- ```
88
+ - `~/.local/share/opencode/copilot-usage-token.json`
89
+ - `~/.local/share/opencode/auth.json` with a `github-copilot` entry
90
+ - `~/.config/opencode/copilot-quota-token.json` (optional override)
89
91
 
90
92
  See `AGENTS.md` for internal architecture.
@@ -33,7 +33,7 @@ export function commandHooks(options) {
33
33
  const snapshots = await fetchUsageSnapshots(effectiveFilter);
34
34
  const filteredSnapshots = snapshots.filter(s => {
35
35
  if (targetProvider)
36
- return true; // User explicitly asked for it
36
+ return true;
37
37
  if (s.provider === "codex")
38
38
  return options.state.availableProviders.codex;
39
39
  if (s.provider === "proxy")
@@ -1,11 +1,8 @@
1
1
  /**
2
2
  * providers/copilot/auth.ts
3
3
  * Provides authentication and configuration helpers for GitHub Copilot.
4
- * Handles local auth token discovery and quota configuration reading.
4
+ * Handles local auth token discovery and standard OpenCode credentials.
5
5
  */
6
- import { type CopilotAuthData, type CopilotQuotaConfig } from "./types.js";
7
- export declare function getQuotaConfigPath(): string;
8
- export declare function getUsageTokenPath(): string;
6
+ import { type CopilotAuthData } from "./types.js";
9
7
  export declare function readCopilotAuth(): Promise<CopilotAuthData | null>;
10
- export declare function readQuotaConfig(): CopilotQuotaConfig | null;
11
8
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAE1E,wBAAgB,kBAAkB,IAAI,MAAM,CAM3C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA4BvE;AAED,wBAAgB,eAAe,IAAI,kBAAkB,GAAG,IAAI,CAY3D"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAevE"}
@@ -1,33 +1,13 @@
1
1
  /**
2
2
  * providers/copilot/auth.ts
3
3
  * Provides authentication and configuration helpers for GitHub Copilot.
4
- * Handles local auth token discovery and quota configuration reading.
4
+ * Handles local auth token discovery and standard OpenCode credentials.
5
5
  */
6
- import { existsSync, readFileSync } from "fs";
6
+ import { existsSync } from "fs";
7
7
  import { readFile } from "fs/promises";
8
- import { homedir } from "os";
9
- import { join } from "path";
10
- import { getAppDataPath, getAuthFilePath } from "../../utils/paths.js";
11
- export function getQuotaConfigPath() {
12
- return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "opencode", "copilot-quota-token.json");
13
- }
14
- export function getUsageTokenPath() {
15
- return join(getAppDataPath(), "copilot-usage-token.json");
16
- }
8
+ import { getAuthFilePath } from "../../utils/paths.js";
17
9
  export async function readCopilotAuth() {
18
10
  try {
19
- const usagePath = getUsageTokenPath();
20
- if (existsSync(usagePath)) {
21
- const content = await readFile(usagePath, "utf-8");
22
- const data = JSON.parse(content);
23
- if (data?.token) {
24
- return {
25
- type: "oauth",
26
- refresh: data.token,
27
- access: data.token,
28
- };
29
- }
30
- }
31
11
  const authPath = getAuthFilePath();
32
12
  if (existsSync(authPath)) {
33
13
  const content = await readFile(authPath, "utf-8");
@@ -43,18 +23,3 @@ export async function readCopilotAuth() {
43
23
  return null;
44
24
  }
45
25
  }
46
- export function readQuotaConfig() {
47
- try {
48
- const configPath = getQuotaConfigPath();
49
- if (!existsSync(configPath))
50
- return null;
51
- const content = readFileSync(configPath, "utf-8");
52
- const parsed = JSON.parse(content);
53
- if (!parsed?.token || !parsed?.username || !parsed?.tier)
54
- return null;
55
- return parsed;
56
- }
57
- catch {
58
- return null;
59
- }
60
- }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * providers/copilot/index.ts
3
3
  * Main entry point for the GitHub Copilot usage provider.
4
- * Orchestrates token exchange and fetching from public and internal APIs.
4
+ * Orchestrates token exchange and fetching from the internal API.
5
5
  */
6
6
  import type { UsageProvider } from "../base.js";
7
7
  export declare const CopilotProvider: UsageProvider<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAiE/C,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,IAAI,CAgF/C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AA8D/C,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,IAAI,CAuD/C,CAAA"}
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * providers/copilot/index.ts
3
3
  * Main entry point for the GitHub Copilot usage provider.
4
- * Orchestrates token exchange and fetching from public and internal APIs.
4
+ * Orchestrates token exchange and fetching from the internal API.
5
5
  */
6
- import { COPILOT_PLAN_LIMITS } from "./types.js";
7
- import { readCopilotAuth, readQuotaConfig } from "./auth.js";
8
- import { toCopilotQuotaFromBilling, toCopilotQuotaFromInternal, } from "./response.js";
6
+ import { readCopilotAuth } from "./auth.js";
7
+ import { toCopilotQuotaFromInternal, } from "./response.js";
9
8
  const GITHUB_API_BASE_URL = "https://api.github.com";
10
9
  const COPILOT_INTERNAL_USER_URL = `${GITHUB_API_BASE_URL}/copilot_internal/user`;
11
10
  const COPILOT_TOKEN_EXCHANGE_URL = `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`;
@@ -57,57 +56,35 @@ export const CopilotProvider = {
57
56
  async fetchUsage() {
58
57
  const now = Date.now();
59
58
  let quota = null;
60
- const config = readQuotaConfig();
61
- if (config) {
59
+ const auth = await readCopilotAuth();
60
+ const oauthToken = auth?.refresh || auth?.access;
61
+ if (oauthToken) {
62
62
  try {
63
- const resp = await fetchWithTimeout(`${GITHUB_API_BASE_URL}/users/${config.username}/settings/billing/premium_request/usage`, {
63
+ let resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
64
64
  headers: {
65
- Accept: "application/vnd.github+json",
66
- Authorization: `Bearer ${config.token}`,
67
- "X-GitHub-Api-Version": "2022-11-28",
65
+ Accept: "application/json",
66
+ Authorization: `token ${oauthToken}`,
67
+ ...COPILOT_HEADERS,
68
68
  },
69
69
  });
70
+ if (!resp.ok) {
71
+ const copilotToken = await exchangeForCopilotToken(oauthToken);
72
+ if (copilotToken) {
73
+ resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
74
+ headers: {
75
+ Accept: "application/json",
76
+ Authorization: `Bearer ${copilotToken}`,
77
+ ...COPILOT_HEADERS,
78
+ },
79
+ });
80
+ }
81
+ }
70
82
  if (resp.ok) {
71
83
  const data = (await resp.json());
72
- quota = toCopilotQuotaFromBilling(data, COPILOT_PLAN_LIMITS[config.tier]);
84
+ quota = toCopilotQuotaFromInternal(data);
73
85
  }
74
86
  }
75
87
  catch {
76
- // Fallback to internal API
77
- }
78
- }
79
- if (!quota) {
80
- const auth = await readCopilotAuth();
81
- const oauthToken = auth?.refresh || auth?.access;
82
- if (oauthToken) {
83
- try {
84
- let resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
85
- headers: {
86
- Accept: "application/json",
87
- Authorization: `token ${oauthToken}`,
88
- ...COPILOT_HEADERS,
89
- },
90
- });
91
- if (!resp.ok) {
92
- const copilotToken = await exchangeForCopilotToken(oauthToken);
93
- if (copilotToken) {
94
- resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
95
- headers: {
96
- Accept: "application/json",
97
- Authorization: `Bearer ${copilotToken}`,
98
- ...COPILOT_HEADERS,
99
- },
100
- });
101
- }
102
- }
103
- if (resp.ok) {
104
- const data = (await resp.json());
105
- quota = toCopilotQuotaFromInternal(data);
106
- }
107
- }
108
- catch {
109
- // Ignore
110
- }
111
88
  }
112
89
  }
113
90
  if (!quota)
@@ -1 +1 @@
1
- {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/response.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,WAAW,2BAA2B;IAC1C,mBAAmB,CAAC,EAAE;QACpB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE;QAChB,oBAAoB,CAAC,EAAE;YACrB,WAAW,EAAE,MAAM,CAAA;YACnB,iBAAiB,EAAE,MAAM,CAAA;YACzB,SAAS,EAAE,MAAM,CAAA;YACjB,SAAS,EAAE,OAAO,CAAA;SACnB,CAAA;KACF,CAAA;IACD,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,gBAAgB,EAAE,CAAA;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,2BAA2B,GAAG,YAAY,GAAG,IAAI,CA8BjG;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,MAAM,GACZ,YAAY,CAed"}
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/response.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,WAAW,2BAA2B;IAC1C,mBAAmB,CAAC,EAAE;QACpB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAA;IACD,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE;QAChB,oBAAoB,CAAC,EAAE;YACrB,WAAW,EAAE,MAAM,CAAA;YACnB,iBAAiB,EAAE,MAAM,CAAA;YACzB,SAAS,EAAE,MAAM,CAAA;YACjB,SAAS,EAAE,OAAO,CAAA;SACnB,CAAA;KACF,CAAA;IACD,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,gBAAgB,EAAE,CAAA;CAC/B;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,2BAA2B,GAAG,YAAY,GAAG,IAAI,CA4CjG;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,MAAM,GACZ,YAAY,CAed"}
@@ -4,27 +4,36 @@
4
4
  * Handles both public billing and internal user API shapes.
5
5
  */
6
6
  export function toCopilotQuotaFromInternal(data) {
7
- // Handle "limited" user format (Free/Pro limited)
8
7
  if (data.limited_user_quotas) {
9
- const chatRemaining = data.limited_user_quotas.chat ?? 0;
10
- const chatTotal = data.monthly_quotas?.chat ?? 50;
11
- const completionsRemaining = data.limited_user_quotas.completions ?? 0;
12
- const completionsTotal = data.monthly_quotas?.completions ?? 2000;
8
+ const chatRemainingRaw = data.limited_user_quotas.chat ?? 0;
9
+ const chatTotalRaw = data.monthly_quotas?.chat ?? 0;
10
+ const chatScale = chatTotalRaw === 500 ? 10 : 1;
11
+ const chatRemaining = Math.floor(chatRemainingRaw / chatScale);
12
+ const chatTotal = Math.floor(chatTotalRaw / chatScale);
13
+ const completionsRemainingRaw = data.limited_user_quotas.completions ?? 0;
14
+ const completionsTotalRaw = data.monthly_quotas?.completions ?? 2000;
15
+ const compScale = completionsTotalRaw === 4000 ? 2 : 1;
16
+ const completionsRemaining = Math.floor(completionsRemainingRaw / compScale);
17
+ const completionsTotal = Math.floor(completionsTotalRaw / compScale);
13
18
  return {
14
- used: Math.max(0, chatTotal - chatRemaining),
19
+ used: chatRemaining,
15
20
  total: chatTotal,
16
21
  percentRemaining: chatTotal > 0 ? Math.round((chatRemaining / chatTotal) * 100) : 0,
17
22
  resetTime: data.limited_user_reset_date || data.quota_reset_date,
18
- completionsUsed: Math.max(0, completionsTotal - completionsRemaining),
23
+ completionsUsed: completionsRemaining,
19
24
  completionsTotal: completionsTotal,
20
25
  };
21
26
  }
22
- // Handle standard format
23
27
  if (data.quota_snapshots?.premium_interactions) {
24
28
  const premium = data.quota_snapshots.premium_interactions;
29
+ const totalRaw = premium.unlimited ? -1 : premium.entitlement;
30
+ const remainingRaw = premium.remaining;
31
+ const scaleFactor = totalRaw === 500 ? 10 : 1;
32
+ const chatRemaining = totalRaw === -1 ? -1 : Math.floor(remainingRaw / scaleFactor);
33
+ const chatTotal = totalRaw === -1 ? -1 : Math.floor(totalRaw / scaleFactor);
25
34
  return {
26
- used: premium.unlimited ? 0 : premium.entitlement - premium.remaining,
27
- total: premium.unlimited ? -1 : premium.entitlement,
35
+ used: chatRemaining,
36
+ total: chatTotal,
28
37
  percentRemaining: Math.round(premium.percent_remaining),
29
38
  resetTime: data.quota_reset_date,
30
39
  };
@@ -4,11 +4,6 @@
4
4
  * Includes auth data shapes and plan limit configurations.
5
5
  */
6
6
  export type CopilotTier = "free" | "pro" | "pro+" | "business" | "enterprise";
7
- export interface CopilotQuotaConfig {
8
- token: string;
9
- username: string;
10
- tier: CopilotTier;
11
- }
12
7
  export interface CopilotAuthData {
13
8
  type: string;
14
9
  refresh?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAA;AAE7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,WAAW,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAM3D,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAA;AAE7E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAM3D,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAA;AAwHxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAoC7D"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAA;AAoHxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAoC7D"}
@@ -12,7 +12,6 @@ const GROUP_MAPPING = {
12
12
  "25-flash": "25-flash",
13
13
  "25-lite": "25-lite"
14
14
  };
15
- // Display name ordering priority
16
15
  const GROUP_ORDER = ["claude", "g3-pro", "g3-flash", "25-flash", "25-lite"];
17
16
  function sortGroupNames(groups) {
18
17
  return Array.from(groups.keys()).sort((a, b) => {
@@ -72,10 +71,8 @@ function aggregateCredentialsByTier(credentials) {
72
71
  if (!(name in GROUP_MAPPING))
73
72
  continue;
74
73
  const mappedName = GROUP_MAPPING[name];
75
- // Find the best window from group_usage
76
74
  const windows = groupData.windows || {};
77
75
  let bestWindow = null;
78
- // Priority order for windows
79
76
  const windowPriority = ["daily", "5h", "1h", "15m"];
80
77
  for (const windowName of windowPriority) {
81
78
  if (windows[windowName]) {
@@ -83,7 +80,6 @@ function aggregateCredentialsByTier(credentials) {
83
80
  break;
84
81
  }
85
82
  }
86
- // Fallback to any available window
87
83
  if (!bestWindow && Object.keys(windows).length > 0) {
88
84
  bestWindow = Object.values(windows)[0];
89
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAM5C,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAiK5C,eAAO,MAAM,aAAa,EAAE,aAwB3B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAM5C,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAyI5C,eAAO,MAAM,aAAa,EAAE,aAwB3B,CAAA"}
@@ -17,34 +17,28 @@ const GROUP_MAPPING = {
17
17
  "25-flash": "25-flash",
18
18
  "25-lite": "25-lite"
19
19
  };
20
- // Display name ordering priority
21
20
  const GROUP_ORDER = ["claude", "g3-pro", "g3-flash", "25-flash", "25-lite"];
22
21
  function sortQuotaGroups(groups) {
23
22
  return groups.sort((a, b) => {
24
23
  const aIndex = GROUP_ORDER.indexOf(a.name);
25
24
  const bIndex = GROUP_ORDER.indexOf(b.name);
26
- // Both in priority list: sort by index
27
25
  if (aIndex !== -1 && bIndex !== -1)
28
26
  return aIndex - bIndex;
29
- // Only a in priority list: a comes first
30
27
  if (aIndex !== -1)
31
28
  return -1;
32
- // Only b in priority list: b comes first
33
29
  if (bIndex !== -1)
34
30
  return 1;
35
- // Neither in priority list: alphabetical
36
31
  return a.name.localeCompare(b.name);
37
32
  });
38
33
  }
39
34
  function normalizeTier(tier) {
40
35
  if (!tier)
41
36
  return "free";
42
- return tier.includes("free") ? "free" : "paid";
37
+ const t = tier.toLowerCase();
38
+ if (t === "paid" || t === "pro" || t === "premium" || t === "individual" || t.includes("paid"))
39
+ return "paid";
40
+ return "free";
43
41
  }
44
- /**
45
- * Extract quota groups from group_usage data
46
- * New API structure: group_usage[groupName].windows[windowName]
47
- */
48
42
  function parseQuotaGroupsFromCredential(groupUsage) {
49
43
  if (!groupUsage)
50
44
  return [];
@@ -53,10 +47,8 @@ function parseQuotaGroupsFromCredential(groupUsage) {
53
47
  const mappedName = GROUP_MAPPING[groupName];
54
48
  if (!mappedName)
55
49
  continue;
56
- // Find the window with the best data (prefer daily, then 5h, then any)
57
50
  const windows = groupData.windows || {};
58
51
  let bestWindow = null;
59
- // Priority order for windows
60
52
  const windowPriority = ["daily", "5h", "1h", "15m"];
61
53
  for (const windowName of windowPriority) {
62
54
  if (windows[windowName]) {
@@ -64,55 +56,42 @@ function parseQuotaGroupsFromCredential(groupUsage) {
64
56
  break;
65
57
  }
66
58
  }
67
- // Fallback to any available window
68
59
  if (!bestWindow && Object.keys(windows).length > 0) {
69
60
  bestWindow = Object.values(windows)[0];
70
61
  }
71
62
  if (!bestWindow)
72
63
  continue;
73
- const existing = result.get(mappedName);
74
- if (existing) {
75
- existing.remaining += bestWindow.remaining;
76
- existing.max += bestWindow.limit || 0;
77
- // Use the latest reset time
78
- if (bestWindow.reset_at) {
79
- const newResetTime = new Date(bestWindow.reset_at * 1000).toISOString();
80
- if (!existing.resetTime || new Date(newResetTime) > new Date(existing.resetTime)) {
81
- existing.resetTime = newResetTime;
82
- }
83
- }
84
- }
85
- else {
86
- result.set(mappedName, {
87
- name: mappedName,
88
- remaining: bestWindow.remaining,
89
- max: bestWindow.limit || bestWindow.remaining,
90
- remainingPct: bestWindow.limit ? Math.round((bestWindow.remaining / bestWindow.limit) * 100) : 0,
91
- resetTime: bestWindow.reset_at ? new Date(bestWindow.reset_at * 1000).toISOString() : null,
92
- });
93
- }
64
+ result.set(mappedName, {
65
+ name: mappedName,
66
+ remaining: bestWindow.remaining,
67
+ max: bestWindow.limit || bestWindow.remaining,
68
+ remainingPct: bestWindow.limit ? Math.round((bestWindow.remaining / bestWindow.limit) * 100) : 0,
69
+ resetTime: bestWindow.reset_at ? new Date(bestWindow.reset_at * 1000).toISOString() : null,
70
+ });
94
71
  }
95
72
  return Array.from(result.values());
96
73
  }
97
- function aggregateByTier(credentials) {
74
+ function aggregateByProvider(provider) {
98
75
  const tiers = {
99
76
  paid: new Map(),
100
77
  free: new Map(),
101
78
  };
102
- for (const cred of credentials) {
103
- const tier = normalizeTier(cred.tier);
104
- const groups = parseQuotaGroupsFromCredential(cred.group_usage);
105
- for (const group of groups) {
106
- const existing = tiers[tier].get(group.name);
107
- if (existing) {
108
- existing.remaining += group.remaining;
109
- existing.max += group.max;
110
- if (group.resetTime && (!existing.resetTime || new Date(group.resetTime) > new Date(existing.resetTime))) {
111
- existing.resetTime = group.resetTime;
79
+ if (provider.credentials) {
80
+ for (const cred of Object.values(provider.credentials)) {
81
+ const tier = normalizeTier(cred.tier);
82
+ const groups = parseQuotaGroupsFromCredential(cred.group_usage);
83
+ for (const group of groups) {
84
+ const existing = tiers[tier].get(group.name);
85
+ if (existing) {
86
+ existing.remaining += group.remaining;
87
+ existing.max += group.max;
88
+ if (group.resetTime && (!existing.resetTime || new Date(group.resetTime) > new Date(existing.resetTime))) {
89
+ existing.resetTime = group.resetTime;
90
+ }
91
+ }
92
+ else {
93
+ tiers[tier].set(group.name, { ...group });
112
94
  }
113
- }
114
- else {
115
- tiers[tier].set(group.name, { ...group });
116
95
  }
117
96
  }
118
97
  }
@@ -134,11 +113,9 @@ function parseProviders(data) {
134
113
  if (!data.providers)
135
114
  return [];
136
115
  return Object.entries(data.providers).map(([name, provider]) => {
137
- // Convert credentials object to array
138
- const credentialsArray = Object.values(provider.credentials || {});
139
116
  return {
140
117
  name,
141
- tiers: aggregateByTier(credentialsArray),
118
+ tiers: aggregateByProvider(provider),
142
119
  };
143
120
  });
144
121
  }
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * Type definitions for the Antigravity proxy provider.
3
3
  */
4
- /** Configuration stored in ~/.config/opencode/usage-config.jsonc */
5
- /** Token statistics from the proxy */
6
4
  export type TokenStats = {
7
5
  input_cached?: number;
8
6
  input_uncached?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS,0IAcZ,CAAA;AAEV,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAA;AAEjD,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAA;IACnB,SAAS,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,WAAW,EAAE,eAAe,EAAE,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,aAAa,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAC9B,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,KAAK,CAAC,EAAE,OAAO,CAAA;QACf,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;IAC/B,SAAS,EAAE,eAAe,GAAG,IAAI,CAAA;IACjC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAA;IAClC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;IAC/B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAExC,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChB;AAwID,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,aAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAExC,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAqChB;AAyID,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,aAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
package/dist/ui/status.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * Renders usage snapshots into readable status text.
3
3
  */
4
4
  export async function sendStatusMessage(options) {
5
- // 1. Send to Companion via Bus
6
5
  // @ts-ignore
7
6
  const bus = options.client.bus;
8
7
  if (bus) {
@@ -18,7 +17,6 @@ export async function sendStatusMessage(options) {
18
17
  }
19
18
  catch { }
20
19
  }
21
- // 2. Send plain message to TUI
22
20
  await options.client.session
23
21
  .prompt({
24
22
  path: { id: options.sessionID },
@@ -34,7 +32,6 @@ export async function sendStatusMessage(options) {
34
32
  },
35
33
  })
36
34
  .catch(async () => {
37
- // 3. Fallback: Toast
38
35
  await options.client.tui
39
36
  .showToast({
40
37
  body: { title: "Usage Status", message: options.text, variant: "info" },
@@ -111,11 +108,13 @@ function formatCopilotSnapshot(snapshot) {
111
108
  const resetSuffix = copilot.resetTime ? formatResetSuffixISO(copilot.resetTime) : "";
112
109
  const totalLabel = copilot.total === -1 ? "∞" : copilot.total.toString();
113
110
  const chatLabel = "Chat:".padEnd(13);
114
- lines.push(` ${chatLabel} ${formatBar(copilot.percentRemaining)} ${copilot.used}/${totalLabel}${resetSuffix}`);
111
+ const chatRemaining = copilot.used;
112
+ const chatPct = copilot.percentRemaining;
113
+ lines.push(` ${chatLabel} ${formatBar(chatPct)} ${chatRemaining}/${totalLabel}${resetSuffix}`);
115
114
  if (copilot.completionsUsed !== undefined && copilot.completionsTotal !== undefined) {
116
115
  const compLabel = "Completions:".padEnd(13);
117
116
  const compPct = copilot.completionsTotal > 0
118
- ? Math.round(((copilot.completionsTotal - copilot.completionsUsed) / copilot.completionsTotal) * 100)
117
+ ? Math.round((copilot.completionsUsed / copilot.completionsTotal) * 100)
119
118
  : 0;
120
119
  lines.push(` ${compLabel} ${formatBar(compPct)} ${copilot.completionsUsed}/${copilot.completionsTotal}`);
121
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/usage/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAI3C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAsD5D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/usage/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAI3C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CA6C5D"}
@@ -11,16 +11,9 @@ export async function loadUsageConfig() {
11
11
  * Usage Plugin Configuration
12
12
  */
13
13
  {
14
- // Proxy endpoint (e.g. http://localhost:8000)
15
14
  "endpoint": "",
16
-
17
- // API key for authentication
18
15
  "apiKey": "",
19
-
20
- // Request timeout in milliseconds
21
16
  "timeout": 10000,
22
-
23
- // Provider visibility
24
17
  "providers": {
25
18
  "openai": true,
26
19
  "proxy": true,
@@ -42,9 +35,7 @@ export async function loadUsageConfig() {
42
35
  }
43
36
  try {
44
37
  const content = await file.text();
45
- // Remove comments first (both // and /* */)
46
38
  const withoutComments = content.replace(/(\".*?\"|\'.*?\')|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g1) => g1 ?? "");
47
- // Remove trailing commas before closing brackets/braces
48
39
  const cleanJson = withoutComments.replace(/,(\s*[}\]])/g, "$1");
49
40
  const config = JSON.parse(cleanJson);
50
41
  return config;
@@ -1 +1 @@
1
- {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/usage/fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAI7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAe5C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWlD,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzE;AAED,wBAAsB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA6CnF;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CASrD"}
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/usage/fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAI7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAe5C,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWlD,CAAA;AAED,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIzE;AAED,wBAAsB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA2CnF;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CASrD"}
@@ -51,7 +51,6 @@ export async function fetchUsageSnapshots(filter) {
51
51
  const auths = await loadAuths();
52
52
  const entries = resolveProviderAuths(auths, null);
53
53
  const snapshots = [];
54
- // Fetch from auth-based providers
55
54
  const fetches = entries
56
55
  .filter((entry) => !targetProvider || entry.providerID === targetProvider)
57
56
  .filter((entry) => isProviderEnabled(entry.providerID))
@@ -63,7 +62,6 @@ export async function fetchUsageSnapshots(filter) {
63
62
  if (snapshot)
64
63
  snapshots.push(snapshot);
65
64
  });
66
- // Always include special providers (no auth entries needed) if no filter or filter matches
67
65
  const specialProviders = ["proxy", "copilot"];
68
66
  for (const id of specialProviders) {
69
67
  if ((!targetProvider || targetProvider === id) && isProviderEnabled(id)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/opencode-usage-plugin",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "opencode plugin for tracking AI provider usage, rate limits, and quotas",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",