@howaboua/opencode-usage-plugin 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/hooks/command.d.ts.map +1 -1
- package/dist/hooks/command.js +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/providers/anthropic/auth.d.ts +3 -0
- package/dist/providers/anthropic/auth.d.ts.map +1 -0
- package/dist/providers/anthropic/auth.js +42 -0
- package/dist/providers/anthropic/fetch.d.ts +4 -0
- package/dist/providers/anthropic/fetch.d.ts.map +1 -0
- package/dist/providers/anthropic/fetch.js +44 -0
- package/dist/providers/anthropic/index.d.ts +3 -0
- package/dist/providers/anthropic/index.d.ts.map +1 -0
- package/dist/providers/anthropic/index.js +30 -0
- package/dist/providers/anthropic/parse.d.ts +5 -0
- package/dist/providers/anthropic/parse.d.ts.map +1 -0
- package/dist/providers/anthropic/parse.js +112 -0
- package/dist/providers/anthropic/types.d.ts +68 -0
- package/dist/providers/anthropic/types.d.ts.map +1 -0
- package/dist/providers/anthropic/types.js +44 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +6 -0
- package/dist/providers/openrouter/fetch.d.ts +6 -0
- package/dist/providers/openrouter/fetch.d.ts.map +1 -0
- package/dist/providers/openrouter/fetch.js +39 -0
- package/dist/providers/openrouter/index.d.ts +8 -0
- package/dist/providers/openrouter/index.d.ts.map +1 -0
- package/dist/providers/openrouter/index.js +55 -0
- package/dist/providers/openrouter/types.d.ts +35 -0
- package/dist/providers/openrouter/types.d.ts.map +1 -0
- package/dist/providers/openrouter/types.js +32 -0
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +1 -0
- package/dist/types.d.ts +35 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/ui/formatters/anthropic.d.ts +3 -0
- package/dist/ui/formatters/anthropic.d.ts.map +1 -0
- package/dist/ui/formatters/anthropic.js +71 -0
- package/dist/ui/formatters/openrouter.d.ts +6 -0
- package/dist/ui/formatters/openrouter.d.ts.map +1 -0
- package/dist/ui/formatters/openrouter.js +23 -0
- package/dist/ui/formatters/shared.d.ts.map +1 -1
- package/dist/ui/formatters/shared.js +3 -1
- package/dist/ui/status.d.ts.map +1 -1
- package/dist/ui/status.js +8 -0
- package/dist/usage/config.d.ts.map +1 -1
- package/dist/usage/config.js +5 -1
- package/dist/usage/fetch.d.ts.map +1 -1
- package/dist/usage/fetch.js +7 -3
- package/dist/usage/registry.d.ts +4 -0
- package/dist/usage/registry.d.ts.map +1 -1
- package/dist/usage/registry.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,11 @@ Track AI provider rate limits and quotas in real-time.
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Live rate limits** – See Codex/OpenAI hourly/weekly limits at a glance
|
|
8
|
+
- **Anthropic subscription limits** – Track Claude OAuth windows (5h, 7d, Sonnet/Opus/cowork tiers)
|
|
8
9
|
- **Proxy quota stats** – Monitor Mirrowel Proxy credentials and tier usage
|
|
9
10
|
- **Copilot usage** – Track GitHub Copilot chat + completions quotas
|
|
11
|
+
- **Z.ai usage** – Track GLM Coding Plan 5-hour token quota and monthly tool quota
|
|
12
|
+
- **OpenRouter usage** – Track API credit usage and remaining balance
|
|
10
13
|
- **Inline status** – Results appear directly in your chat, no context switching
|
|
11
14
|
- **Zero setup** – Auto-detects providers from your existing config
|
|
12
15
|
|
|
@@ -45,11 +48,17 @@ The plugin creates a default config file on first run at:
|
|
|
45
48
|
// Optional: Request timeout in milliseconds (default: 10000)
|
|
46
49
|
"timeout": 10000,
|
|
47
50
|
|
|
51
|
+
// Optional: Z.ai API endpoint (default: "https://api.z.ai")
|
|
52
|
+
"zaiEndpoint": "https://api.z.ai",
|
|
53
|
+
|
|
48
54
|
// Optional: Show/hide providers in /usage output
|
|
49
55
|
"providers": {
|
|
50
56
|
"openai": true,
|
|
57
|
+
"anthropic": true,
|
|
51
58
|
"proxy": true,
|
|
52
|
-
"copilot": true
|
|
59
|
+
"copilot": true,
|
|
60
|
+
"zai": true,
|
|
61
|
+
"openrouter": true
|
|
53
62
|
},
|
|
54
63
|
|
|
55
64
|
// Model group display configuration (optional)
|
|
@@ -106,8 +115,14 @@ Copilot is detected from either of these locations:
|
|
|
106
115
|
|
|
107
116
|
```
|
|
108
117
|
/usage codex
|
|
118
|
+
/usage anthropic
|
|
119
|
+
/usage claude
|
|
109
120
|
/usage proxy
|
|
110
121
|
/usage copilot
|
|
122
|
+
/usage zai
|
|
123
|
+
/usage glm
|
|
124
|
+
/usage openrouter
|
|
125
|
+
/usage or
|
|
111
126
|
```
|
|
112
127
|
|
|
113
128
|
### Support the proxy
|
|
@@ -121,8 +136,11 @@ Copilot is detected from either of these locations:
|
|
|
121
136
|
| Provider | Source |
|
|
122
137
|
|----------|--------|
|
|
123
138
|
| **Codex / OpenAI** | Auth tokens + `/wham/usage` endpoint |
|
|
139
|
+
| **Anthropic Claude** | OAuth profile + `/api/oauth/usage` windows |
|
|
124
140
|
| **Mirrowel Proxy** | Local `/v1/quota-stats` endpoint |
|
|
125
141
|
| **GitHub Copilot** | GitHub internal usage APIs |
|
|
142
|
+
| **Z.ai GLM Coding Plan** | `chat.z.ai` auth + Z.ai usage APIs |
|
|
143
|
+
| **OpenRouter** | API key + `openrouter.ai/api/v1/key` |
|
|
126
144
|
|
|
127
145
|
## Troubleshooting
|
|
128
146
|
|
|
@@ -136,6 +154,9 @@ Copilot is detected from either of these locations:
|
|
|
136
154
|
- Use `providers: { ... }` in config to disable unused providers
|
|
137
155
|
- For Codex: Ensure you have valid auth tokens
|
|
138
156
|
- For Copilot: Check token file locations in Configuration section above
|
|
157
|
+
- For Z.ai: Ensure your OpenCode auth includes `chat.z.ai` credentials
|
|
158
|
+
- For Anthropic: Ensure Claude OAuth credentials are available (`anthropic` in auth.json)
|
|
159
|
+
- For OpenRouter: Ensure OpenRouter API key is available (`openrouter` or `or` in auth.json)
|
|
139
160
|
|
|
140
161
|
**Config file not found**
|
|
141
162
|
- The plugin auto-creates `usage-config.jsonc` on first run
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/hooks/command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAI1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAWxC,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;CAClB,GAAG,IAAI,CAAC,KAAK,EAAE,wBAAwB,GAAG,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/hooks/command.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAI1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAWxC,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;CAClB,GAAG,IAAI,CAAC,KAAK,EAAE,wBAAwB,GAAG,QAAQ,CAAC,CAqDnD"}
|
package/dist/hooks/command.js
CHANGED
|
@@ -11,7 +11,7 @@ export function commandHooks(options) {
|
|
|
11
11
|
config.command ??= {};
|
|
12
12
|
config.command["usage"] = {
|
|
13
13
|
template: "/usage",
|
|
14
|
-
description: "Show API usage and rate limits (codex/proxy
|
|
14
|
+
description: "Show API usage and rate limits (anthropic/codex/proxy/copilot/zai)",
|
|
15
15
|
};
|
|
16
16
|
},
|
|
17
17
|
"command.execute.before": async (input) => {
|
|
@@ -36,6 +36,8 @@ export function commandHooks(options) {
|
|
|
36
36
|
return true;
|
|
37
37
|
if (s.provider === "codex")
|
|
38
38
|
return options.state.availableProviders.codex;
|
|
39
|
+
if (s.provider === "anthropic")
|
|
40
|
+
return options.state.availableProviders.anthropic;
|
|
39
41
|
if (s.provider === "proxy")
|
|
40
42
|
return options.state.availableProviders.proxy;
|
|
41
43
|
if (s.provider === "copilot")
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAMjD,eAAO,MAAM,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAMjD,eAAO,MAAM,WAAW,EAAE,MAqCzB,CAAA;AAED,eAAe,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ export const UsagePlugin = async ({ client }) => {
|
|
|
12
12
|
state.availableProviders.codex = usageConfig?.providers?.openai !== false;
|
|
13
13
|
state.availableProviders.proxy = usageConfig?.providers?.proxy !== false;
|
|
14
14
|
state.availableProviders.copilot = usageConfig?.providers?.copilot !== false;
|
|
15
|
+
state.availableProviders.anthropic = usageConfig?.providers?.anthropic !== false;
|
|
15
16
|
}
|
|
16
17
|
catch (err) { }
|
|
17
18
|
async function sendStatusMessage(sessionID, text) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/auth.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAqC3E"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { getAuthFilePath } from "../../utils/paths.js";
|
|
6
|
+
export async function readAnthropicAuth() {
|
|
7
|
+
// 1. Check environment variable
|
|
8
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
9
|
+
return { access: process.env.CLAUDE_CODE_OAUTH_TOKEN };
|
|
10
|
+
}
|
|
11
|
+
// 2. Check opencode auth.json
|
|
12
|
+
try {
|
|
13
|
+
const authPath = getAuthFilePath();
|
|
14
|
+
if (existsSync(authPath)) {
|
|
15
|
+
const content = await readFile(authPath, "utf-8");
|
|
16
|
+
const authData = JSON.parse(content);
|
|
17
|
+
const anthropicAuth = authData?.["anthropic"];
|
|
18
|
+
if (anthropicAuth?.access) {
|
|
19
|
+
return anthropicAuth;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
// 3. Check ~/.claude/credentials.json (Claude Code)
|
|
25
|
+
try {
|
|
26
|
+
const claudePath = join(homedir(), ".claude", "credentials.json");
|
|
27
|
+
if (existsSync(claudePath)) {
|
|
28
|
+
const content = await readFile(claudePath, "utf-8");
|
|
29
|
+
const creds = JSON.parse(content);
|
|
30
|
+
const oauth = creds?.claudeAiOauth;
|
|
31
|
+
if (oauth?.accessToken) {
|
|
32
|
+
return {
|
|
33
|
+
access: oauth.accessToken,
|
|
34
|
+
refresh: oauth.refreshToken,
|
|
35
|
+
expires: oauth.expiresAt
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type AnthropicProfileResponse, type AnthropicUsageResponse } from "./types.js";
|
|
2
|
+
export declare function fetchAnthropicUsage(token: string): Promise<AnthropicUsageResponse | null>;
|
|
3
|
+
export declare function fetchAnthropicProfile(token: string): Promise<AnthropicProfileResponse | null>;
|
|
4
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAA;AA4BnB,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAM/F;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAMnG"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { anthropicProfileResponseSchema, anthropicUsageResponseSchema, oauthUsageHeaders, } from "./types.js";
|
|
2
|
+
const USAGE_ENDPOINT = "https://api.anthropic.com/api/oauth/usage";
|
|
3
|
+
const PROFILE_ENDPOINT = "https://api.anthropic.com/api/oauth/profile";
|
|
4
|
+
const REQUEST_TIMEOUT_MS = 5000;
|
|
5
|
+
async function fetchOAuthJson(url, token) {
|
|
6
|
+
const controller = new AbortController();
|
|
7
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
8
|
+
try {
|
|
9
|
+
const response = await fetch(url, {
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${token}`,
|
|
12
|
+
...oauthUsageHeaders,
|
|
13
|
+
},
|
|
14
|
+
signal: controller.signal,
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok)
|
|
17
|
+
return null;
|
|
18
|
+
return await response.json().catch(() => null);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function fetchAnthropicUsage(token) {
|
|
28
|
+
const data = await fetchOAuthJson(USAGE_ENDPOINT, token);
|
|
29
|
+
if (!data)
|
|
30
|
+
return null;
|
|
31
|
+
const parsed = anthropicUsageResponseSchema.safeParse(data);
|
|
32
|
+
if (!parsed.success)
|
|
33
|
+
return null;
|
|
34
|
+
return parsed.data;
|
|
35
|
+
}
|
|
36
|
+
export async function fetchAnthropicProfile(token) {
|
|
37
|
+
const data = await fetchOAuthJson(PROFILE_ENDPOINT, token);
|
|
38
|
+
if (!data)
|
|
39
|
+
return null;
|
|
40
|
+
const parsed = anthropicProfileResponseSchema.safeParse(data);
|
|
41
|
+
if (!parsed.success)
|
|
42
|
+
return null;
|
|
43
|
+
return parsed.data;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAM/C,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,IAAI,CA4BjD,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { readAnthropicAuth } from "./auth.js";
|
|
2
|
+
import { fetchAnthropicProfile, fetchAnthropicUsage } from "./fetch.js";
|
|
3
|
+
import { buildAnthropicQuota, inferAnthropicPlanType } from "./parse.js";
|
|
4
|
+
export const AnthropicProvider = {
|
|
5
|
+
id: "anthropic",
|
|
6
|
+
displayName: "Anthropic Claude",
|
|
7
|
+
usageEndpoint: "https://api.anthropic.com/api/oauth/usage",
|
|
8
|
+
async fetchUsage() {
|
|
9
|
+
const auth = await readAnthropicAuth();
|
|
10
|
+
if (!auth?.access)
|
|
11
|
+
return null;
|
|
12
|
+
const [usage, profile] = await Promise.all([
|
|
13
|
+
fetchAnthropicUsage(auth.access),
|
|
14
|
+
fetchAnthropicProfile(auth.access),
|
|
15
|
+
]);
|
|
16
|
+
if (!usage)
|
|
17
|
+
return null;
|
|
18
|
+
return {
|
|
19
|
+
timestamp: Date.now(),
|
|
20
|
+
updatedAt: Date.now(),
|
|
21
|
+
provider: "anthropic",
|
|
22
|
+
planType: inferAnthropicPlanType(profile),
|
|
23
|
+
primary: null,
|
|
24
|
+
secondary: null,
|
|
25
|
+
codeReview: null,
|
|
26
|
+
credits: null,
|
|
27
|
+
anthropicQuota: buildAnthropicQuota(usage, profile),
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AnthropicQuota, PlanType } from "../../types.js";
|
|
2
|
+
import type { AnthropicProfileResponse, AnthropicUsageResponse } from "./types.js";
|
|
3
|
+
export declare function inferAnthropicPlanType(profile: AnthropicProfileResponse | null): PlanType | null;
|
|
4
|
+
export declare function buildAnthropicQuota(usage: AnthropicUsageResponse, profile: AnthropicProfileResponse | null): AnthropicQuota;
|
|
5
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,KAAK,EAAE,wBAAwB,EAAE,sBAAsB,EAAwB,MAAM,YAAY,CAAA;AAqDxG,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAehG;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,cAAc,CAyC3H"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const KNOWN_LIMIT_ORDER = [
|
|
2
|
+
"five_hour",
|
|
3
|
+
"seven_day",
|
|
4
|
+
"seven_day_oauth_apps",
|
|
5
|
+
"seven_day_sonnet",
|
|
6
|
+
"seven_day_opus",
|
|
7
|
+
"seven_day_cowork",
|
|
8
|
+
"iguana_necktie",
|
|
9
|
+
];
|
|
10
|
+
const LIMIT_LABELS = {
|
|
11
|
+
five_hour: "5-Hour",
|
|
12
|
+
seven_day: "7-Day (All)",
|
|
13
|
+
seven_day_oauth_apps: "7-Day (OAuth Apps)",
|
|
14
|
+
seven_day_sonnet: "7-Day (Sonnet)",
|
|
15
|
+
seven_day_opus: "7-Day (Opus)",
|
|
16
|
+
seven_day_cowork: "7-Day (Co-work)",
|
|
17
|
+
iguana_necktie: "Iguana Necktie",
|
|
18
|
+
};
|
|
19
|
+
function humanizeKey(key) {
|
|
20
|
+
return key
|
|
21
|
+
.split("_")
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
.map((token) => token[0]?.toUpperCase() + token.slice(1))
|
|
24
|
+
.join(" ");
|
|
25
|
+
}
|
|
26
|
+
function toPercent(value) {
|
|
27
|
+
if (typeof value !== "number" || Number.isNaN(value))
|
|
28
|
+
return 0;
|
|
29
|
+
return Math.max(0, Math.min(100, value));
|
|
30
|
+
}
|
|
31
|
+
function asString(value) {
|
|
32
|
+
if (value === null || value === undefined)
|
|
33
|
+
return null;
|
|
34
|
+
if (typeof value === "string")
|
|
35
|
+
return value;
|
|
36
|
+
if (typeof value === "number")
|
|
37
|
+
return String(value);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function isUsageWindow(value) {
|
|
41
|
+
if (!value || typeof value !== "object")
|
|
42
|
+
return false;
|
|
43
|
+
return "utilization" in value || "resets_at" in value;
|
|
44
|
+
}
|
|
45
|
+
function getOrderedLimitKeys(raw) {
|
|
46
|
+
const known = KNOWN_LIMIT_ORDER.filter((k) => k in raw);
|
|
47
|
+
const extras = Object.keys(raw).filter((k) => !KNOWN_LIMIT_ORDER.includes(k));
|
|
48
|
+
return [...known, ...extras];
|
|
49
|
+
}
|
|
50
|
+
export function inferAnthropicPlanType(profile) {
|
|
51
|
+
const account = profile?.account;
|
|
52
|
+
const organization = profile?.organization;
|
|
53
|
+
const orgType = (organization?.organization_type || "").toLowerCase();
|
|
54
|
+
const tier = (organization?.rate_limit_tier || "").toLowerCase();
|
|
55
|
+
if (tier.includes("max_20"))
|
|
56
|
+
return "max_20x";
|
|
57
|
+
if (tier.includes("max_5"))
|
|
58
|
+
return "max_5x";
|
|
59
|
+
if (orgType.includes("max"))
|
|
60
|
+
return "max";
|
|
61
|
+
if (orgType.includes("enterprise"))
|
|
62
|
+
return "enterprise";
|
|
63
|
+
if (orgType.includes("team"))
|
|
64
|
+
return "team";
|
|
65
|
+
if (orgType.includes("pro"))
|
|
66
|
+
return "pro";
|
|
67
|
+
if (account?.has_claude_max)
|
|
68
|
+
return "max";
|
|
69
|
+
if (account?.has_claude_pro)
|
|
70
|
+
return "pro";
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
export function buildAnthropicQuota(usage, profile) {
|
|
74
|
+
const raw = usage;
|
|
75
|
+
const limits = [];
|
|
76
|
+
for (const key of getOrderedLimitKeys(raw)) {
|
|
77
|
+
if (key === "extra_usage")
|
|
78
|
+
continue;
|
|
79
|
+
const candidate = raw[key];
|
|
80
|
+
if (!isUsageWindow(candidate))
|
|
81
|
+
continue;
|
|
82
|
+
const utilization = typeof candidate.utilization === "number" ? toPercent(candidate.utilization) : null;
|
|
83
|
+
const resetsAt = asString(candidate.resets_at);
|
|
84
|
+
if (utilization === null && resetsAt === null)
|
|
85
|
+
continue;
|
|
86
|
+
limits.push({
|
|
87
|
+
key,
|
|
88
|
+
label: LIMIT_LABELS[key] ?? humanizeKey(key),
|
|
89
|
+
utilization: utilization ?? 0,
|
|
90
|
+
resetsAt,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const extraRaw = usage.extra_usage;
|
|
94
|
+
return {
|
|
95
|
+
limits,
|
|
96
|
+
extraUsage: extraRaw
|
|
97
|
+
? {
|
|
98
|
+
isEnabled: extraRaw.is_enabled === true,
|
|
99
|
+
monthlyLimit: asString(extraRaw.monthly_limit),
|
|
100
|
+
usedCredits: asString(extraRaw.used_credits),
|
|
101
|
+
utilization: typeof extraRaw.utilization === "number" ? toPercent(extraRaw.utilization) : null,
|
|
102
|
+
}
|
|
103
|
+
: null,
|
|
104
|
+
subscription: {
|
|
105
|
+
organizationType: profile?.organization?.organization_type || null,
|
|
106
|
+
rateLimitTier: profile?.organization?.rate_limit_tier || null,
|
|
107
|
+
subscriptionStatus: profile?.organization?.subscription_status || null,
|
|
108
|
+
hasClaudeMax: profile?.account?.has_claude_max === true,
|
|
109
|
+
hasClaudePro: profile?.account?.has_claude_pro === true,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export interface AnthropicAuthData {
|
|
3
|
+
access: string;
|
|
4
|
+
refresh?: string;
|
|
5
|
+
expires?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const oauthUsageHeaders: {
|
|
8
|
+
readonly "anthropic-beta": "oauth-2025-04-20";
|
|
9
|
+
readonly "anthropic-dangerous-direct-browser-access": "true";
|
|
10
|
+
readonly "x-app": "cli";
|
|
11
|
+
readonly "user-agent": "claude-cli/2.1.2 (external, cli)";
|
|
12
|
+
};
|
|
13
|
+
declare const usageWindowSchema: z.ZodObject<{
|
|
14
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
15
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
16
|
+
}, z.core.$loose>;
|
|
17
|
+
export declare const anthropicUsageResponseSchema: z.ZodObject<{
|
|
18
|
+
five_hour: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
19
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
20
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
|
+
}, z.core.$loose>>>;
|
|
22
|
+
seven_day: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
23
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
24
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
|
+
}, z.core.$loose>>>;
|
|
26
|
+
seven_day_oauth_apps: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
27
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
28
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
29
|
+
}, z.core.$loose>>>;
|
|
30
|
+
seven_day_opus: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
31
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
32
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
33
|
+
}, z.core.$loose>>>;
|
|
34
|
+
seven_day_sonnet: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
35
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
36
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
37
|
+
}, z.core.$loose>>>;
|
|
38
|
+
seven_day_cowork: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
39
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
40
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
}, z.core.$loose>>>;
|
|
42
|
+
iguana_necktie: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
43
|
+
utilization: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
44
|
+
resets_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
45
|
+
}, z.core.$loose>>>;
|
|
46
|
+
extra_usage: z.ZodNullable<z.ZodOptional<z.ZodObject<{
|
|
47
|
+
is_enabled: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
|
|
48
|
+
monthly_limit: z.ZodNullable<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
|
|
49
|
+
used_credits: z.ZodNullable<z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
|
|
50
|
+
utilization: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
51
|
+
}, z.core.$loose>>>;
|
|
52
|
+
}, z.core.$loose>;
|
|
53
|
+
export declare const anthropicProfileResponseSchema: z.ZodObject<{
|
|
54
|
+
account: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
has_claude_max: z.ZodOptional<z.ZodBoolean>;
|
|
56
|
+
has_claude_pro: z.ZodOptional<z.ZodBoolean>;
|
|
57
|
+
}, z.core.$loose>>;
|
|
58
|
+
organization: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
organization_type: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
60
|
+
rate_limit_tier: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
61
|
+
subscription_status: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
62
|
+
}, z.core.$loose>>;
|
|
63
|
+
}, z.core.$loose>;
|
|
64
|
+
export type AnthropicUsageResponse = z.infer<typeof anthropicUsageResponseSchema>;
|
|
65
|
+
export type AnthropicProfileResponse = z.infer<typeof anthropicProfileResponseSchema>;
|
|
66
|
+
export type AnthropicUsageWindow = z.infer<typeof usageWindowSchema>;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAA;AAEnB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,iBAAiB;;;;;CAKpB,CAAA;AAEV,QAAA,MAAM,iBAAiB;;;iBAGP,CAAA;AAShB,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASzB,CAAA;AAEhB,eAAO,MAAM,8BAA8B;;;;;;;;;;iBAgB3B,CAAA;AAEhB,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAA;AACrF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export const oauthUsageHeaders = {
|
|
3
|
+
"anthropic-beta": "oauth-2025-04-20",
|
|
4
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
5
|
+
"x-app": "cli",
|
|
6
|
+
"user-agent": "claude-cli/2.1.2 (external, cli)",
|
|
7
|
+
};
|
|
8
|
+
const usageWindowSchema = z.object({
|
|
9
|
+
utilization: z.number().nullable().optional(),
|
|
10
|
+
resets_at: z.string().nullable().optional(),
|
|
11
|
+
}).passthrough();
|
|
12
|
+
const extraUsageSchema = z.object({
|
|
13
|
+
is_enabled: z.boolean().optional().nullable(),
|
|
14
|
+
monthly_limit: z.union([z.number(), z.string()]).optional().nullable(),
|
|
15
|
+
used_credits: z.union([z.number(), z.string()]).optional().nullable(),
|
|
16
|
+
utilization: z.number().optional().nullable(),
|
|
17
|
+
}).passthrough();
|
|
18
|
+
export const anthropicUsageResponseSchema = z.object({
|
|
19
|
+
five_hour: usageWindowSchema.optional().nullable(),
|
|
20
|
+
seven_day: usageWindowSchema.optional().nullable(),
|
|
21
|
+
seven_day_oauth_apps: usageWindowSchema.optional().nullable(),
|
|
22
|
+
seven_day_opus: usageWindowSchema.optional().nullable(),
|
|
23
|
+
seven_day_sonnet: usageWindowSchema.optional().nullable(),
|
|
24
|
+
seven_day_cowork: usageWindowSchema.optional().nullable(),
|
|
25
|
+
iguana_necktie: usageWindowSchema.optional().nullable(),
|
|
26
|
+
extra_usage: extraUsageSchema.optional().nullable(),
|
|
27
|
+
}).passthrough();
|
|
28
|
+
export const anthropicProfileResponseSchema = z.object({
|
|
29
|
+
account: z
|
|
30
|
+
.object({
|
|
31
|
+
has_claude_max: z.boolean().optional(),
|
|
32
|
+
has_claude_pro: z.boolean().optional(),
|
|
33
|
+
})
|
|
34
|
+
.passthrough()
|
|
35
|
+
.optional(),
|
|
36
|
+
organization: z
|
|
37
|
+
.object({
|
|
38
|
+
organization_type: z.string().optional().nullable(),
|
|
39
|
+
rate_limit_tier: z.string().optional().nullable(),
|
|
40
|
+
subscription_status: z.string().optional().nullable(),
|
|
41
|
+
})
|
|
42
|
+
.passthrough()
|
|
43
|
+
.optional(),
|
|
44
|
+
}).passthrough();
|
|
@@ -4,5 +4,7 @@ export { CodexProvider } from "./codex";
|
|
|
4
4
|
export { ProxyProvider } from "./proxy";
|
|
5
5
|
export { CopilotProvider } from "./copilot";
|
|
6
6
|
export { ZaiProvider } from "./zai";
|
|
7
|
+
export { OpenRouterProvider } from "./openrouter";
|
|
8
|
+
export { AnthropicProvider } from "./anthropic";
|
|
7
9
|
export type { UsageProvider } from "./base";
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AAQ3C,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAO5D,CAAA;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA"}
|
package/dist/providers/index.js
CHANGED
|
@@ -2,13 +2,19 @@ import { CodexProvider } from "./codex";
|
|
|
2
2
|
import { ProxyProvider } from "./proxy";
|
|
3
3
|
import { CopilotProvider } from "./copilot";
|
|
4
4
|
import { ZaiProvider } from "./zai";
|
|
5
|
+
import { OpenRouterProvider } from "./openrouter";
|
|
6
|
+
import { AnthropicProvider } from "./anthropic";
|
|
5
7
|
export const providers = {
|
|
6
8
|
[CodexProvider.id]: CodexProvider,
|
|
7
9
|
[ProxyProvider.id]: ProxyProvider,
|
|
8
10
|
[CopilotProvider.id]: CopilotProvider,
|
|
9
11
|
[ZaiProvider.id]: ZaiProvider,
|
|
12
|
+
[OpenRouterProvider.id]: OpenRouterProvider,
|
|
13
|
+
[AnthropicProvider.id]: AnthropicProvider,
|
|
10
14
|
};
|
|
11
15
|
export { CodexProvider } from "./codex";
|
|
12
16
|
export { ProxyProvider } from "./proxy";
|
|
13
17
|
export { CopilotProvider } from "./copilot";
|
|
14
18
|
export { ZaiProvider } from "./zai";
|
|
19
|
+
export { OpenRouterProvider } from "./openrouter";
|
|
20
|
+
export { AnthropicProvider } from "./anthropic";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch logic for OpenRouter usage monitoring.
|
|
3
|
+
*/
|
|
4
|
+
import { type OpenRouterAuth, type OpenRouterAuthResponse } from "./types";
|
|
5
|
+
export declare function fetchOpenRouterUsage(auth: OpenRouterAuth): Promise<OpenRouterAuthResponse>;
|
|
6
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,SAAS,CAAA;AAEhB,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAsChG"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch logic for OpenRouter usage monitoring.
|
|
3
|
+
*/
|
|
4
|
+
import { openRouterAuthResponseSchema, } from "./types";
|
|
5
|
+
export async function fetchOpenRouterUsage(auth) {
|
|
6
|
+
const urls = [
|
|
7
|
+
"https://openrouter.ai/api/v1/key",
|
|
8
|
+
"https://openrouter.ai/api/v1/auth/key",
|
|
9
|
+
];
|
|
10
|
+
let lastError = "Unknown OpenRouter API error";
|
|
11
|
+
for (const url of urls) {
|
|
12
|
+
const response = await fetch(url, {
|
|
13
|
+
headers: {
|
|
14
|
+
"Authorization": `Bearer ${auth.key}`,
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
},
|
|
17
|
+
}).catch(() => null);
|
|
18
|
+
if (!response) {
|
|
19
|
+
lastError = `OpenRouter API failed: network error for ${url}`;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
lastError = `OpenRouter API failed: ${response.status} ${await response.text()}`;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const data = await response.json().catch(() => null);
|
|
27
|
+
if (!data) {
|
|
28
|
+
lastError = "Invalid OpenRouter response: empty JSON body";
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const parsed = openRouterAuthResponseSchema.safeParse(data);
|
|
32
|
+
if (!parsed.success) {
|
|
33
|
+
lastError = "Invalid OpenRouter response structure";
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
return parsed.data;
|
|
37
|
+
}
|
|
38
|
+
throw new Error(lastError);
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* providers/openrouter/index.ts
|
|
3
|
+
* Main entry point for the OpenRouter usage provider.
|
|
4
|
+
*/
|
|
5
|
+
import type { UsageProvider } from "../base";
|
|
6
|
+
import type { OpenRouterAuth } from "./types";
|
|
7
|
+
export declare const OpenRouterProvider: UsageProvider<OpenRouterAuth>;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA0B,MAAM,SAAS,CAAA;AAerE,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC,cAAc,CAsC5D,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* providers/openrouter/index.ts
|
|
3
|
+
* Main entry point for the OpenRouter usage provider.
|
|
4
|
+
*/
|
|
5
|
+
import { fetchOpenRouterUsage } from "./fetch";
|
|
6
|
+
function toRateLimitWindow(data) {
|
|
7
|
+
const limit = data.data.limit;
|
|
8
|
+
const usage = data.data.usage;
|
|
9
|
+
if (limit === null || limit <= 0)
|
|
10
|
+
return null;
|
|
11
|
+
return {
|
|
12
|
+
usedPercent: (usage / limit) * 100,
|
|
13
|
+
windowMinutes: null,
|
|
14
|
+
resetsAt: data.data.limit_reset ? new Date(data.data.limit_reset).getTime() : null,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export const OpenRouterProvider = {
|
|
18
|
+
id: "openrouter",
|
|
19
|
+
displayName: "OpenRouter",
|
|
20
|
+
async fetchUsage(auth) {
|
|
21
|
+
try {
|
|
22
|
+
if (!auth?.key)
|
|
23
|
+
return null;
|
|
24
|
+
const data = await fetchOpenRouterUsage(auth);
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
return {
|
|
27
|
+
timestamp: now,
|
|
28
|
+
provider: "openrouter",
|
|
29
|
+
planType: data.data.is_free_tier ? "free" : "plus",
|
|
30
|
+
primary: toRateLimitWindow(data),
|
|
31
|
+
secondary: null,
|
|
32
|
+
codeReview: null,
|
|
33
|
+
credits: {
|
|
34
|
+
hasCredits: true,
|
|
35
|
+
unlimited: data.data.limit === null,
|
|
36
|
+
balance: data.data.limit_remaining === null ? "Unlimited" : `$${data.data.limit_remaining.toFixed(2)}`,
|
|
37
|
+
},
|
|
38
|
+
updatedAt: now,
|
|
39
|
+
openrouterQuota: {
|
|
40
|
+
limit: data.data.limit,
|
|
41
|
+
usage: data.data.usage,
|
|
42
|
+
limitRemaining: data.data.limit_remaining,
|
|
43
|
+
usageDaily: data.data.usage_daily,
|
|
44
|
+
usageWeekly: data.data.usage_weekly,
|
|
45
|
+
usageMonthly: data.data.usage_monthly,
|
|
46
|
+
isFreeTier: data.data.is_free_tier,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
void error;
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the OpenRouter provider.
|
|
3
|
+
*/
|
|
4
|
+
import z from "zod";
|
|
5
|
+
export interface OpenRouterAuth {
|
|
6
|
+
key: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const openRouterAuthResponseSchema: z.ZodObject<{
|
|
9
|
+
data: z.ZodObject<{
|
|
10
|
+
label: z.ZodOptional<z.ZodString>;
|
|
11
|
+
is_management_key: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
is_provisioning_key: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
limit: z.ZodNullable<z.ZodNumber>;
|
|
14
|
+
limit_reset: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15
|
+
limit_remaining: z.ZodNullable<z.ZodNumber>;
|
|
16
|
+
include_byok_in_limit: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
usage: z.ZodNumber;
|
|
18
|
+
usage_daily: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
19
|
+
usage_weekly: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
20
|
+
usage_monthly: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
21
|
+
byok_usage: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
byok_usage_daily: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
byok_usage_weekly: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
byok_usage_monthly: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
is_free_tier: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
26
|
+
expires_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
|
+
rate_limit: z.ZodOptional<z.ZodObject<{
|
|
28
|
+
requests: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
interval: z.ZodOptional<z.ZodString>;
|
|
30
|
+
note: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export type OpenRouterAuthResponse = z.infer<typeof openRouterAuthResponseSchema>;
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/openrouter/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,CAAC,MAAM,KAAK,CAAA;AAEnB,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;iBA2BvC,CAAA;AAEF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the OpenRouter provider.
|
|
3
|
+
*/
|
|
4
|
+
import z from "zod";
|
|
5
|
+
export const openRouterAuthResponseSchema = z.object({
|
|
6
|
+
data: z.object({
|
|
7
|
+
label: z.string().optional(),
|
|
8
|
+
is_management_key: z.boolean().optional(),
|
|
9
|
+
is_provisioning_key: z.boolean().optional(),
|
|
10
|
+
limit: z.number().nullable(),
|
|
11
|
+
limit_reset: z.string().nullable().optional(),
|
|
12
|
+
limit_remaining: z.number().nullable(),
|
|
13
|
+
include_byok_in_limit: z.boolean().optional(),
|
|
14
|
+
usage: z.number(),
|
|
15
|
+
usage_daily: z.number().optional().default(0),
|
|
16
|
+
usage_weekly: z.number().optional().default(0),
|
|
17
|
+
usage_monthly: z.number().optional().default(0),
|
|
18
|
+
byok_usage: z.number().optional(),
|
|
19
|
+
byok_usage_daily: z.number().optional(),
|
|
20
|
+
byok_usage_weekly: z.number().optional(),
|
|
21
|
+
byok_usage_monthly: z.number().optional(),
|
|
22
|
+
is_free_tier: z.boolean().optional().default(false),
|
|
23
|
+
expires_at: z.string().nullable().optional(),
|
|
24
|
+
rate_limit: z
|
|
25
|
+
.object({
|
|
26
|
+
requests: z.number().optional(),
|
|
27
|
+
interval: z.string().optional(),
|
|
28
|
+
note: z.string().optional(),
|
|
29
|
+
})
|
|
30
|
+
.optional(),
|
|
31
|
+
}),
|
|
32
|
+
});
|
package/dist/state.d.ts
CHANGED
package/dist/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,kBAAkB,EAAE;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,KAAK,EAAE,OAAO,CAAA;QACd,OAAO,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,kBAAkB,EAAE;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,KAAK,EAAE,OAAO,CAAA;QACd,OAAO,EAAE,OAAO,CAAA;QAChB,SAAS,EAAE,OAAO,CAAA;KACnB,CAAA;CACF,CAAA;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAU7C"}
|
package/dist/state.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core type definitions for the Usage Tracking Plugin.
|
|
3
3
|
*/
|
|
4
|
-
export declare const PlanTypes: readonly ["guest", "free", "go", "plus", "pro", "free_workspace", "team", "business", "education", "quorum", "k12", "enterprise", "edu"];
|
|
4
|
+
export declare const PlanTypes: readonly ["guest", "free", "go", "plus", "pro", "max", "max_5x", "max_20x", "free_workspace", "team", "business", "education", "quorum", "k12", "enterprise", "edu"];
|
|
5
5
|
export type PlanType = (typeof PlanTypes)[number];
|
|
6
6
|
export interface RateLimitWindow {
|
|
7
7
|
usedPercent: number;
|
|
@@ -52,6 +52,8 @@ export interface UsageConfig {
|
|
|
52
52
|
proxy?: boolean;
|
|
53
53
|
copilot?: boolean;
|
|
54
54
|
zai?: boolean;
|
|
55
|
+
openrouter?: boolean;
|
|
56
|
+
anthropic?: boolean;
|
|
55
57
|
};
|
|
56
58
|
modelGroups?: {
|
|
57
59
|
showAll?: boolean;
|
|
@@ -81,6 +83,36 @@ export interface ZaiQuota {
|
|
|
81
83
|
totalZreadMcpCount: number;
|
|
82
84
|
};
|
|
83
85
|
}
|
|
86
|
+
export interface AnthropicQuota {
|
|
87
|
+
limits: Array<{
|
|
88
|
+
key: string;
|
|
89
|
+
label: string;
|
|
90
|
+
utilization: number;
|
|
91
|
+
resetsAt: string | null;
|
|
92
|
+
}>;
|
|
93
|
+
extraUsage: {
|
|
94
|
+
isEnabled: boolean;
|
|
95
|
+
monthlyLimit: string | null;
|
|
96
|
+
usedCredits: string | null;
|
|
97
|
+
utilization: number | null;
|
|
98
|
+
} | null;
|
|
99
|
+
subscription: {
|
|
100
|
+
organizationType: string | null;
|
|
101
|
+
rateLimitTier: string | null;
|
|
102
|
+
subscriptionStatus: string | null;
|
|
103
|
+
hasClaudeMax: boolean;
|
|
104
|
+
hasClaudePro: boolean;
|
|
105
|
+
} | null;
|
|
106
|
+
}
|
|
107
|
+
export interface OpenRouterQuota {
|
|
108
|
+
limit: number | null;
|
|
109
|
+
usage: number;
|
|
110
|
+
limitRemaining: number | null;
|
|
111
|
+
usageDaily: number;
|
|
112
|
+
usageWeekly: number;
|
|
113
|
+
usageMonthly: number;
|
|
114
|
+
isFreeTier: boolean;
|
|
115
|
+
}
|
|
84
116
|
export interface UsageSnapshot {
|
|
85
117
|
timestamp: number;
|
|
86
118
|
provider: string;
|
|
@@ -92,6 +124,8 @@ export interface UsageSnapshot {
|
|
|
92
124
|
proxyQuota?: ProxyQuota;
|
|
93
125
|
copilotQuota?: CopilotQuota;
|
|
94
126
|
zaiQuota?: ZaiQuota;
|
|
127
|
+
openrouterQuota?: OpenRouterQuota;
|
|
128
|
+
anthropicQuota?: AnthropicQuota;
|
|
95
129
|
updatedAt: number;
|
|
96
130
|
isMissing?: boolean;
|
|
97
131
|
missingReason?: string;
|
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,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAwDhD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CA0BzE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { formatBar, formatMissingSnapshot, formatResetSuffixISO } from "./shared";
|
|
2
|
+
function toTitleCase(value) {
|
|
3
|
+
return value.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
4
|
+
}
|
|
5
|
+
function formatTierLabel(tier) {
|
|
6
|
+
if (!tier)
|
|
7
|
+
return null;
|
|
8
|
+
const known = {
|
|
9
|
+
default_claude_ai: "Claude Pro",
|
|
10
|
+
default_claude_max_5x: "Claude Max 5x",
|
|
11
|
+
default_claude_max_20x: "Claude Max 20x",
|
|
12
|
+
};
|
|
13
|
+
if (known[tier])
|
|
14
|
+
return known[tier];
|
|
15
|
+
if (tier.startsWith("default_claude_")) {
|
|
16
|
+
return toTitleCase(tier.replace(/^default_claude_/, "Claude "));
|
|
17
|
+
}
|
|
18
|
+
return toTitleCase(tier);
|
|
19
|
+
}
|
|
20
|
+
function formatExtraUsage(extra) {
|
|
21
|
+
if (!extra?.isEnabled)
|
|
22
|
+
return [];
|
|
23
|
+
const lines = [
|
|
24
|
+
` Extra Usage: ${extra.utilization !== null ? `${extra.utilization.toFixed(0)}% used` : "enabled"}`,
|
|
25
|
+
];
|
|
26
|
+
if (extra.usedCredits || extra.monthlyLimit) {
|
|
27
|
+
lines.push(` Credits: ${extra.usedCredits ?? "-"} / ${extra.monthlyLimit ?? "-"}`);
|
|
28
|
+
}
|
|
29
|
+
return lines;
|
|
30
|
+
}
|
|
31
|
+
function shouldShowTier(planType, tierLabel) {
|
|
32
|
+
if (!tierLabel)
|
|
33
|
+
return false;
|
|
34
|
+
if (!planType)
|
|
35
|
+
return true;
|
|
36
|
+
const plan = planType.toLowerCase();
|
|
37
|
+
const tier = tierLabel.toLowerCase();
|
|
38
|
+
if (plan === "pro" && tier.includes("pro"))
|
|
39
|
+
return false;
|
|
40
|
+
if (plan === "max" && tier.includes("max"))
|
|
41
|
+
return false;
|
|
42
|
+
if (plan === "max_5x" && tier.includes("max") && tier.includes("5x"))
|
|
43
|
+
return false;
|
|
44
|
+
if (plan === "max_20x" && tier.includes("max") && tier.includes("20x"))
|
|
45
|
+
return false;
|
|
46
|
+
if (plan === "team" && tier.includes("team"))
|
|
47
|
+
return false;
|
|
48
|
+
if (plan === "enterprise" && tier.includes("enterprise"))
|
|
49
|
+
return false;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
export function formatAnthropicSnapshot(snapshot) {
|
|
53
|
+
const quota = snapshot.anthropicQuota;
|
|
54
|
+
if (!quota)
|
|
55
|
+
return formatMissingSnapshot(snapshot);
|
|
56
|
+
const plan = snapshot.planType ? ` (${toTitleCase(snapshot.planType)})` : "";
|
|
57
|
+
const lines = [`→ [ANTHROPIC]${plan}`];
|
|
58
|
+
const tierLabel = formatTierLabel(quota.subscription?.rateLimitTier);
|
|
59
|
+
if (shouldShowTier(snapshot.planType, tierLabel)) {
|
|
60
|
+
lines.push(` Tier: ${tierLabel}`);
|
|
61
|
+
}
|
|
62
|
+
for (const limit of quota.limits) {
|
|
63
|
+
const leftPercent = Math.max(0, Math.min(100, 100 - limit.utilization));
|
|
64
|
+
lines.push(` ${`${limit.label}:`.padEnd(14)} ${formatBar(leftPercent)} ${leftPercent.toFixed(0)}% left${limit.resetsAt ? formatResetSuffixISO(limit.resetsAt) : ""}`);
|
|
65
|
+
}
|
|
66
|
+
lines.push(...formatExtraUsage(quota.extraUsage));
|
|
67
|
+
if (quota.limits.length === 0 && !quota.extraUsage?.isEnabled) {
|
|
68
|
+
return formatMissingSnapshot(snapshot);
|
|
69
|
+
}
|
|
70
|
+
return lines;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/openrouter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAoB1E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats OpenRouter usage snapshots.
|
|
3
|
+
*/
|
|
4
|
+
import { formatBar, formatMissingSnapshot, formatResetSuffix } from "./shared";
|
|
5
|
+
export function formatOpenRouterSnapshot(snapshot) {
|
|
6
|
+
const or = snapshot.openrouterQuota;
|
|
7
|
+
if (!or)
|
|
8
|
+
return formatMissingSnapshot(snapshot);
|
|
9
|
+
const lines = ["→ [OPENROUTER]"];
|
|
10
|
+
if (or.limit === null) {
|
|
11
|
+
lines.push(` ${"Credit:".padEnd(13)} Unlimited`);
|
|
12
|
+
lines.push(` ${"Used:".padEnd(13)} $${or.usage.toFixed(2)}`);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
const remainingPct = snapshot.primary ? 100 - snapshot.primary.usedPercent : 100;
|
|
16
|
+
const resetSuffix = snapshot.primary ? formatResetSuffix(snapshot.primary.resetsAt) : "";
|
|
17
|
+
lines.push(` ${"Credit:".padEnd(13)} ${formatBar(remainingPct)} ${remainingPct.toFixed(0)}% left`);
|
|
18
|
+
const remaining = or.limitRemaining === null ? "Unlimited" : `$${or.limitRemaining.toFixed(2)}`;
|
|
19
|
+
lines.push(` ${"Used:".padEnd(13)} $${or.usage.toFixed(2)} / $${or.limit.toFixed(2)}`);
|
|
20
|
+
lines.push(` ${"Remaining:".padEnd(13)} ${remaining}${resetSuffix}`);
|
|
21
|
+
}
|
|
22
|
+
return lines;
|
|
23
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD;AAwBD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAIhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMxD;AAwBD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAkBvE"}
|
|
@@ -50,7 +50,9 @@ export function formatMissingSnapshot(snapshot) {
|
|
|
50
50
|
const instructions = {
|
|
51
51
|
codex: "if you dont have codex oauth, please set your usage-config.jsonc to openai: false",
|
|
52
52
|
proxy: "check your usage-config.jsonc. Default: endpoint http://localhost:8000, apiKey VerysecretKey. If you changed these during proxy setup, update your config to match. Or set proxy: false to disable.",
|
|
53
|
-
copilot: "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false"
|
|
53
|
+
copilot: "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false",
|
|
54
|
+
anthropic: "if you are not using Claude Code with a subscription, please set your usage-config.jsonc to anthropic: false",
|
|
55
|
+
openrouter: "if you are not using OpenRouter API keys, please set your usage-config.jsonc to openrouter: false",
|
|
54
56
|
};
|
|
55
57
|
const lines = [`→ [${provider.toUpperCase()}] - ${instructions[provider] || ""}`];
|
|
56
58
|
if (snapshot.missingReason)
|
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;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAQ1C,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,CAmBhB;AAqCD,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,CAahB"}
|
package/dist/ui/status.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { formatProxySnapshot } from "./formatters/proxy";
|
|
6
6
|
import { formatCopilotSnapshot } from "./formatters/copilot";
|
|
7
7
|
import { formatZaiSnapshot } from "./formatters/zai";
|
|
8
|
+
import { formatOpenRouterSnapshot } from "./formatters/openrouter";
|
|
9
|
+
import { formatAnthropicSnapshot } from "./formatters/anthropic";
|
|
8
10
|
import { formatBar, formatResetSuffix, formatMissingSnapshot } from "./formatters/shared";
|
|
9
11
|
export async function sendStatusMessage(options) {
|
|
10
12
|
const bus = options.client.bus;
|
|
@@ -35,6 +37,12 @@ function formatSnapshot(snapshot) {
|
|
|
35
37
|
return formatCopilotSnapshot(snapshot);
|
|
36
38
|
if (snapshot.provider === "zai-coding-plan")
|
|
37
39
|
return formatZaiSnapshot(snapshot);
|
|
40
|
+
if (snapshot.provider === "openrouter")
|
|
41
|
+
return formatOpenRouterSnapshot(snapshot);
|
|
42
|
+
if (snapshot.provider === "anthropic")
|
|
43
|
+
return formatAnthropicSnapshot(snapshot);
|
|
44
|
+
if (snapshot.provider === "openrouter")
|
|
45
|
+
return formatOpenRouterSnapshot(snapshot);
|
|
38
46
|
const plan = snapshot.planType ? ` (${snapshot.planType.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase())})` : "";
|
|
39
47
|
const lines = [`→ [${snapshot.provider.toUpperCase()}]${plan}`];
|
|
40
48
|
const metrics = [
|
|
@@ -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;AAiB3C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,
|
|
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,CA8D5D"}
|
package/dist/usage/config.js
CHANGED
|
@@ -37,7 +37,9 @@ export async function loadUsageConfig() {
|
|
|
37
37
|
"openai": true,
|
|
38
38
|
"proxy": true,
|
|
39
39
|
"copilot": true,
|
|
40
|
-
"zai": true
|
|
40
|
+
"zai": true,
|
|
41
|
+
"anthropic": true,
|
|
42
|
+
"openrouter": true
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
`;
|
|
@@ -51,6 +53,8 @@ export async function loadUsageConfig() {
|
|
|
51
53
|
proxy: true,
|
|
52
54
|
copilot: true,
|
|
53
55
|
zai: true,
|
|
56
|
+
anthropic: true,
|
|
57
|
+
openrouter: true,
|
|
54
58
|
},
|
|
55
59
|
};
|
|
56
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../src/usage/fetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAQ7C,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;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAQ7C,wBAAsB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CA6CnF;AAcD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzE;AA8BD,wBAAsB,SAAS,gDAG9B"}
|
package/dist/usage/fetch.js
CHANGED
|
@@ -6,7 +6,7 @@ import { providers } from "../providers";
|
|
|
6
6
|
import { loadUsageConfig } from "./config";
|
|
7
7
|
import { loadMergedAuths } from "./auth/loader";
|
|
8
8
|
import { resolveProviderAuths } from "./registry";
|
|
9
|
-
const CORE_PROVIDERS = ["codex", "proxy", "copilot", "zai-coding-plan"];
|
|
9
|
+
const CORE_PROVIDERS = ["codex", "proxy", "copilot", "zai-coding-plan", "anthropic", "openrouter"];
|
|
10
10
|
export async function fetchUsageSnapshots(filter) {
|
|
11
11
|
const target = resolveFilter(filter);
|
|
12
12
|
const config = await loadUsageConfig().catch(() => null);
|
|
@@ -16,6 +16,8 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
16
16
|
return toggles.openai !== false;
|
|
17
17
|
if (id === "zai-coding-plan")
|
|
18
18
|
return toggles.zai !== false;
|
|
19
|
+
if (id === "openrouter")
|
|
20
|
+
return toggles.openrouter !== false;
|
|
19
21
|
return toggles[id] !== false;
|
|
20
22
|
};
|
|
21
23
|
const { auths, codexDiagnostics } = await loadMergedAuths();
|
|
@@ -32,7 +34,7 @@ export async function fetchUsageSnapshots(filter) {
|
|
|
32
34
|
}
|
|
33
35
|
});
|
|
34
36
|
// Handle special/default fetches
|
|
35
|
-
for (const id of ["proxy", "copilot"]) {
|
|
37
|
+
for (const id of ["proxy", "copilot", "anthropic"]) {
|
|
36
38
|
if ((!target || target === id) && isEnabled(id) && !fetched.has(id)) {
|
|
37
39
|
const provider = providers[id];
|
|
38
40
|
if (provider?.fetchUsage) {
|
|
@@ -54,7 +56,9 @@ function resolveFilter(f) {
|
|
|
54
56
|
codex: "codex", openai: "codex", gpt: "codex",
|
|
55
57
|
proxy: "proxy", agy: "proxy", gemini: "proxy",
|
|
56
58
|
copilot: "copilot", github: "copilot",
|
|
57
|
-
zai: "zai-coding-plan", glm: "zai-coding-plan"
|
|
59
|
+
zai: "zai-coding-plan", glm: "zai-coding-plan",
|
|
60
|
+
anthropic: "anthropic", claude: "anthropic",
|
|
61
|
+
openrouter: "openrouter", or: "openrouter",
|
|
58
62
|
};
|
|
59
63
|
return f ? aliases[f.toLowerCase().trim()] : undefined;
|
|
60
64
|
}
|
package/dist/usage/registry.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type { CodexAuth } from "../providers/codex";
|
|
5
5
|
import type { CopilotAuthData } from "../providers/copilot/types";
|
|
6
6
|
import type { ZaiAuth } from "../providers/zai/types";
|
|
7
|
+
import type { OpenRouterAuth } from "../providers/openrouter/types";
|
|
7
8
|
export type AuthEntry = {
|
|
8
9
|
type?: string;
|
|
9
10
|
access?: string;
|
|
@@ -22,6 +23,9 @@ type ProviderAuthEntry = {
|
|
|
22
23
|
} | {
|
|
23
24
|
providerID: "zai-coding-plan";
|
|
24
25
|
auth: ZaiAuth;
|
|
26
|
+
} | {
|
|
27
|
+
providerID: "openrouter";
|
|
28
|
+
auth: OpenRouterAuth;
|
|
25
29
|
};
|
|
26
30
|
export declare function resolveProviderAuths(auths: AuthRecord, usageToken: string | null): ProviderAuthEntry[];
|
|
27
31
|
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;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,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;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEnE,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,GAChD;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAChD;IAAE,UAAU,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,CAAA;AA8CtD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,EAAE,CActG"}
|
package/dist/usage/registry.js
CHANGED
|
@@ -28,6 +28,14 @@ const providerDescriptors = [
|
|
|
28
28
|
key: entry.key || entry.access || "",
|
|
29
29
|
}),
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
id: "openrouter",
|
|
33
|
+
authKeys: ["openrouter", "or"],
|
|
34
|
+
requiresOAuth: false,
|
|
35
|
+
buildAuth: (entry) => ({
|
|
36
|
+
key: entry.key || entry.access || "",
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
31
39
|
];
|
|
32
40
|
export function resolveProviderAuths(auths, usageToken) {
|
|
33
41
|
const entries = [];
|