@howaboua/opencode-usage-plugin 0.1.3 → 0.1.4-dev.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.
- package/dist/providers/proxy/index.d.ts.map +1 -1
- package/dist/providers/proxy/index.js +48 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/status.d.ts.map +1 -1
- package/dist/ui/status.js +24 -11
- package/dist/usage/fetch.d.ts +4 -0
- package/dist/usage/fetch.d.ts.map +1 -1
- package/dist/usage/fetch.js +88 -35
- package/dist/usage/registry.d.ts +5 -0
- package/dist/usage/registry.d.ts.map +1 -1
- package/dist/usage/registry.js +11 -2
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +5 -22
- package/package.json +4 -2
|
@@ -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;AAkM5C,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,IAAI,CAwB7C,CAAA"}
|
|
@@ -39,6 +39,49 @@ function normalizeTier(tier) {
|
|
|
39
39
|
return "paid";
|
|
40
40
|
return "free";
|
|
41
41
|
}
|
|
42
|
+
function parseQuotaGroupsFromAggregation(quotaGroups) {
|
|
43
|
+
if (!quotaGroups)
|
|
44
|
+
return [];
|
|
45
|
+
const tiers = {
|
|
46
|
+
paid: new Map(),
|
|
47
|
+
free: new Map(),
|
|
48
|
+
};
|
|
49
|
+
for (const [groupName, groupData] of Object.entries(quotaGroups)) {
|
|
50
|
+
const mappedName = GROUP_MAPPING[groupName];
|
|
51
|
+
if (!mappedName)
|
|
52
|
+
continue;
|
|
53
|
+
const windows = groupData.windows || {};
|
|
54
|
+
const windowPriority = ["daily", "5h", "1h", "15m"];
|
|
55
|
+
let bestWindowName = null;
|
|
56
|
+
for (const windowName of windowPriority) {
|
|
57
|
+
if (windows[windowName]) {
|
|
58
|
+
bestWindowName = windowName;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!bestWindowName && Object.keys(windows).length > 0) {
|
|
63
|
+
bestWindowName = Object.keys(windows)[0];
|
|
64
|
+
}
|
|
65
|
+
if (!bestWindowName)
|
|
66
|
+
continue;
|
|
67
|
+
const window = windows[bestWindowName];
|
|
68
|
+
// Since these are already aggregated by provider, we split by tier if possible.
|
|
69
|
+
// However, the aggregate API provides tier-agnostic totals.
|
|
70
|
+
// For now, we put them into "paid" as the default high-level view.
|
|
71
|
+
tiers.paid.set(mappedName, {
|
|
72
|
+
name: mappedName,
|
|
73
|
+
remaining: window.total_remaining,
|
|
74
|
+
max: window.total_max,
|
|
75
|
+
remainingPct: Math.round(window.remaining_pct),
|
|
76
|
+
resetTime: null, // Aggregated windows don't have a single reset_at
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const result = [];
|
|
80
|
+
if (tiers.paid.size > 0) {
|
|
81
|
+
result.push({ tier: "paid", quotaGroups: sortQuotaGroups(Array.from(tiers.paid.values())) });
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
42
85
|
function parseQuotaGroupsFromCredential(groupUsage) {
|
|
43
86
|
if (!groupUsage)
|
|
44
87
|
return [];
|
|
@@ -72,6 +115,11 @@ function parseQuotaGroupsFromCredential(groupUsage) {
|
|
|
72
115
|
return Array.from(result.values());
|
|
73
116
|
}
|
|
74
117
|
function aggregateByProvider(provider) {
|
|
118
|
+
// Try aggregated quota groups first
|
|
119
|
+
if (provider.quota_groups && Object.keys(provider.quota_groups).length > 0) {
|
|
120
|
+
return parseQuotaGroupsFromAggregation(provider.quota_groups);
|
|
121
|
+
}
|
|
122
|
+
// Fallback to manual aggregation of credentials
|
|
75
123
|
const tiers = {
|
|
76
124
|
paid: new Map(),
|
|
77
125
|
free: new Map(),
|
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;IAC/B,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,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;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;
|
|
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;AAkMD,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
|
@@ -84,21 +84,28 @@ function formatResetSuffixISO(isoString) {
|
|
|
84
84
|
}
|
|
85
85
|
function formatProxySnapshot(snapshot) {
|
|
86
86
|
const proxy = snapshot.proxyQuota;
|
|
87
|
-
if (!proxy)
|
|
87
|
+
if (!proxy || !proxy.providers || proxy.providers.length === 0)
|
|
88
88
|
return ["→ [proxy] No data"];
|
|
89
89
|
const lines = ["→ [Google] Mirrowel Proxy"];
|
|
90
90
|
for (const provider of proxy.providers) {
|
|
91
|
-
|
|
92
|
-
lines.push(` ${provider.name}:`);
|
|
91
|
+
const providerLines = [];
|
|
93
92
|
for (const tierInfo of provider.tiers) {
|
|
93
|
+
if (!tierInfo.quotaGroups || tierInfo.quotaGroups.length === 0)
|
|
94
|
+
continue;
|
|
94
95
|
const tierLabel = tierInfo.tier === "paid" ? "Paid" : "Free";
|
|
95
|
-
|
|
96
|
+
providerLines.push(` ${tierLabel}:`);
|
|
96
97
|
for (const group of tierInfo.quotaGroups) {
|
|
97
98
|
const resetSuffix = group.resetTime ? formatResetSuffixISO(group.resetTime) : "";
|
|
98
99
|
const label = `${group.name}:`.padEnd(9);
|
|
99
|
-
|
|
100
|
+
providerLines.push(` ${label} ${formatBar(group.remainingPct)} ${group.remaining}/${group.max}${resetSuffix}`);
|
|
100
101
|
}
|
|
101
102
|
}
|
|
103
|
+
if (providerLines.length > 0) {
|
|
104
|
+
lines.push("");
|
|
105
|
+
lines.push(` ${provider.name}:`);
|
|
106
|
+
for (const line of providerLines)
|
|
107
|
+
lines.push(line);
|
|
108
|
+
}
|
|
102
109
|
}
|
|
103
110
|
return lines;
|
|
104
111
|
}
|
|
@@ -133,7 +140,6 @@ function getAppDataPath() {
|
|
|
133
140
|
}
|
|
134
141
|
function formatMissingSnapshot(snapshot) {
|
|
135
142
|
const provider = snapshot.provider;
|
|
136
|
-
const label = provider === "codex" ? "codex" : provider === "proxy" ? "proxy" : "gh";
|
|
137
143
|
const configPath = join(getAppDataPath(), "usage-config.jsonc");
|
|
138
144
|
let providerInstruction = "";
|
|
139
145
|
if (provider === "codex") {
|
|
@@ -145,13 +151,20 @@ function formatMissingSnapshot(snapshot) {
|
|
|
145
151
|
else if (provider === "copilot") {
|
|
146
152
|
providerInstruction = "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false";
|
|
147
153
|
}
|
|
148
|
-
|
|
154
|
+
const lines = [
|
|
149
155
|
`→ [${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
156
|
];
|
|
157
|
+
if (snapshot.missingReason) {
|
|
158
|
+
lines.push("", `Reason: ${snapshot.missingReason}`);
|
|
159
|
+
}
|
|
160
|
+
if (snapshot.missingDetails && snapshot.missingDetails.length > 0) {
|
|
161
|
+
lines.push("", "Details:");
|
|
162
|
+
for (const detail of snapshot.missingDetails) {
|
|
163
|
+
lines.push(`- ${detail}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
lines.push("", `The file can be found in ${configPath}. Please read the comments in the file or visit the repo for the readme.`, "", "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!");
|
|
167
|
+
return lines;
|
|
155
168
|
}
|
|
156
169
|
function formatSnapshot(snapshot) {
|
|
157
170
|
if (snapshot.isMissing) {
|
package/dist/usage/fetch.d.ts
CHANGED
|
@@ -8,4 +8,8 @@ export declare const providerAliases: Record<string, string>;
|
|
|
8
8
|
export declare function resolveProviderFilter(filter?: string): string | undefined;
|
|
9
9
|
export declare function fetchUsageSnapshots(filter?: string): Promise<UsageSnapshot[]>;
|
|
10
10
|
export declare function loadAuths(): Promise<AuthRecord>;
|
|
11
|
+
export declare function loadAuthsWithDiagnostics(): Promise<{
|
|
12
|
+
auths: AuthRecord;
|
|
13
|
+
codexDiagnostics: string[];
|
|
14
|
+
}>;
|
|
11
15
|
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -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;
|
|
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;AAgB5C,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,CA+EnF;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CAGrD;AAED,wBAAsB,wBAAwB,IAAI,OAAO,CAAC;IACxD,KAAK,EAAE,UAAU,CAAA;IACjB,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAC3B,CAAC,CAsED"}
|
package/dist/usage/fetch.js
CHANGED
|
@@ -14,6 +14,7 @@ const authEntrySchema = z
|
|
|
14
14
|
refresh: z.string().optional(),
|
|
15
15
|
enterpriseUrl: z.string().optional(),
|
|
16
16
|
accountId: z.string().optional(),
|
|
17
|
+
key: z.string().optional(),
|
|
17
18
|
})
|
|
18
19
|
.passthrough();
|
|
19
20
|
const authRecordSchema = z.record(z.string(), authEntrySchema);
|
|
@@ -48,7 +49,7 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
48
49
|
return providerToggles.copilot !== false;
|
|
49
50
|
return true;
|
|
50
51
|
};
|
|
51
|
-
const auths = await
|
|
52
|
+
const { auths, codexDiagnostics } = await loadAuthsWithDiagnostics();
|
|
52
53
|
const entries = resolveProviderAuths(auths, null);
|
|
53
54
|
const snapshots = [];
|
|
54
55
|
const coreProviders = ["codex", "proxy", "copilot"];
|
|
@@ -72,7 +73,7 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
72
73
|
});
|
|
73
74
|
const specialProviders = ["proxy", "copilot"];
|
|
74
75
|
for (const id of specialProviders) {
|
|
75
|
-
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id)) {
|
|
76
|
+
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id) && !fetchedProviders.has(id)) {
|
|
76
77
|
const provider = providers[id];
|
|
77
78
|
if (provider?.fetchUsage) {
|
|
78
79
|
fetches.push(provider
|
|
@@ -91,6 +92,7 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
91
92
|
for (const id of coreProviders) {
|
|
92
93
|
if (isProviderEnabled(id) && !fetchedProviders.has(id)) {
|
|
93
94
|
if (!targetProvider || targetProvider === id) {
|
|
95
|
+
const codexDetails = id === "codex" && codexDiagnostics.length > 0 ? codexDiagnostics : undefined;
|
|
94
96
|
snapshots.push({
|
|
95
97
|
timestamp: Date.now(),
|
|
96
98
|
provider: id,
|
|
@@ -101,6 +103,8 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
101
103
|
credits: null,
|
|
102
104
|
updatedAt: Date.now(),
|
|
103
105
|
isMissing: true,
|
|
106
|
+
missingReason: codexDetails ? "Codex auth was not resolved from auth.json." : undefined,
|
|
107
|
+
missingDetails: codexDetails,
|
|
104
108
|
});
|
|
105
109
|
}
|
|
106
110
|
}
|
|
@@ -108,55 +112,104 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
108
112
|
return snapshots;
|
|
109
113
|
}
|
|
110
114
|
export async function loadAuths() {
|
|
115
|
+
const { auths } = await loadAuthsWithDiagnostics();
|
|
116
|
+
return auths;
|
|
117
|
+
}
|
|
118
|
+
export async function loadAuthsWithDiagnostics() {
|
|
111
119
|
const possiblePaths = getPossibleAuthPaths();
|
|
112
120
|
const mergedAuth = {};
|
|
113
|
-
|
|
121
|
+
const codexDiagnostics = [];
|
|
122
|
+
const orderedPaths = [...possiblePaths].reverse();
|
|
123
|
+
codexDiagnostics.push(`Auth paths checked: ${possiblePaths.join(", ")}`);
|
|
124
|
+
for (const authPath of orderedPaths) {
|
|
114
125
|
try {
|
|
115
126
|
const file = Bun.file(authPath);
|
|
116
|
-
|
|
127
|
+
const exists = await file.exists();
|
|
128
|
+
if (!exists) {
|
|
129
|
+
codexDiagnostics.push(`Missing auth file: ${authPath}`);
|
|
117
130
|
continue;
|
|
131
|
+
}
|
|
118
132
|
const data = await file.json();
|
|
119
|
-
if (data
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
if (!isRecord(data)) {
|
|
134
|
+
codexDiagnostics.push(`Auth file is not a JSON object: ${authPath}`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (authPath.includes(".codex")) {
|
|
138
|
+
const parsed = parseCodexAuth(data, authPath);
|
|
139
|
+
codexDiagnostics.push(...parsed.diagnostics);
|
|
140
|
+
if (parsed.auth)
|
|
141
|
+
Object.assign(mergedAuth, parsed.auth);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const parsed = authRecordSchema.safeParse(data);
|
|
145
|
+
if (!parsed.success) {
|
|
146
|
+
codexDiagnostics.push(`Auth file failed schema validation: ${authPath}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
Object.assign(mergedAuth, parsed.data);
|
|
150
|
+
const openaiEntry = parsed.data.openai ?? parsed.data.codex;
|
|
151
|
+
if (!openaiEntry) {
|
|
152
|
+
codexDiagnostics.push(`No "openai" or "codex" entry in auth file: ${authPath}`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
codexDiagnostics.push(`Found OpenAI/Codex entry in auth file: ${authPath}`);
|
|
156
|
+
if (openaiEntry.type && openaiEntry.type !== "oauth" && openaiEntry.type !== "token") {
|
|
157
|
+
codexDiagnostics.push(`OpenAI/Codex entry has unsupported type "${openaiEntry.type}" in ${authPath}`);
|
|
158
|
+
}
|
|
159
|
+
if (!openaiEntry.access && !openaiEntry.key) {
|
|
160
|
+
codexDiagnostics.push(`OpenAI/Codex entry missing "access" or "key" in ${authPath}`);
|
|
131
161
|
}
|
|
132
162
|
}
|
|
133
|
-
catch {
|
|
163
|
+
catch (error) {
|
|
164
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
165
|
+
codexDiagnostics.push(`Failed to read auth file ${authPath}: ${message}`);
|
|
134
166
|
continue;
|
|
135
167
|
}
|
|
136
168
|
}
|
|
137
|
-
|
|
169
|
+
const mergedEntry = mergedAuth.openai ?? mergedAuth.codex;
|
|
170
|
+
if (!mergedEntry) {
|
|
171
|
+
codexDiagnostics.push("Merged auth record has no OpenAI/Codex entry.");
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
if (mergedEntry.type && mergedEntry.type !== "oauth" && mergedEntry.type !== "token") {
|
|
175
|
+
codexDiagnostics.push(`Merged OpenAI/Codex entry has unsupported type "${mergedEntry.type}".`);
|
|
176
|
+
}
|
|
177
|
+
if (!mergedEntry.access && !mergedEntry.key) {
|
|
178
|
+
codexDiagnostics.push("Merged OpenAI/Codex entry missing access or key.");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { auths: mergedAuth, codexDiagnostics };
|
|
138
182
|
}
|
|
139
|
-
function
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return null;
|
|
150
|
-
|
|
183
|
+
function parseCodexAuth(data, authPath) {
|
|
184
|
+
const diagnostics = [];
|
|
185
|
+
const tokens = data.tokens;
|
|
186
|
+
if (!isRecord(tokens)) {
|
|
187
|
+
diagnostics.push(`Codex auth missing "tokens" object in ${authPath}`);
|
|
188
|
+
return { auth: null, diagnostics };
|
|
189
|
+
}
|
|
190
|
+
const accessToken = tokens.access_token;
|
|
191
|
+
if (typeof accessToken !== "string" || accessToken.length === 0) {
|
|
192
|
+
diagnostics.push(`Codex auth missing tokens.access_token in ${authPath}`);
|
|
193
|
+
return { auth: null, diagnostics };
|
|
194
|
+
}
|
|
195
|
+
const accountId = tokens.account_id;
|
|
196
|
+
const refreshToken = tokens.refresh_token;
|
|
197
|
+
diagnostics.push(`Codex CLI auth loaded from ${authPath}`);
|
|
151
198
|
return {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
199
|
+
auth: {
|
|
200
|
+
openai: {
|
|
201
|
+
type: "oauth",
|
|
202
|
+
access: accessToken,
|
|
203
|
+
accountId: typeof accountId === "string" ? accountId : undefined,
|
|
204
|
+
refresh: typeof refreshToken === "string" ? refreshToken : undefined,
|
|
205
|
+
},
|
|
157
206
|
},
|
|
207
|
+
diagnostics,
|
|
158
208
|
};
|
|
159
209
|
}
|
|
210
|
+
function isRecord(value) {
|
|
211
|
+
return typeof value === "object" && value !== null;
|
|
212
|
+
}
|
|
160
213
|
function timeout(ms) {
|
|
161
214
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
162
215
|
}
|
package/dist/usage/registry.d.ts
CHANGED
|
@@ -2,17 +2,22 @@
|
|
|
2
2
|
* Resolves provider auth entries for usage snapshots.
|
|
3
3
|
*/
|
|
4
4
|
import type { CodexAuth } from "../providers/codex";
|
|
5
|
+
import type { CopilotAuthData } from "../providers/copilot/types";
|
|
5
6
|
export type AuthEntry = {
|
|
6
7
|
type?: string;
|
|
7
8
|
access?: string;
|
|
8
9
|
refresh?: string;
|
|
9
10
|
enterpriseUrl?: string;
|
|
10
11
|
accountId?: string;
|
|
12
|
+
key?: string;
|
|
11
13
|
};
|
|
12
14
|
export type AuthRecord = Record<string, AuthEntry>;
|
|
13
15
|
type ProviderAuthEntry = {
|
|
14
16
|
providerID: "codex";
|
|
15
17
|
auth: CodexAuth;
|
|
18
|
+
} | {
|
|
19
|
+
providerID: "copilot";
|
|
20
|
+
auth: CopilotAuthData;
|
|
16
21
|
};
|
|
17
22
|
export declare function resolveProviderAuths(auths: AuthRecord, usageToken: string | null): ProviderAuthEntry[];
|
|
18
23
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/usage/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/usage/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAEjE,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AAElD,KAAK,iBAAiB,GAClB;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GACxC;IAAE,UAAU,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAA;AA8BpD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,EAAE,CActG"}
|
package/dist/usage/registry.js
CHANGED
|
@@ -7,10 +7,19 @@ const providerDescriptors = [
|
|
|
7
7
|
authKeys: ["codex", "openai"],
|
|
8
8
|
requiresOAuth: true,
|
|
9
9
|
buildAuth: (entry) => ({
|
|
10
|
-
access: entry.access,
|
|
10
|
+
access: entry.access || entry.key,
|
|
11
11
|
accountId: entry.accountId,
|
|
12
12
|
}),
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
id: "copilot",
|
|
16
|
+
authKeys: ["copilot", "github-copilot"],
|
|
17
|
+
requiresOAuth: true,
|
|
18
|
+
buildAuth: (entry) => ({
|
|
19
|
+
access: entry.access,
|
|
20
|
+
refresh: entry.refresh,
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
14
23
|
];
|
|
15
24
|
export function resolveProviderAuths(auths, usageToken) {
|
|
16
25
|
const entries = [];
|
|
@@ -21,7 +30,7 @@ export function resolveProviderAuths(auths, usageToken) {
|
|
|
21
30
|
const auth = auths[matched];
|
|
22
31
|
if (!auth)
|
|
23
32
|
continue;
|
|
24
|
-
if (descriptor.requiresOAuth && auth.type && auth.type !== "oauth")
|
|
33
|
+
if (descriptor.requiresOAuth && auth.type && auth.type !== "oauth" && auth.type !== "token")
|
|
25
34
|
continue;
|
|
26
35
|
const built = descriptor.buildAuth(auth, usageToken);
|
|
27
36
|
entries.push({ providerID: descriptor.id, auth: built });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,wBAAgB,cAAc,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,wBAAgB,cAAc,IAAI,MAAM,CAUvC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAe/C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAYxC"}
|
package/dist/utils/paths.js
CHANGED
|
@@ -8,17 +8,11 @@ import { existsSync } from "fs";
|
|
|
8
8
|
export function getAppDataPath() {
|
|
9
9
|
const plat = platform();
|
|
10
10
|
const home = homedir();
|
|
11
|
-
if (plat === "darwin") {
|
|
12
|
-
return join(home, "Library", "Application Support", "opencode");
|
|
13
|
-
}
|
|
14
11
|
if (plat === "win32") {
|
|
15
12
|
return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode");
|
|
16
13
|
}
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
return join(xdgData, "opencode");
|
|
20
|
-
}
|
|
21
|
-
return join(home, ".local", "share", "opencode");
|
|
14
|
+
const dataHome = process.env.XDG_DATA_HOME || join(home, ".local", "share");
|
|
15
|
+
return join(dataHome, "opencode");
|
|
22
16
|
}
|
|
23
17
|
/**
|
|
24
18
|
* Returns all possible auth file paths for the current platform.
|
|
@@ -28,24 +22,13 @@ export function getPossibleAuthPaths() {
|
|
|
28
22
|
const plat = platform();
|
|
29
23
|
const home = homedir();
|
|
30
24
|
const pathSet = new Set();
|
|
31
|
-
if (plat === "
|
|
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") {
|
|
25
|
+
if (plat === "win32") {
|
|
40
26
|
pathSet.add(join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode", "auth.json"));
|
|
41
27
|
}
|
|
42
28
|
else {
|
|
43
29
|
// Linux/other
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
pathSet.add(join(xdgData, "opencode", "auth.json"));
|
|
47
|
-
}
|
|
48
|
-
pathSet.add(join(home, ".local", "share", "opencode", "auth.json"));
|
|
30
|
+
const dataHome = process.env.XDG_DATA_HOME || join(home, ".local", "share");
|
|
31
|
+
pathSet.add(join(dataHome, "opencode", "auth.json"));
|
|
49
32
|
pathSet.add(join(home, ".codex", "auth.json"));
|
|
50
33
|
}
|
|
51
34
|
return Array.from(pathSet);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@howaboua/opencode-usage-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4-dev.0",
|
|
4
4
|
"description": "opencode plugin for tracking AI provider usage, rate limits, and quotas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
"scripts": {
|
|
32
32
|
"clean": "rm -rf dist",
|
|
33
33
|
"build": "npm run clean && tsc",
|
|
34
|
-
"prepublishOnly": "npm run build"
|
|
34
|
+
"prepublishOnly": "npm run build",
|
|
35
|
+
"publish:dev": "npm publish --tag dev",
|
|
36
|
+
"release:dev": "npm version prerelease --preid dev && npm publish --tag dev"
|
|
35
37
|
},
|
|
36
38
|
"publishConfig": {
|
|
37
39
|
"access": "public"
|