@howaboua/opencode-usage-plugin 0.1.1 → 0.1.3
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/dist/hooks/command.js +1 -1
- package/dist/providers/copilot/auth.d.ts +1 -5
- package/dist/providers/copilot/auth.d.ts.map +1 -1
- package/dist/providers/copilot/auth.js +2 -38
- package/dist/providers/copilot/index.d.ts +0 -1
- package/dist/providers/copilot/index.d.ts.map +1 -1
- package/dist/providers/copilot/index.js +22 -46
- package/dist/providers/copilot/response.d.ts.map +1 -1
- package/dist/providers/copilot/response.js +20 -11
- package/dist/providers/copilot/types.d.ts +0 -5
- package/dist/providers/copilot/types.d.ts.map +1 -1
- package/dist/providers/proxy/format.d.ts.map +1 -1
- package/dist/providers/proxy/format.js +0 -4
- package/dist/providers/proxy/index.d.ts +1 -1
- package/dist/providers/proxy/index.d.ts.map +1 -1
- package/dist/providers/proxy/index.js +29 -52
- package/dist/providers/proxy/types.d.ts +0 -2
- package/dist/providers/proxy/types.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/status.d.ts.map +1 -1
- package/dist/ui/status.js +40 -5
- package/dist/usage/config.d.ts.map +1 -1
- package/dist/usage/config.js +13 -15
- package/dist/usage/fetch.d.ts.map +1 -1
- package/dist/usage/fetch.js +79 -16
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/paths.d.ts +8 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +43 -1
- package/package.json +1 -1
package/dist/hooks/command.js
CHANGED
|
@@ -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;
|
|
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,7 @@
|
|
|
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.
|
|
5
4
|
*/
|
|
6
|
-
import { type CopilotAuthData
|
|
7
|
-
export declare function getQuotaConfigPath(): string;
|
|
8
|
-
export declare function getUsageTokenPath(): string;
|
|
5
|
+
import { type CopilotAuthData } from "./types.js";
|
|
9
6
|
export declare function readCopilotAuth(): Promise<CopilotAuthData | null>;
|
|
10
|
-
export declare function readQuotaConfig(): CopilotQuotaConfig | null;
|
|
11
7
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAevE"}
|
|
@@ -1,33 +1,12 @@
|
|
|
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.
|
|
5
4
|
*/
|
|
6
|
-
import { existsSync
|
|
5
|
+
import { existsSync } from "fs";
|
|
7
6
|
import { readFile } from "fs/promises";
|
|
8
|
-
import {
|
|
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
|
-
}
|
|
7
|
+
import { getAuthFilePath } from "../../utils/paths.js";
|
|
17
8
|
export async function readCopilotAuth() {
|
|
18
9
|
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
10
|
const authPath = getAuthFilePath();
|
|
32
11
|
if (existsSync(authPath)) {
|
|
33
12
|
const content = await readFile(authPath, "utf-8");
|
|
@@ -43,18 +22,3 @@ export async function readCopilotAuth() {
|
|
|
43
22
|
return null;
|
|
44
23
|
}
|
|
45
24
|
}
|
|
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,6 @@
|
|
|
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.
|
|
5
4
|
*/
|
|
6
5
|
import type { UsageProvider } from "../base.js";
|
|
7
6
|
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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/copilot/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AA8D/C,eAAO,MAAM,eAAe,EAAE,aAAa,CAAC,IAAI,CAuD/C,CAAA"}
|
|
@@ -1,11 +1,9 @@
|
|
|
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.
|
|
5
4
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { toCopilotQuotaFromBilling, toCopilotQuotaFromInternal, } from "./response.js";
|
|
5
|
+
import { readCopilotAuth } from "./auth.js";
|
|
6
|
+
import { toCopilotQuotaFromInternal, } from "./response.js";
|
|
9
7
|
const GITHUB_API_BASE_URL = "https://api.github.com";
|
|
10
8
|
const COPILOT_INTERNAL_USER_URL = `${GITHUB_API_BASE_URL}/copilot_internal/user`;
|
|
11
9
|
const COPILOT_TOKEN_EXCHANGE_URL = `${GITHUB_API_BASE_URL}/copilot_internal/v2/token`;
|
|
@@ -57,57 +55,35 @@ export const CopilotProvider = {
|
|
|
57
55
|
async fetchUsage() {
|
|
58
56
|
const now = Date.now();
|
|
59
57
|
let quota = null;
|
|
60
|
-
const
|
|
61
|
-
|
|
58
|
+
const auth = await readCopilotAuth();
|
|
59
|
+
const oauthToken = auth?.refresh || auth?.access;
|
|
60
|
+
if (oauthToken) {
|
|
62
61
|
try {
|
|
63
|
-
|
|
62
|
+
let resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
|
|
64
63
|
headers: {
|
|
65
|
-
Accept: "application/
|
|
66
|
-
Authorization: `
|
|
67
|
-
|
|
64
|
+
Accept: "application/json",
|
|
65
|
+
Authorization: `token ${oauthToken}`,
|
|
66
|
+
...COPILOT_HEADERS,
|
|
68
67
|
},
|
|
69
68
|
});
|
|
69
|
+
if (!resp.ok) {
|
|
70
|
+
const copilotToken = await exchangeForCopilotToken(oauthToken);
|
|
71
|
+
if (copilotToken) {
|
|
72
|
+
resp = await fetchWithTimeout(COPILOT_INTERNAL_USER_URL, {
|
|
73
|
+
headers: {
|
|
74
|
+
Accept: "application/json",
|
|
75
|
+
Authorization: `Bearer ${copilotToken}`,
|
|
76
|
+
...COPILOT_HEADERS,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
70
81
|
if (resp.ok) {
|
|
71
82
|
const data = (await resp.json());
|
|
72
|
-
quota =
|
|
83
|
+
quota = toCopilotQuotaFromInternal(data);
|
|
73
84
|
}
|
|
74
85
|
}
|
|
75
86
|
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
87
|
}
|
|
112
88
|
}
|
|
113
89
|
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,
|
|
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
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
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:
|
|
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:
|
|
19
|
-
completionsTotal
|
|
23
|
+
completionsUsed: completionsRemaining,
|
|
24
|
+
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:
|
|
27
|
-
total:
|
|
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,
|
|
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;
|
|
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
|
}
|
|
@@ -6,5 +6,5 @@ import type { UsageProvider } from "../base";
|
|
|
6
6
|
export type { ProxyResponse } from "./types";
|
|
7
7
|
export { fetchProxyLimits } from "./fetch";
|
|
8
8
|
export { formatProxyLimits } from "./format";
|
|
9
|
-
export declare const ProxyProvider: UsageProvider
|
|
9
|
+
export declare const ProxyProvider: UsageProvider<void>;
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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;
|
|
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,aAAa,CAAC,IAAI,CAwB7C,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
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
|
74
|
+
function aggregateByProvider(provider) {
|
|
98
75
|
const tiers = {
|
|
99
76
|
paid: new Map(),
|
|
100
77
|
free: new Map(),
|
|
101
78
|
};
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
existing
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
existing.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:
|
|
118
|
+
tiers: aggregateByProvider(provider),
|
|
142
119
|
};
|
|
143
120
|
});
|
|
144
121
|
}
|
|
@@ -159,7 +136,7 @@ export const ProxyProvider = {
|
|
|
159
136
|
const config = await loadUsageConfig();
|
|
160
137
|
const data = await fetchProxyLimits(config);
|
|
161
138
|
return {
|
|
162
|
-
timestamp: data.timestamp * 1000,
|
|
139
|
+
timestamp: (data.timestamp || Date.now() / 1000) * 1000,
|
|
163
140
|
provider: "proxy",
|
|
164
141
|
planType: null,
|
|
165
142
|
primary: null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/ui/status.d.ts.map
CHANGED
|
@@ -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;
|
|
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;AAGtD,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;AA4KD,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
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Renders usage snapshots into readable status text.
|
|
3
3
|
*/
|
|
4
|
+
import { platform, homedir } from "os";
|
|
5
|
+
import { join } from "path";
|
|
4
6
|
export async function sendStatusMessage(options) {
|
|
5
|
-
// 1. Send to Companion via Bus
|
|
6
7
|
// @ts-ignore
|
|
7
8
|
const bus = options.client.bus;
|
|
8
9
|
if (bus) {
|
|
@@ -18,7 +19,6 @@ export async function sendStatusMessage(options) {
|
|
|
18
19
|
}
|
|
19
20
|
catch { }
|
|
20
21
|
}
|
|
21
|
-
// 2. Send plain message to TUI
|
|
22
22
|
await options.client.session
|
|
23
23
|
.prompt({
|
|
24
24
|
path: { id: options.sessionID },
|
|
@@ -34,7 +34,6 @@ export async function sendStatusMessage(options) {
|
|
|
34
34
|
},
|
|
35
35
|
})
|
|
36
36
|
.catch(async () => {
|
|
37
|
-
// 3. Fallback: Toast
|
|
38
37
|
await options.client.tui
|
|
39
38
|
.showToast({
|
|
40
39
|
body: { title: "Usage Status", message: options.text, variant: "info" },
|
|
@@ -111,17 +110,53 @@ function formatCopilotSnapshot(snapshot) {
|
|
|
111
110
|
const resetSuffix = copilot.resetTime ? formatResetSuffixISO(copilot.resetTime) : "";
|
|
112
111
|
const totalLabel = copilot.total === -1 ? "∞" : copilot.total.toString();
|
|
113
112
|
const chatLabel = "Chat:".padEnd(13);
|
|
114
|
-
|
|
113
|
+
const chatRemaining = copilot.used;
|
|
114
|
+
const chatPct = copilot.percentRemaining;
|
|
115
|
+
lines.push(` ${chatLabel} ${formatBar(chatPct)} ${chatRemaining}/${totalLabel}${resetSuffix}`);
|
|
115
116
|
if (copilot.completionsUsed !== undefined && copilot.completionsTotal !== undefined) {
|
|
116
117
|
const compLabel = "Completions:".padEnd(13);
|
|
117
118
|
const compPct = copilot.completionsTotal > 0
|
|
118
|
-
? Math.round((
|
|
119
|
+
? Math.round((copilot.completionsUsed / copilot.completionsTotal) * 100)
|
|
119
120
|
: 0;
|
|
120
121
|
lines.push(` ${compLabel} ${formatBar(compPct)} ${copilot.completionsUsed}/${copilot.completionsTotal}`);
|
|
121
122
|
}
|
|
122
123
|
return lines;
|
|
123
124
|
}
|
|
125
|
+
function getAppDataPath() {
|
|
126
|
+
const home = homedir();
|
|
127
|
+
const plat = platform();
|
|
128
|
+
if (plat === "darwin")
|
|
129
|
+
return join(home, ".config", "opencode");
|
|
130
|
+
if (plat === "win32")
|
|
131
|
+
return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode");
|
|
132
|
+
return join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "opencode");
|
|
133
|
+
}
|
|
134
|
+
function formatMissingSnapshot(snapshot) {
|
|
135
|
+
const provider = snapshot.provider;
|
|
136
|
+
const label = provider === "codex" ? "codex" : provider === "proxy" ? "proxy" : "gh";
|
|
137
|
+
const configPath = join(getAppDataPath(), "usage-config.jsonc");
|
|
138
|
+
let providerInstruction = "";
|
|
139
|
+
if (provider === "codex") {
|
|
140
|
+
providerInstruction = "if you dont have codex oauth, please set your usage-config.jsonc to openai: false";
|
|
141
|
+
}
|
|
142
|
+
else if (provider === "proxy") {
|
|
143
|
+
providerInstruction = "if you are not running Mirrowel's proxy, please set your usage-config.jsonc to proxy: false";
|
|
144
|
+
}
|
|
145
|
+
else if (provider === "copilot") {
|
|
146
|
+
providerInstruction = "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false";
|
|
147
|
+
}
|
|
148
|
+
return [
|
|
149
|
+
`→ [${provider.toUpperCase()}] - ${providerInstruction}`,
|
|
150
|
+
"",
|
|
151
|
+
`The file can be found in ${configPath}. Please read the comments in the file or visit the repo for the readme.`,
|
|
152
|
+
"",
|
|
153
|
+
"If you are seeing empty usages or errors, despite having everything set up correctly, please fire an issue at https://github.com/IgorWarzocha/opencode-usage-plugin/issues - thank you!",
|
|
154
|
+
];
|
|
155
|
+
}
|
|
124
156
|
function formatSnapshot(snapshot) {
|
|
157
|
+
if (snapshot.isMissing) {
|
|
158
|
+
return formatMissingSnapshot(snapshot);
|
|
159
|
+
}
|
|
125
160
|
if (snapshot.provider === "proxy" && snapshot.proxyQuota) {
|
|
126
161
|
return formatProxySnapshot(snapshot);
|
|
127
162
|
}
|
|
@@ -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;
|
|
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;AAiB3C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CA0C5D"}
|
package/dist/usage/config.js
CHANGED
|
@@ -2,25 +2,25 @@
|
|
|
2
2
|
* Configuration management for the Usage Plugin.
|
|
3
3
|
*/
|
|
4
4
|
import { join } from "path";
|
|
5
|
-
import { homedir } from "os";
|
|
6
|
-
|
|
5
|
+
import { homedir, platform } from "os";
|
|
6
|
+
function getConfigPath() {
|
|
7
|
+
const plat = platform();
|
|
8
|
+
const home = homedir();
|
|
9
|
+
if (plat === "win32") {
|
|
10
|
+
return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode", "usage-config.jsonc");
|
|
11
|
+
}
|
|
12
|
+
// For macOS, Linux, and other Unix-like systems, use XDG_CONFIG_HOME or default to ~/.config
|
|
13
|
+
const configHome = process.env.XDG_CONFIG_HOME || join(home, ".config");
|
|
14
|
+
return join(configHome, "opencode", "usage-config.jsonc");
|
|
15
|
+
}
|
|
16
|
+
const CONFIG_PATH = getConfigPath();
|
|
7
17
|
export async function loadUsageConfig() {
|
|
8
18
|
const file = Bun.file(CONFIG_PATH);
|
|
9
19
|
if (!(await file.exists())) {
|
|
10
|
-
const content =
|
|
11
|
-
* Usage Plugin Configuration
|
|
12
|
-
*/
|
|
13
|
-
{
|
|
14
|
-
// Proxy endpoint (e.g. http://localhost:8000)
|
|
20
|
+
const content = `{
|
|
15
21
|
"endpoint": "",
|
|
16
|
-
|
|
17
|
-
// API key for authentication
|
|
18
22
|
"apiKey": "",
|
|
19
|
-
|
|
20
|
-
// Request timeout in milliseconds
|
|
21
23
|
"timeout": 10000,
|
|
22
|
-
|
|
23
|
-
// Provider visibility
|
|
24
24
|
"providers": {
|
|
25
25
|
"openai": true,
|
|
26
26
|
"proxy": true,
|
|
@@ -42,9 +42,7 @@ export async function loadUsageConfig() {
|
|
|
42
42
|
}
|
|
43
43
|
try {
|
|
44
44
|
const content = await file.text();
|
|
45
|
-
// Remove comments first (both // and /* */)
|
|
46
45
|
const withoutComments = content.replace(/(\".*?\"|\'.*?\')|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g1) => g1 ?? "");
|
|
47
|
-
// Remove trailing commas before closing brackets/braces
|
|
48
46
|
const cleanJson = withoutComments.replace(/,(\s*[}\]])/g, "$1");
|
|
49
47
|
const config = JSON.parse(cleanJson);
|
|
50
48
|
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,
|
|
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,CA4EnF;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CA8BrD"}
|
package/dist/usage/fetch.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import z from "zod";
|
|
6
6
|
import { providers } from "../providers";
|
|
7
7
|
import { loadUsageConfig } from "./config";
|
|
8
|
-
import {
|
|
8
|
+
import { getPossibleAuthPaths } from "../utils";
|
|
9
9
|
import { resolveProviderAuths } from "./registry";
|
|
10
10
|
const authEntrySchema = z
|
|
11
11
|
.object({
|
|
@@ -51,7 +51,8 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
51
51
|
const auths = await loadAuths();
|
|
52
52
|
const entries = resolveProviderAuths(auths, null);
|
|
53
53
|
const snapshots = [];
|
|
54
|
-
|
|
54
|
+
const coreProviders = ["codex", "proxy", "copilot"];
|
|
55
|
+
const fetchedProviders = new Set();
|
|
55
56
|
const fetches = entries
|
|
56
57
|
.filter((entry) => !targetProvider || entry.providerID === targetProvider)
|
|
57
58
|
.filter((entry) => isProviderEnabled(entry.providerID))
|
|
@@ -59,11 +60,16 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
59
60
|
const provider = providers[entry.providerID];
|
|
60
61
|
if (!provider?.fetchUsage)
|
|
61
62
|
return;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
try {
|
|
64
|
+
const snapshot = await provider.fetchUsage(entry.auth);
|
|
65
|
+
if (snapshot) {
|
|
66
|
+
snapshots.push(snapshot);
|
|
67
|
+
fetchedProviders.add(entry.providerID);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
}
|
|
65
72
|
});
|
|
66
|
-
// Always include special providers (no auth entries needed) if no filter or filter matches
|
|
67
73
|
const specialProviders = ["proxy", "copilot"];
|
|
68
74
|
for (const id of specialProviders) {
|
|
69
75
|
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id)) {
|
|
@@ -72,27 +78,84 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
72
78
|
fetches.push(provider
|
|
73
79
|
.fetchUsage(undefined)
|
|
74
80
|
.then((snapshot) => {
|
|
75
|
-
if (snapshot)
|
|
81
|
+
if (snapshot) {
|
|
76
82
|
snapshots.push(snapshot);
|
|
83
|
+
fetchedProviders.add(id);
|
|
84
|
+
}
|
|
77
85
|
})
|
|
78
86
|
.catch(() => { }));
|
|
79
87
|
}
|
|
80
88
|
}
|
|
81
89
|
}
|
|
82
90
|
await Promise.race([Promise.all(fetches), timeout(5000)]);
|
|
91
|
+
for (const id of coreProviders) {
|
|
92
|
+
if (isProviderEnabled(id) && !fetchedProviders.has(id)) {
|
|
93
|
+
if (!targetProvider || targetProvider === id) {
|
|
94
|
+
snapshots.push({
|
|
95
|
+
timestamp: Date.now(),
|
|
96
|
+
provider: id,
|
|
97
|
+
planType: null,
|
|
98
|
+
primary: null,
|
|
99
|
+
secondary: null,
|
|
100
|
+
codeReview: null,
|
|
101
|
+
credits: null,
|
|
102
|
+
updatedAt: Date.now(),
|
|
103
|
+
isMissing: true,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
83
108
|
return snapshots;
|
|
84
109
|
}
|
|
85
110
|
export async function loadAuths() {
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
const possiblePaths = getPossibleAuthPaths();
|
|
112
|
+
const mergedAuth = {};
|
|
113
|
+
for (const authPath of possiblePaths.reverse()) {
|
|
114
|
+
try {
|
|
115
|
+
const file = Bun.file(authPath);
|
|
116
|
+
if (!(await file.exists()))
|
|
117
|
+
continue;
|
|
118
|
+
const data = await file.json();
|
|
119
|
+
if (data && typeof data === "object") {
|
|
120
|
+
if (authPath.includes(".codex")) {
|
|
121
|
+
const codexAuth = transformCodexAuth(data);
|
|
122
|
+
if (codexAuth) {
|
|
123
|
+
Object.assign(mergedAuth, codexAuth);
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const parsed = authRecordSchema.safeParse(data);
|
|
128
|
+
if (parsed.success) {
|
|
129
|
+
Object.assign(mergedAuth, parsed.data);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return mergedAuth;
|
|
138
|
+
}
|
|
139
|
+
function transformCodexAuth(data) {
|
|
140
|
+
const codexAuthSchema = z.object({
|
|
141
|
+
tokens: z.object({
|
|
142
|
+
access_token: z.string(),
|
|
143
|
+
account_id: z.string().optional(),
|
|
144
|
+
refresh_token: z.string().optional(),
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
const parsed = codexAuthSchema.safeParse(data);
|
|
93
148
|
if (!parsed.success)
|
|
94
|
-
return
|
|
95
|
-
|
|
149
|
+
return null;
|
|
150
|
+
const { access_token, account_id, refresh_token } = parsed.data.tokens;
|
|
151
|
+
return {
|
|
152
|
+
openai: {
|
|
153
|
+
type: "oauth",
|
|
154
|
+
access: access_token,
|
|
155
|
+
accountId: account_id,
|
|
156
|
+
refresh: refresh_token,
|
|
157
|
+
},
|
|
158
|
+
};
|
|
96
159
|
}
|
|
97
160
|
function timeout(ms) {
|
|
98
161
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { parseBooleanHeader, parseIntegerHeader, parseNumberHeader } from "./headers";
|
|
2
|
-
export { getAppDataPath, getAuthFilePath } from "./paths";
|
|
2
|
+
export { getAppDataPath, getAuthFilePath, getPossibleAuthPaths } from "./paths";
|
package/dist/utils/paths.d.ts
CHANGED
|
@@ -3,5 +3,13 @@
|
|
|
3
3
|
* Centralizes platform-specific paths so callers stay simple and consistent.
|
|
4
4
|
*/
|
|
5
5
|
export declare function getAppDataPath(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Returns all possible auth file paths for the current platform.
|
|
8
|
+
* On macOS, OpenCode uses Linux-style paths, so we check both.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getPossibleAuthPaths(): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Returns the first existing auth file path, or the default location if none exist.
|
|
13
|
+
*/
|
|
6
14
|
export declare function getAuthFilePath(): string;
|
|
7
15
|
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,wBAAgB,cAAc,IAAI,MAAM,CAiBvC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAyB/C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAYxC"}
|
package/dist/utils/paths.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { homedir, platform } from "os";
|
|
6
6
|
import { join } from "path";
|
|
7
|
+
import { existsSync } from "fs";
|
|
7
8
|
export function getAppDataPath() {
|
|
8
9
|
const plat = platform();
|
|
9
10
|
const home = homedir();
|
|
@@ -19,6 +20,47 @@ export function getAppDataPath() {
|
|
|
19
20
|
}
|
|
20
21
|
return join(home, ".local", "share", "opencode");
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Returns all possible auth file paths for the current platform.
|
|
25
|
+
* On macOS, OpenCode uses Linux-style paths, so we check both.
|
|
26
|
+
*/
|
|
27
|
+
export function getPossibleAuthPaths() {
|
|
28
|
+
const plat = platform();
|
|
29
|
+
const home = homedir();
|
|
30
|
+
const pathSet = new Set();
|
|
31
|
+
if (plat === "darwin") {
|
|
32
|
+
// OpenCode on macOS uses Linux-style paths
|
|
33
|
+
pathSet.add(join(home, ".local", "share", "opencode", "auth.json"));
|
|
34
|
+
// Standard macOS location (fallback)
|
|
35
|
+
pathSet.add(join(home, "Library", "Application Support", "opencode", "auth.json"));
|
|
36
|
+
// Codex-specific auth (fallback)
|
|
37
|
+
pathSet.add(join(home, ".codex", "auth.json"));
|
|
38
|
+
}
|
|
39
|
+
else if (plat === "win32") {
|
|
40
|
+
pathSet.add(join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode", "auth.json"));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Linux/other
|
|
44
|
+
const xdgData = process.env.XDG_DATA_HOME;
|
|
45
|
+
if (xdgData) {
|
|
46
|
+
pathSet.add(join(xdgData, "opencode", "auth.json"));
|
|
47
|
+
}
|
|
48
|
+
pathSet.add(join(home, ".local", "share", "opencode", "auth.json"));
|
|
49
|
+
pathSet.add(join(home, ".codex", "auth.json"));
|
|
50
|
+
}
|
|
51
|
+
return Array.from(pathSet);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Returns the first existing auth file path, or the default location if none exist.
|
|
55
|
+
*/
|
|
22
56
|
export function getAuthFilePath() {
|
|
23
|
-
|
|
57
|
+
const possiblePaths = getPossibleAuthPaths();
|
|
58
|
+
// Return the first existing path
|
|
59
|
+
for (const path of possiblePaths) {
|
|
60
|
+
if (existsSync(path)) {
|
|
61
|
+
return path;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Return the default (first) path if none exist
|
|
65
|
+
return possiblePaths[0];
|
|
24
66
|
}
|