@howaboua/opencode-usage-plugin 0.1.2 → 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/copilot/auth.d.ts +0 -1
- package/dist/providers/copilot/auth.d.ts.map +1 -1
- package/dist/providers/copilot/auth.js +0 -1
- 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 +0 -1
- package/dist/providers/copilot/response.js +1 -1
- 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 +49 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/status.d.ts.map +1 -1
- package/dist/ui/status.js +54 -5
- package/dist/usage/config.d.ts.map +1 -1
- package/dist/usage/config.js +13 -6
- package/dist/usage/fetch.d.ts +4 -0
- package/dist/usage/fetch.d.ts.map +1 -1
- package/dist/usage/fetch.js +135 -17
- 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/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 +33 -8
- package/package.json +4 -2
|
@@ -1,7 +1,6 @@
|
|
|
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 standard OpenCode credentials.
|
|
5
4
|
*/
|
|
6
5
|
import { type CopilotAuthData } from "./types.js";
|
|
7
6
|
export declare function readCopilotAuth(): Promise<CopilotAuthData | null>;
|
|
@@ -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,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 the internal API.
|
|
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,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 the internal API.
|
|
5
4
|
*/
|
|
6
5
|
import { readCopilotAuth } from "./auth.js";
|
|
7
6
|
import { toCopilotQuotaFromInternal, } from "./response.js";
|
|
@@ -21,7 +21,7 @@ export function toCopilotQuotaFromInternal(data) {
|
|
|
21
21
|
percentRemaining: chatTotal > 0 ? Math.round((chatRemaining / chatTotal) * 100) : 0,
|
|
22
22
|
resetTime: data.limited_user_reset_date || data.quota_reset_date,
|
|
23
23
|
completionsUsed: completionsRemaining,
|
|
24
|
-
completionsTotal
|
|
24
|
+
completionsTotal,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
if (data.quota_snapshots?.premium_interactions) {
|
|
@@ -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;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(),
|
|
@@ -136,7 +184,7 @@ export const ProxyProvider = {
|
|
|
136
184
|
const config = await loadUsageConfig();
|
|
137
185
|
const data = await fetchProxyLimits(config);
|
|
138
186
|
return {
|
|
139
|
-
timestamp: data.timestamp * 1000,
|
|
187
|
+
timestamp: (data.timestamp || Date.now() / 1000) * 1000,
|
|
140
188
|
provider: "proxy",
|
|
141
189
|
planType: null,
|
|
142
190
|
primary: null,
|
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;
|
|
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;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
|
@@ -1,6 +1,8 @@
|
|
|
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
7
|
// @ts-ignore
|
|
6
8
|
const bus = options.client.bus;
|
|
@@ -82,21 +84,28 @@ function formatResetSuffixISO(isoString) {
|
|
|
82
84
|
}
|
|
83
85
|
function formatProxySnapshot(snapshot) {
|
|
84
86
|
const proxy = snapshot.proxyQuota;
|
|
85
|
-
if (!proxy)
|
|
87
|
+
if (!proxy || !proxy.providers || proxy.providers.length === 0)
|
|
86
88
|
return ["→ [proxy] No data"];
|
|
87
89
|
const lines = ["→ [Google] Mirrowel Proxy"];
|
|
88
90
|
for (const provider of proxy.providers) {
|
|
89
|
-
|
|
90
|
-
lines.push(` ${provider.name}:`);
|
|
91
|
+
const providerLines = [];
|
|
91
92
|
for (const tierInfo of provider.tiers) {
|
|
93
|
+
if (!tierInfo.quotaGroups || tierInfo.quotaGroups.length === 0)
|
|
94
|
+
continue;
|
|
92
95
|
const tierLabel = tierInfo.tier === "paid" ? "Paid" : "Free";
|
|
93
|
-
|
|
96
|
+
providerLines.push(` ${tierLabel}:`);
|
|
94
97
|
for (const group of tierInfo.quotaGroups) {
|
|
95
98
|
const resetSuffix = group.resetTime ? formatResetSuffixISO(group.resetTime) : "";
|
|
96
99
|
const label = `${group.name}:`.padEnd(9);
|
|
97
|
-
|
|
100
|
+
providerLines.push(` ${label} ${formatBar(group.remainingPct)} ${group.remaining}/${group.max}${resetSuffix}`);
|
|
98
101
|
}
|
|
99
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
|
+
}
|
|
100
109
|
}
|
|
101
110
|
return lines;
|
|
102
111
|
}
|
|
@@ -120,7 +129,47 @@ function formatCopilotSnapshot(snapshot) {
|
|
|
120
129
|
}
|
|
121
130
|
return lines;
|
|
122
131
|
}
|
|
132
|
+
function getAppDataPath() {
|
|
133
|
+
const home = homedir();
|
|
134
|
+
const plat = platform();
|
|
135
|
+
if (plat === "darwin")
|
|
136
|
+
return join(home, ".config", "opencode");
|
|
137
|
+
if (plat === "win32")
|
|
138
|
+
return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode");
|
|
139
|
+
return join(process.env.XDG_CONFIG_HOME || join(home, ".config"), "opencode");
|
|
140
|
+
}
|
|
141
|
+
function formatMissingSnapshot(snapshot) {
|
|
142
|
+
const provider = snapshot.provider;
|
|
143
|
+
const configPath = join(getAppDataPath(), "usage-config.jsonc");
|
|
144
|
+
let providerInstruction = "";
|
|
145
|
+
if (provider === "codex") {
|
|
146
|
+
providerInstruction = "if you dont have codex oauth, please set your usage-config.jsonc to openai: false";
|
|
147
|
+
}
|
|
148
|
+
else if (provider === "proxy") {
|
|
149
|
+
providerInstruction = "if you are not running Mirrowel's proxy, please set your usage-config.jsonc to proxy: false";
|
|
150
|
+
}
|
|
151
|
+
else if (provider === "copilot") {
|
|
152
|
+
providerInstruction = "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false";
|
|
153
|
+
}
|
|
154
|
+
const lines = [
|
|
155
|
+
`→ [${provider.toUpperCase()}] - ${providerInstruction}`,
|
|
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;
|
|
168
|
+
}
|
|
123
169
|
function formatSnapshot(snapshot) {
|
|
170
|
+
if (snapshot.isMissing) {
|
|
171
|
+
return formatMissingSnapshot(snapshot);
|
|
172
|
+
}
|
|
124
173
|
if (snapshot.provider === "proxy" && snapshot.proxyQuota) {
|
|
125
174
|
return formatProxySnapshot(snapshot);
|
|
126
175
|
}
|
|
@@ -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,15 +2,22 @@
|
|
|
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
|
-
{
|
|
20
|
+
const content = `{
|
|
14
21
|
"endpoint": "",
|
|
15
22
|
"apiKey": "",
|
|
16
23
|
"timeout": 10000,
|
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
|
@@ -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({
|
|
@@ -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,9 +49,11 @@ 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 = [];
|
|
55
|
+
const coreProviders = ["codex", "proxy", "copilot"];
|
|
56
|
+
const fetchedProviders = new Set();
|
|
54
57
|
const fetches = entries
|
|
55
58
|
.filter((entry) => !targetProvider || entry.providerID === targetProvider)
|
|
56
59
|
.filter((entry) => isProviderEnabled(entry.providerID))
|
|
@@ -58,39 +61,154 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
58
61
|
const provider = providers[entry.providerID];
|
|
59
62
|
if (!provider?.fetchUsage)
|
|
60
63
|
return;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
try {
|
|
65
|
+
const snapshot = await provider.fetchUsage(entry.auth);
|
|
66
|
+
if (snapshot) {
|
|
67
|
+
snapshots.push(snapshot);
|
|
68
|
+
fetchedProviders.add(entry.providerID);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
}
|
|
64
73
|
});
|
|
65
74
|
const specialProviders = ["proxy", "copilot"];
|
|
66
75
|
for (const id of specialProviders) {
|
|
67
|
-
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id)) {
|
|
76
|
+
if ((!targetProvider || targetProvider === id) && isProviderEnabled(id) && !fetchedProviders.has(id)) {
|
|
68
77
|
const provider = providers[id];
|
|
69
78
|
if (provider?.fetchUsage) {
|
|
70
79
|
fetches.push(provider
|
|
71
80
|
.fetchUsage(undefined)
|
|
72
81
|
.then((snapshot) => {
|
|
73
|
-
if (snapshot)
|
|
82
|
+
if (snapshot) {
|
|
74
83
|
snapshots.push(snapshot);
|
|
84
|
+
fetchedProviders.add(id);
|
|
85
|
+
}
|
|
75
86
|
})
|
|
76
87
|
.catch(() => { }));
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
await Promise.race([Promise.all(fetches), timeout(5000)]);
|
|
92
|
+
for (const id of coreProviders) {
|
|
93
|
+
if (isProviderEnabled(id) && !fetchedProviders.has(id)) {
|
|
94
|
+
if (!targetProvider || targetProvider === id) {
|
|
95
|
+
const codexDetails = id === "codex" && codexDiagnostics.length > 0 ? codexDiagnostics : undefined;
|
|
96
|
+
snapshots.push({
|
|
97
|
+
timestamp: Date.now(),
|
|
98
|
+
provider: id,
|
|
99
|
+
planType: null,
|
|
100
|
+
primary: null,
|
|
101
|
+
secondary: null,
|
|
102
|
+
codeReview: null,
|
|
103
|
+
credits: null,
|
|
104
|
+
updatedAt: Date.now(),
|
|
105
|
+
isMissing: true,
|
|
106
|
+
missingReason: codexDetails ? "Codex auth was not resolved from auth.json." : undefined,
|
|
107
|
+
missingDetails: codexDetails,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
81
112
|
return snapshots;
|
|
82
113
|
}
|
|
83
114
|
export async function loadAuths() {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
115
|
+
const { auths } = await loadAuthsWithDiagnostics();
|
|
116
|
+
return auths;
|
|
117
|
+
}
|
|
118
|
+
export async function loadAuthsWithDiagnostics() {
|
|
119
|
+
const possiblePaths = getPossibleAuthPaths();
|
|
120
|
+
const mergedAuth = {};
|
|
121
|
+
const codexDiagnostics = [];
|
|
122
|
+
const orderedPaths = [...possiblePaths].reverse();
|
|
123
|
+
codexDiagnostics.push(`Auth paths checked: ${possiblePaths.join(", ")}`);
|
|
124
|
+
for (const authPath of orderedPaths) {
|
|
125
|
+
try {
|
|
126
|
+
const file = Bun.file(authPath);
|
|
127
|
+
const exists = await file.exists();
|
|
128
|
+
if (!exists) {
|
|
129
|
+
codexDiagnostics.push(`Missing auth file: ${authPath}`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const data = await file.json();
|
|
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}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
165
|
+
codexDiagnostics.push(`Failed to read auth file ${authPath}: ${message}`);
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
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 };
|
|
182
|
+
}
|
|
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}`);
|
|
198
|
+
return {
|
|
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
|
+
},
|
|
206
|
+
},
|
|
207
|
+
diagnostics,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function isRecord(value) {
|
|
211
|
+
return typeof value === "object" && value !== null;
|
|
94
212
|
}
|
|
95
213
|
function timeout(ms) {
|
|
96
214
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
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 });
|
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,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
|
@@ -4,21 +4,46 @@
|
|
|
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();
|
|
10
|
-
if (plat === "darwin") {
|
|
11
|
-
return join(home, "Library", "Application Support", "opencode");
|
|
12
|
-
}
|
|
13
11
|
if (plat === "win32") {
|
|
14
12
|
return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode");
|
|
15
13
|
}
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const dataHome = process.env.XDG_DATA_HOME || join(home, ".local", "share");
|
|
15
|
+
return join(dataHome, "opencode");
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns all possible auth file paths for the current platform.
|
|
19
|
+
* On macOS, OpenCode uses Linux-style paths, so we check both.
|
|
20
|
+
*/
|
|
21
|
+
export function getPossibleAuthPaths() {
|
|
22
|
+
const plat = platform();
|
|
23
|
+
const home = homedir();
|
|
24
|
+
const pathSet = new Set();
|
|
25
|
+
if (plat === "win32") {
|
|
26
|
+
pathSet.add(join(process.env.APPDATA || join(home, "AppData", "Roaming"), "opencode", "auth.json"));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Linux/other
|
|
30
|
+
const dataHome = process.env.XDG_DATA_HOME || join(home, ".local", "share");
|
|
31
|
+
pathSet.add(join(dataHome, "opencode", "auth.json"));
|
|
32
|
+
pathSet.add(join(home, ".codex", "auth.json"));
|
|
19
33
|
}
|
|
20
|
-
return
|
|
34
|
+
return Array.from(pathSet);
|
|
21
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the first existing auth file path, or the default location if none exist.
|
|
38
|
+
*/
|
|
22
39
|
export function getAuthFilePath() {
|
|
23
|
-
|
|
40
|
+
const possiblePaths = getPossibleAuthPaths();
|
|
41
|
+
// Return the first existing path
|
|
42
|
+
for (const path of possiblePaths) {
|
|
43
|
+
if (existsSync(path)) {
|
|
44
|
+
return path;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Return the default (first) path if none exist
|
|
48
|
+
return possiblePaths[0];
|
|
24
49
|
}
|
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"
|