@howaboua/opencode-usage-plugin 0.1.4 → 0.1.5

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.
Files changed (39) hide show
  1. package/README.md +83 -30
  2. package/dist/providers/index.d.ts +1 -0
  3. package/dist/providers/index.d.ts.map +1 -1
  4. package/dist/providers/index.js +3 -0
  5. package/dist/providers/proxy/fetch.js +2 -2
  6. package/dist/providers/proxy/format.d.ts +2 -1
  7. package/dist/providers/proxy/format.d.ts.map +1 -1
  8. package/dist/providers/proxy/format.js +11 -21
  9. package/dist/providers/proxy/index.d.ts +6 -0
  10. package/dist/providers/proxy/index.d.ts.map +1 -1
  11. package/dist/providers/proxy/index.js +54 -22
  12. package/dist/providers/proxy/types.d.ts +1 -0
  13. package/dist/providers/proxy/types.d.ts.map +1 -1
  14. package/dist/providers/zai/fetch.d.ts +32 -0
  15. package/dist/providers/zai/fetch.d.ts.map +1 -0
  16. package/dist/providers/zai/fetch.js +40 -0
  17. package/dist/providers/zai/index.d.ts +7 -0
  18. package/dist/providers/zai/index.d.ts.map +1 -0
  19. package/dist/providers/zai/index.js +39 -0
  20. package/dist/providers/zai/types.d.ts +61 -0
  21. package/dist/providers/zai/types.d.ts.map +1 -0
  22. package/dist/providers/zai/types.js +4 -0
  23. package/dist/types.d.ts +30 -0
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/ui/formatters/shared.d.ts.map +1 -1
  26. package/dist/ui/formatters/shared.js +4 -3
  27. package/dist/ui/formatters/zai.d.ts +6 -0
  28. package/dist/ui/formatters/zai.d.ts.map +1 -0
  29. package/dist/ui/formatters/zai.js +29 -0
  30. package/dist/ui/status.d.ts.map +1 -1
  31. package/dist/ui/status.js +3 -0
  32. package/dist/usage/config.d.ts.map +1 -1
  33. package/dist/usage/config.js +17 -3
  34. package/dist/usage/fetch.d.ts.map +1 -1
  35. package/dist/usage/fetch.js +5 -2
  36. package/dist/usage/registry.d.ts +4 -0
  37. package/dist/usage/registry.d.ts.map +1 -1
  38. package/dist/usage/registry.js +8 -0
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -25,6 +25,75 @@ Add to your `opencode.json`:
25
25
 
26
26
  OpenCode installs dependencies automatically on next launch.
27
27
 
28
+ ## Configuration
29
+
30
+ The plugin creates a default config file on first run at:
31
+
32
+ **Linux/macOS**: `~/.config/opencode/usage-config.jsonc`
33
+ **Windows**: `%APPDATA%\opencode\usage-config.jsonc`
34
+
35
+ ```jsonc
36
+ {
37
+ // REQUIRED: Proxy server endpoint (default: "http://localhost:8000")
38
+ // Leave empty ONLY if you don't use the proxy
39
+ "endpoint": "http://localhost:8000",
40
+
41
+ // REQUIRED: API key for proxy auth (default: "VerysecretKey")
42
+ // Leave empty if your proxy doesn't require authentication
43
+ "apiKey": "VerysecretKey",
44
+
45
+ // Optional: Request timeout in milliseconds (default: 10000)
46
+ "timeout": 10000,
47
+
48
+ // Optional: Show/hide providers in /usage output
49
+ "providers": {
50
+ "openai": true,
51
+ "proxy": true,
52
+ "copilot": true
53
+ },
54
+
55
+ // Model group display configuration (optional)
56
+ "modelGroups": {
57
+ // Show all model groups from proxy (default: true)
58
+ // When true: auto-discovers all groups, uses displayNames as overrides
59
+ // When false: only shows groups listed in displayNames (whitelist mode)
60
+ "showAll": true,
61
+
62
+ // Override display names for specific groups (optional)
63
+ // Groups not listed here use their original name from the proxy
64
+ "displayNames": {
65
+ "g3-pro": "Gemini Pro",
66
+ "g3-flash": "Gemini Flash",
67
+ "claude": "Claude"
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ > **⚠️ Important**: If using the Mirrowel Proxy, both `endpoint` and `apiKey` must be set. The proxy defaults to `endpoint: http://localhost:8000` and `apiKey: VerysecretKey`. If you changed these during your proxy setup, you MUST update your config file to match.
74
+
75
+ ### Model Group Configuration
76
+
77
+ The `modelGroups` section controls how quota groups are displayed:
78
+
79
+ | `showAll` | `displayNames` | Behavior |
80
+ |-----------|----------------|----------|
81
+ | `true` (default) | empty/missing | Show all groups with original names |
82
+ | `true` | provided | Show all groups, apply display name overrides |
83
+ | `false` | provided | Only show groups in displayNames (whitelist mode) |
84
+ | `false` | empty/missing | Shows no groups (all filtered out) |
85
+ | missing section | — | Legacy behavior (hardcoded group whitelist) |
86
+
87
+ If missing, the plugin creates a default template on first run.
88
+
89
+ ### Copilot auth
90
+
91
+ Copilot is detected from either of these locations:
92
+
93
+ - `~/.local/share/opencode/copilot-usage-token.json`
94
+ - `~/.local/share/opencode/auth.json` with a `github-copilot` entry
95
+ - `~/.config/opencode/copilot-quota-token.json` (optional override)
96
+
28
97
  ## Usage
29
98
 
30
99
  ### Check all providers
@@ -55,38 +124,22 @@ OpenCode installs dependencies automatically on next launch.
55
124
  | **Mirrowel Proxy** | Local `/v1/quota-stats` endpoint |
56
125
  | **GitHub Copilot** | GitHub internal usage APIs |
57
126
 
58
- ## Configuration
59
-
60
- Optional config at `~/.config/opencode/usage-config.jsonc`:
61
-
62
- ```jsonc
63
- {
64
- // Proxy server endpoint
65
- "endpoint": "http://localhost:8000",
66
-
67
- // API key for proxy auth
68
- "apiKey": "your-key",
69
-
70
- // Request timeout (ms)
71
- "timeout": 10000,
72
-
73
- // Show/hide providers in /usage output
74
- "providers": {
75
- "openai": true,
76
- "proxy": true,
77
- "copilot": true
78
- }
79
- }
80
- ```
127
+ ## Troubleshooting
81
128
 
82
- If missing, the plugin creates a default template on first run.
83
-
84
- ### Copilot auth
129
+ **Proxy shows "not configured" error**
130
+ - Ensure `endpoint` and `apiKey` are set in `usage-config.jsonc`
131
+ - Default values: `endpoint: http://localhost:8000`, `apiKey: VerysecretKey`
132
+ - If you changed these during proxy setup, update your config file to match
133
+ - Verify your proxy is running at the specified endpoint
85
134
 
86
- Copilot is detected from either of these locations:
135
+ **Missing provider data**
136
+ - Use `providers: { ... }` in config to disable unused providers
137
+ - For Codex: Ensure you have valid auth tokens
138
+ - For Copilot: Check token file locations in Configuration section above
87
139
 
88
- - `~/.local/share/opencode/copilot-usage-token.json`
89
- - `~/.local/share/opencode/auth.json` with a `github-copilot` entry
90
- - `~/.config/opencode/copilot-quota-token.json` (optional override)
140
+ **Config file not found**
141
+ - The plugin auto-creates `usage-config.jsonc` on first run
142
+ - Check the path in Configuration section above
143
+ - Manually create the file if needed
91
144
 
92
145
  See `AGENTS.md` for internal architecture.
@@ -3,5 +3,6 @@ export declare const providers: Record<string, UsageProvider<unknown>>;
3
3
  export { CodexProvider } from "./codex";
4
4
  export { ProxyProvider } from "./proxy";
5
5
  export { CopilotProvider } from "./copilot";
6
+ export { ZaiProvider } from "./zai";
6
7
  export type { UsageProvider } from "./base";
7
8
  //# 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;AAK3C,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAI5D,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,YAAY,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;AAM3C,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAK5D,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,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA"}
@@ -1,11 +1,14 @@
1
1
  import { CodexProvider } from "./codex";
2
2
  import { ProxyProvider } from "./proxy";
3
3
  import { CopilotProvider } from "./copilot";
4
+ import { ZaiProvider } from "./zai";
4
5
  export const providers = {
5
6
  [CodexProvider.id]: CodexProvider,
6
7
  [ProxyProvider.id]: ProxyProvider,
7
8
  [CopilotProvider.id]: CopilotProvider,
9
+ [ZaiProvider.id]: ZaiProvider,
8
10
  };
9
11
  export { CodexProvider } from "./codex";
10
12
  export { ProxyProvider } from "./proxy";
11
13
  export { CopilotProvider } from "./copilot";
14
+ export { ZaiProvider } from "./zai";
@@ -4,7 +4,7 @@
4
4
  export async function fetchProxyLimits(config) {
5
5
  const { endpoint, apiKey, timeout = 10000 } = config;
6
6
  if (!endpoint) {
7
- throw new Error("Proxy endpoint not configured");
7
+ throw new Error("Proxy endpoint not configured. Set 'endpoint' in ~/.config/opencode/usage-config.jsonc (Windows: %APPDATA%\\opencode\\usage-config.jsonc)\n\nDefault: http://localhost:8000\nIf you changed this during proxy setup, update your config.");
8
8
  }
9
9
  const headers = {
10
10
  "Content-Type": "application/json",
@@ -23,7 +23,7 @@ export async function fetchProxyLimits(config) {
23
23
  signal: controller.signal,
24
24
  });
25
25
  if (!response.ok) {
26
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
26
+ throw new Error(`Proxy request failed: HTTP ${response.status}. Check your usage-config.jsonc:\n\n - Default endpoint: http://localhost:8000\n - Default apiKey: VerysecretKey\n\nIf you changed these during proxy setup, you MUST update your config file to match.`);
27
27
  }
28
28
  return (await response.json());
29
29
  }
@@ -2,5 +2,6 @@
2
2
  * Display formatting utilities for proxy limits.
3
3
  */
4
4
  import type { ProxyResponse } from "./types";
5
- export declare function formatProxyLimits(data: ProxyResponse): string;
5
+ import type { UsageConfig } from "../../types";
6
+ export declare function formatProxyLimits(data: ProxyResponse, config: UsageConfig | null): string;
6
7
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAA;AAoHxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAoC7D"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAA;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA0G9C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,MAAM,CAqCzF"}
@@ -1,22 +1,11 @@
1
1
  /**
2
2
  * Display formatting utilities for proxy limits.
3
3
  */
4
- const GROUP_MAPPING = {
5
- "claude": "claude",
6
- "g3-pro": "g3-pro",
7
- "g3-flash": "g3-flash",
8
- "g25-flash": "25-flash",
9
- "g25-lite": "25-lite",
10
- "pro": "g3-pro",
11
- "3-flash": "g3-flash",
12
- "25-flash": "25-flash",
13
- "25-lite": "25-lite"
14
- };
15
- const GROUP_ORDER = ["claude", "g3-pro", "g3-flash", "25-flash", "25-lite"];
16
- function sortGroupNames(groups) {
4
+ import { resolveDisplayName } from "./index";
5
+ function sortGroupNames(groups, groupOrder) {
17
6
  return Array.from(groups.keys()).sort((a, b) => {
18
- const aIndex = GROUP_ORDER.indexOf(a);
19
- const bIndex = GROUP_ORDER.indexOf(b);
7
+ const aIndex = groupOrder.indexOf(a);
8
+ const bIndex = groupOrder.indexOf(b);
20
9
  if (aIndex !== -1 && bIndex !== -1)
21
10
  return aIndex - bIndex;
22
11
  if (aIndex !== -1)
@@ -59,7 +48,7 @@ function formatResetTime(isoString) {
59
48
  return "";
60
49
  }
61
50
  }
62
- function aggregateCredentialsByTier(credentials) {
51
+ function aggregateCredentialsByTier(credentials, config) {
63
52
  const result = {
64
53
  paid: new Map(),
65
54
  free: new Map(),
@@ -68,9 +57,9 @@ function aggregateCredentialsByTier(credentials) {
68
57
  const tier = normalizeTier(cred.tier);
69
58
  const groupUsage = cred.group_usage ?? {};
70
59
  for (const [name, groupData] of Object.entries(groupUsage)) {
71
- if (!(name in GROUP_MAPPING))
60
+ const mappedName = resolveDisplayName(name, config);
61
+ if (mappedName === null)
72
62
  continue;
73
- const mappedName = GROUP_MAPPING[name];
74
63
  const windows = groupData.windows || {};
75
64
  let bestWindow = null;
76
65
  const windowPriority = ["daily", "5h", "1h", "15m"];
@@ -107,8 +96,9 @@ function aggregateCredentialsByTier(credentials) {
107
96
  }
108
97
  return result;
109
98
  }
110
- export function formatProxyLimits(data) {
99
+ export function formatProxyLimits(data, config) {
111
100
  const lines = [];
101
+ const groupOrder = ["claude", "g3-pro", "g3-flash", "25-flash", "25-lite"];
112
102
  lines.push("[Google] Mirrowel Proxy");
113
103
  lines.push("");
114
104
  if (!data.providers || Object.keys(data.providers).length === 0) {
@@ -118,13 +108,13 @@ export function formatProxyLimits(data) {
118
108
  for (const [providerName, provider] of Object.entries(data.providers)) {
119
109
  lines.push(`${providerName}:`);
120
110
  const credentialsArray = Object.values(provider.credentials ?? {});
121
- const tierData = aggregateCredentialsByTier(credentialsArray);
111
+ const tierData = aggregateCredentialsByTier(credentialsArray, config);
122
112
  for (const [tierName, quotas] of Object.entries(tierData)) {
123
113
  if (quotas.size === 0)
124
114
  continue;
125
115
  const tierLabel = tierName === "paid" ? "Paid" : "Free";
126
116
  lines.push(` ${tierLabel}:`);
127
- const sortedNames = sortGroupNames(quotas);
117
+ const sortedNames = sortGroupNames(quotas, groupOrder);
128
118
  for (const groupName of sortedNames) {
129
119
  const quota = quotas.get(groupName);
130
120
  const remainingPct = quota.max > 0 ? (quota.remaining / quota.max) * 100 : 0;
@@ -3,8 +3,14 @@
3
3
  * Fetches quota stats from a local/remote proxy server.
4
4
  */
5
5
  import type { UsageProvider } from "../base";
6
+ import type { UsageConfig } from "../../types";
6
7
  export type { ProxyResponse } from "./types";
7
8
  export { fetchProxyLimits } from "./fetch";
8
9
  export { formatProxyLimits } from "./format";
10
+ /**
11
+ * Resolve the display name for a model group based on config.
12
+ * Returns null if the group should be filtered out.
13
+ */
14
+ export declare function resolveDisplayName(groupName: string, config: UsageConfig | null): string | null;
9
15
  export declare const ProxyProvider: UsageProvider<void>;
10
16
  //# 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;AAkM5C,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,IAAI,CAwB7C,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;AAC5C,OAAO,KAAK,EAAgF,WAAW,EAAE,MAAM,aAAa,CAAA;AAK5H,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA4B5C;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,GAAG,IAAI,GACzB,MAAM,GAAG,IAAI,CAoBf;AAqLD,eAAO,MAAM,aAAa,EAAE,aAAa,CAAC,IAAI,CAwB7C,CAAA"}
@@ -6,7 +6,8 @@ import { loadUsageConfig } from "../../usage/config";
6
6
  import { fetchProxyLimits } from "./fetch";
7
7
  export { fetchProxyLimits } from "./fetch";
8
8
  export { formatProxyLimits } from "./format";
9
- const GROUP_MAPPING = {
9
+ /** Default mapping for backward compatibility when no modelGroups config is present */
10
+ const DEFAULT_GROUP_MAPPING = {
10
11
  "claude": "claude",
11
12
  "g3-pro": "g3-pro",
12
13
  "g3-flash": "g3-flash",
@@ -31,6 +32,29 @@ function sortQuotaGroups(groups) {
31
32
  return a.name.localeCompare(b.name);
32
33
  });
33
34
  }
35
+ /**
36
+ * Resolve the display name for a model group based on config.
37
+ * Returns null if the group should be filtered out.
38
+ */
39
+ export function resolveDisplayName(groupName, config) {
40
+ const modelGroupsConfig = config?.modelGroups;
41
+ // No config section → backward compat: use hardcoded whitelist
42
+ if (!modelGroupsConfig) {
43
+ return groupName in DEFAULT_GROUP_MAPPING
44
+ ? DEFAULT_GROUP_MAPPING[groupName]
45
+ : null; // filter out
46
+ }
47
+ const showAll = modelGroupsConfig.showAll ?? true; // Default to auto-discovery
48
+ const displayNames = modelGroupsConfig.displayNames ?? {};
49
+ if (showAll) {
50
+ // Auto-discovery mode: show all, apply overrides
51
+ return displayNames[groupName] ?? groupName;
52
+ }
53
+ else {
54
+ // Whitelist mode: only show configured groups
55
+ return groupName in displayNames ? displayNames[groupName] : null;
56
+ }
57
+ }
34
58
  function normalizeTier(tier) {
35
59
  if (!tier)
36
60
  return "free";
@@ -39,7 +63,7 @@ function normalizeTier(tier) {
39
63
  return "paid";
40
64
  return "free";
41
65
  }
42
- function parseQuotaGroupsFromAggregation(quotaGroups) {
66
+ function parseQuotaGroupsFromAggregation(quotaGroups, config) {
43
67
  if (!quotaGroups)
44
68
  return [];
45
69
  const tiers = {
@@ -47,8 +71,8 @@ function parseQuotaGroupsFromAggregation(quotaGroups) {
47
71
  free: new Map(),
48
72
  };
49
73
  for (const [groupName, groupData] of Object.entries(quotaGroups)) {
50
- const mappedName = GROUP_MAPPING[groupName];
51
- if (!mappedName)
74
+ const displayName = resolveDisplayName(groupName, config);
75
+ if (displayName === null)
52
76
  continue;
53
77
  const windows = groupData.windows || {};
54
78
  const windowPriority = ["daily", "5h", "1h", "15m"];
@@ -68,11 +92,18 @@ function parseQuotaGroupsFromAggregation(quotaGroups) {
68
92
  // Since these are already aggregated by provider, we split by tier if possible.
69
93
  // However, the aggregate API provides tier-agnostic totals.
70
94
  // 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),
95
+ const max = window.total_max ?? window.total_remaining;
96
+ const remaining = window.total_remaining;
97
+ const remainingPct = typeof window.remaining_pct === "number"
98
+ ? Math.round(window.remaining_pct)
99
+ : max > 0
100
+ ? Math.round((remaining / max) * 100)
101
+ : 0;
102
+ tiers.paid.set(displayName, {
103
+ name: displayName,
104
+ remaining,
105
+ max,
106
+ remainingPct,
76
107
  resetTime: null, // Aggregated windows don't have a single reset_at
77
108
  });
78
109
  }
@@ -82,13 +113,14 @@ function parseQuotaGroupsFromAggregation(quotaGroups) {
82
113
  }
83
114
  return result;
84
115
  }
85
- function parseQuotaGroupsFromCredential(groupUsage) {
116
+ function parseQuotaGroupsFromCredential(groupUsage, config) {
86
117
  if (!groupUsage)
87
118
  return [];
88
119
  const result = new Map();
89
120
  for (const [groupName, groupData] of Object.entries(groupUsage)) {
90
- const mappedName = GROUP_MAPPING[groupName];
91
- if (!mappedName)
121
+ // Apply config-based filtering and display name resolution
122
+ const displayName = resolveDisplayName(groupName, config);
123
+ if (displayName === null)
92
124
  continue;
93
125
  const windows = groupData.windows || {};
94
126
  let bestWindow = null;
@@ -104,8 +136,8 @@ function parseQuotaGroupsFromCredential(groupUsage) {
104
136
  }
105
137
  if (!bestWindow)
106
138
  continue;
107
- result.set(mappedName, {
108
- name: mappedName,
139
+ result.set(displayName, {
140
+ name: displayName,
109
141
  remaining: bestWindow.remaining,
110
142
  max: bestWindow.limit || bestWindow.remaining,
111
143
  remainingPct: bestWindow.limit ? Math.round((bestWindow.remaining / bestWindow.limit) * 100) : 0,
@@ -114,10 +146,10 @@ function parseQuotaGroupsFromCredential(groupUsage) {
114
146
  }
115
147
  return Array.from(result.values());
116
148
  }
117
- function aggregateByProvider(provider) {
149
+ function aggregateByProvider(provider, config) {
118
150
  // Try aggregated quota groups first
119
151
  if (provider.quota_groups && Object.keys(provider.quota_groups).length > 0) {
120
- return parseQuotaGroupsFromAggregation(provider.quota_groups);
152
+ return parseQuotaGroupsFromAggregation(provider.quota_groups, config);
121
153
  }
122
154
  // Fallback to manual aggregation of credentials
123
155
  const tiers = {
@@ -127,7 +159,7 @@ function aggregateByProvider(provider) {
127
159
  if (provider.credentials) {
128
160
  for (const cred of Object.values(provider.credentials)) {
129
161
  const tier = normalizeTier(cred.tier);
130
- const groups = parseQuotaGroupsFromCredential(cred.group_usage);
162
+ const groups = parseQuotaGroupsFromCredential(cred.group_usage, config);
131
163
  for (const group of groups) {
132
164
  const existing = tiers[tier].get(group.name);
133
165
  if (existing) {
@@ -157,20 +189,20 @@ function aggregateByProvider(provider) {
157
189
  }
158
190
  return result;
159
191
  }
160
- function parseProviders(data) {
192
+ function parseProviders(data, config) {
161
193
  if (!data.providers)
162
194
  return [];
163
195
  return Object.entries(data.providers).map(([name, provider]) => {
164
196
  return {
165
197
  name,
166
- tiers: aggregateByProvider(provider),
198
+ tiers: aggregateByProvider(provider, config),
167
199
  };
168
200
  });
169
201
  }
170
- function parseProxyQuota(data) {
202
+ function parseProxyQuota(data, config) {
171
203
  const summary = data.summary;
172
204
  return {
173
- providers: parseProviders(data),
205
+ providers: parseProviders(data, config),
174
206
  totalCredentials: summary?.total_credentials ?? 0,
175
207
  activeCredentials: summary?.active_credentials ?? 0,
176
208
  dataSource: data.data_source,
@@ -191,7 +223,7 @@ export const ProxyProvider = {
191
223
  secondary: null,
192
224
  codeReview: null,
193
225
  credits: null,
194
- proxyQuota: parseProxyQuota(data),
226
+ proxyQuota: parseProxyQuota(data, config),
195
227
  updatedAt: Date.now(),
196
228
  };
197
229
  }
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Type definitions for the Antigravity proxy provider.
3
3
  */
4
+ /** Token statistics from the proxy */
4
5
  export type TokenStats = {
5
6
  input_cached?: number;
6
7
  input_uncached?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Fetch logic for Z.ai usage monitoring.
3
+ */
4
+ import type { ZaiAuth } from "./types";
5
+ export declare function fetchZaiUsage(auth: ZaiAuth): Promise<{
6
+ quota: {
7
+ limits: import("./types").ZaiQuotaLimit[];
8
+ };
9
+ model: {
10
+ x_time: string[];
11
+ modelCallCount: (number | null)[];
12
+ tokensUsage: (number | null)[];
13
+ totalUsage: {
14
+ totalModelCallCount: number;
15
+ totalTokensUsage: number;
16
+ };
17
+ } | undefined;
18
+ tool: {
19
+ x_time: string[];
20
+ networkSearchCount: (number | null)[];
21
+ webReadMcpCount: (number | null)[];
22
+ zreadMcpCount: (number | null)[];
23
+ totalUsage: {
24
+ totalNetworkSearchCount: number;
25
+ totalWebReadMcpCount: number;
26
+ totalZreadMcpCount: number;
27
+ totalSearchMcpCount: number;
28
+ toolDetails: unknown[];
29
+ };
30
+ } | undefined;
31
+ }>;
32
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/providers/zai/fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAiE,MAAM,SAAS,CAAA;AAErG,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;GA4ChD"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Fetch logic for Z.ai usage monitoring.
3
+ */
4
+ import { loadUsageConfig } from "../../usage/config";
5
+ export async function fetchZaiUsage(auth) {
6
+ const config = await loadUsageConfig().catch(() => null);
7
+ const baseUrl = config?.zaiEndpoint?.replace(/\/$/, "") || "https://api.z.ai";
8
+ const monitorUrl = `${baseUrl}/api/monitor/usage`;
9
+ const now = new Date();
10
+ const endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), 0, 0, 0);
11
+ const startDate = new Date(endDate.getTime() - 24 * 60 * 60 * 1000);
12
+ const formatDateTime = (date) => {
13
+ const pad = (n) => String(n).padStart(2, "0");
14
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
15
+ };
16
+ const startTime = formatDateTime(startDate);
17
+ const endTime = formatDateTime(endDate);
18
+ const queryParams = `?startTime=${encodeURIComponent(startTime)}&endTime=${encodeURIComponent(endTime)}`;
19
+ const headers = {
20
+ "Authorization": auth.key,
21
+ "Accept-Language": "en-US,en",
22
+ "Content-Type": "application/json",
23
+ };
24
+ const [quotaRes, modelRes, toolRes] = await Promise.all([
25
+ fetch(`${monitorUrl}/quota/limit`, { headers }),
26
+ fetch(`${monitorUrl}/model-usage${queryParams}`, { headers }),
27
+ fetch(`${monitorUrl}/tool-usage${queryParams}`, { headers }),
28
+ ]);
29
+ if (!quotaRes.ok) {
30
+ throw new Error(`Z.ai quota query failed: ${quotaRes.status} ${await quotaRes.text()}`);
31
+ }
32
+ const quota = (await quotaRes.json());
33
+ const model = modelRes.ok ? (await modelRes.json()) : null;
34
+ const tool = toolRes.ok ? (await toolRes.json()) : null;
35
+ return {
36
+ quota: quota.data,
37
+ model: model?.data,
38
+ tool: tool?.data,
39
+ };
40
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Z.ai GLM Coding Plan provider.
3
+ */
4
+ import type { UsageProvider } from "../base";
5
+ import type { ZaiAuth } from "./types";
6
+ export declare const ZaiProvider: UsageProvider<ZaiAuth>;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/zai/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAG5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC,OAAO,CAmC9C,CAAA"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Z.ai GLM Coding Plan provider.
3
+ */
4
+ import { fetchZaiUsage } from "./fetch";
5
+ export const ZaiProvider = {
6
+ id: "zai-coding-plan",
7
+ displayName: "Z.ai GLM Coding Plan",
8
+ async fetchUsage(auth) {
9
+ try {
10
+ const data = await fetchZaiUsage(auth);
11
+ return {
12
+ timestamp: Date.now(),
13
+ provider: "zai-coding-plan",
14
+ planType: null, // Don't assume pro, let quota numbers show tier
15
+ primary: null,
16
+ secondary: null,
17
+ codeReview: null,
18
+ credits: null,
19
+ zaiQuota: {
20
+ limits: data.quota.limits.map(l => ({
21
+ type: l.type,
22
+ usage: l.usage,
23
+ currentValue: l.currentValue,
24
+ remaining: l.remaining,
25
+ percentage: l.percentage,
26
+ nextResetTime: l.nextResetTime,
27
+ usageDetails: l.usageDetails
28
+ })),
29
+ modelUsage: data.model?.totalUsage,
30
+ toolUsage: data.tool?.totalUsage
31
+ },
32
+ updatedAt: Date.now(),
33
+ };
34
+ }
35
+ catch (e) {
36
+ return null;
37
+ }
38
+ },
39
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Type definitions for the Z.ai GLM Coding Plan provider.
3
+ */
4
+ export interface ZaiQuotaLimit {
5
+ type: string;
6
+ unit: number;
7
+ number: number;
8
+ usage: number;
9
+ currentValue: number;
10
+ remaining: number;
11
+ percentage: number;
12
+ usageDetails?: Array<{
13
+ modelCode: string;
14
+ usage: number;
15
+ }>;
16
+ nextResetTime?: number;
17
+ }
18
+ export interface ZaiQuotaResponse {
19
+ code: number;
20
+ msg: string;
21
+ data: {
22
+ limits: ZaiQuotaLimit[];
23
+ };
24
+ success: boolean;
25
+ }
26
+ export interface ZaiModelUsageResponse {
27
+ code: number;
28
+ msg: string;
29
+ data: {
30
+ x_time: string[];
31
+ modelCallCount: (number | null)[];
32
+ tokensUsage: (number | null)[];
33
+ totalUsage: {
34
+ totalModelCallCount: number;
35
+ totalTokensUsage: number;
36
+ };
37
+ };
38
+ success: boolean;
39
+ }
40
+ export interface ZaiToolUsageResponse {
41
+ code: number;
42
+ msg: string;
43
+ data: {
44
+ x_time: string[];
45
+ networkSearchCount: (number | null)[];
46
+ webReadMcpCount: (number | null)[];
47
+ zreadMcpCount: (number | null)[];
48
+ totalUsage: {
49
+ totalNetworkSearchCount: number;
50
+ totalWebReadMcpCount: number;
51
+ totalZreadMcpCount: number;
52
+ totalSearchMcpCount: number;
53
+ toolDetails: unknown[];
54
+ };
55
+ };
56
+ success: boolean;
57
+ }
58
+ export interface ZaiAuth {
59
+ key: string;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/zai/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE;QACJ,MAAM,EAAE,aAAa,EAAE,CAAA;KACxB,CAAA;IACD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,cAAc,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;QACjC,WAAW,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;QAC9B,UAAU,EAAE;YACV,mBAAmB,EAAE,MAAM,CAAA;YAC3B,gBAAgB,EAAE,MAAM,CAAA;SACzB,CAAA;KACF,CAAA;IACD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE;QACJ,MAAM,EAAE,MAAM,EAAE,CAAA;QAChB,kBAAkB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;QACrC,eAAe,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;QAClC,aAAa,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;QAChC,UAAU,EAAE;YACV,uBAAuB,EAAE,MAAM,CAAA;YAC/B,oBAAoB,EAAE,MAAM,CAAA;YAC5B,kBAAkB,EAAE,MAAM,CAAA;YAC1B,mBAAmB,EAAE,MAAM,CAAA;YAC3B,WAAW,EAAE,OAAO,EAAE,CAAA;SACvB,CAAA;KACF,CAAA;IACD,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAA;CACZ"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Type definitions for the Z.ai GLM Coding Plan provider.
3
+ */
4
+ export {};
package/dist/types.d.ts CHANGED
@@ -45,11 +45,40 @@ export interface ProxyQuota {
45
45
  export interface UsageConfig {
46
46
  endpoint?: string;
47
47
  apiKey?: string;
48
+ zaiEndpoint?: string;
48
49
  timeout?: number;
49
50
  providers?: {
50
51
  openai?: boolean;
51
52
  proxy?: boolean;
52
53
  copilot?: boolean;
54
+ zai?: boolean;
55
+ };
56
+ modelGroups?: {
57
+ showAll?: boolean;
58
+ displayNames?: Record<string, string>;
59
+ };
60
+ }
61
+ export interface ZaiQuota {
62
+ limits: Array<{
63
+ type: string;
64
+ usage: number;
65
+ currentValue: number;
66
+ remaining: number;
67
+ percentage: number;
68
+ nextResetTime?: number;
69
+ usageDetails?: Array<{
70
+ modelCode: string;
71
+ usage: number;
72
+ }>;
73
+ }>;
74
+ modelUsage?: {
75
+ totalModelCallCount: number;
76
+ totalTokensUsage: number;
77
+ };
78
+ toolUsage?: {
79
+ totalNetworkSearchCount: number;
80
+ totalWebReadMcpCount: number;
81
+ totalZreadMcpCount: number;
53
82
  };
54
83
  }
55
84
  export interface UsageSnapshot {
@@ -62,6 +91,7 @@ export interface UsageSnapshot {
62
91
  credits: CreditsSnapshot | null;
63
92
  proxyQuota?: ProxyQuota;
64
93
  copilotQuota?: CopilotQuota;
94
+ zaiQuota?: ZaiQuota;
65
95
  updatedAt: number;
66
96
  isMissing?: boolean;
67
97
  missingReason?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -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,CAGhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKxD;AAWD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBvE"}
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,CAGhE;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKxD;AAaD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAgBvE"}
@@ -25,14 +25,15 @@ export function formatResetSuffixISO(iso) {
25
25
  }
26
26
  }
27
27
  function formatTimeDelta(at) {
28
- const diff = at - Math.floor(Date.now() / 1000);
28
+ const atSeconds = at > 1e11 ? Math.floor(at / 1000) : at;
29
+ const diff = atSeconds - Math.floor(Date.now() / 1000);
29
30
  if (diff <= 0)
30
31
  return "now";
31
32
  if (diff < 60)
32
33
  return `${diff}s`;
33
34
  if (diff < 3600)
34
35
  return `${Math.ceil(diff / 60)}m`;
35
- if (diff < 84400)
36
+ if (diff < 86400)
36
37
  return `${Math.round(diff / 3600)}h`;
37
38
  return `${Math.round(diff / 86400)}d`;
38
39
  }
@@ -41,7 +42,7 @@ export function formatMissingSnapshot(snapshot) {
41
42
  const configPath = getConfigPath();
42
43
  const instructions = {
43
44
  codex: "if you dont have codex oauth, please set your usage-config.jsonc to openai: false",
44
- proxy: "if you are not running Mirrowel's proxy, please set your usage-config.jsonc to proxy: false",
45
+ 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.",
45
46
  copilot: "if you are not running GitHub Copilot, please set your usage-config.jsonc to copilot: false"
46
47
  };
47
48
  const lines = [`→ [${provider.toUpperCase()}] - ${instructions[provider] || ""}`];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Formats Z.ai GLM Coding Plan usage snapshots.
3
+ */
4
+ import type { UsageSnapshot } from "../../types";
5
+ export declare function formatZaiSnapshot(snapshot: UsageSnapshot): string[];
6
+ //# sourceMappingURL=zai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zai.d.ts","sourceRoot":"","sources":["../../../src/ui/formatters/zai.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAGhD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CA8BnE"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Formats Z.ai GLM Coding Plan usage snapshots.
3
+ */
4
+ import { formatBar, formatMissingSnapshot, formatResetSuffix } from "./shared";
5
+ export function formatZaiSnapshot(snapshot) {
6
+ const zai = snapshot.zaiQuota;
7
+ if (!zai?.limits?.length)
8
+ return formatMissingSnapshot(snapshot);
9
+ const lines = ["→ [Z.ai] GLM Coding Plan"];
10
+ for (const limit of zai.limits) {
11
+ const isTokens = limit.type === "TOKENS_LIMIT";
12
+ const label = isTokens ? "5 Hours Quota" : "Total Monthly Web Search / Reader / Zread Quota";
13
+ const remainingPct = 100 - limit.percentage;
14
+ const reset = isTokens
15
+ ? (limit.nextResetTime ? formatResetSuffix(limit.nextResetTime) : "")
16
+ : " (resets on the 1st)";
17
+ lines.push(` ${label}`);
18
+ lines.push(` ${formatBar(remainingPct)} ${remainingPct.toFixed(0)}% left${reset}`);
19
+ const unit = isTokens ? "Tokens" : "Times";
20
+ lines.push(` Used: ${limit.currentValue.toLocaleString()} / ${limit.usage.toLocaleString()} ${unit}`);
21
+ lines.push("");
22
+ }
23
+ if (zai.modelUsage) {
24
+ lines.push(` 24h Activity:`);
25
+ lines.push(` Tokens: ${zai.modelUsage.totalTokensUsage.toLocaleString()}`);
26
+ lines.push(` Calls: ${zai.modelUsage.totalModelCallCount.toLocaleString()}`);
27
+ }
28
+ return lines;
29
+ }
@@ -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;AAK1C,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;AAiCD,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"}
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;AAM1C,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;AAkCD,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
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { formatProxySnapshot } from "./formatters/proxy";
6
6
  import { formatCopilotSnapshot } from "./formatters/copilot";
7
+ import { formatZaiSnapshot } from "./formatters/zai";
7
8
  import { formatBar, formatResetSuffix, formatMissingSnapshot } from "./formatters/shared";
8
9
  export async function sendStatusMessage(options) {
9
10
  const bus = options.client.bus;
@@ -32,6 +33,8 @@ function formatSnapshot(snapshot) {
32
33
  return formatProxySnapshot(snapshot);
33
34
  if (snapshot.provider === "copilot")
34
35
  return formatCopilotSnapshot(snapshot);
36
+ if (snapshot.provider === "zai-coding-plan")
37
+ return formatZaiSnapshot(snapshot);
35
38
  const plan = snapshot.planType ? ` (${snapshot.planType.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase())})` : "";
36
39
  const lines = [`→ [${snapshot.provider.toUpperCase()}]${plan}`];
37
40
  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,CA0C5D"}
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,CA0D5D"}
@@ -18,13 +18,26 @@ export async function loadUsageConfig() {
18
18
  const file = Bun.file(CONFIG_PATH);
19
19
  if (!(await file.exists())) {
20
20
  const content = `{
21
- "endpoint": "",
22
- "apiKey": "",
21
+ // REQUIRED: Proxy server endpoint (default: "http://localhost:8000")
22
+ // Leave empty ONLY if you don't use the proxy
23
+ "endpoint": "http://localhost:8000",
24
+
25
+ // REQUIRED: API key for proxy auth (default: "VerysecretKey")
26
+ // Leave empty if your proxy doesn't require authentication
27
+ "apiKey": "VerysecretKey",
28
+
29
+ // Optional: Z.ai API endpoint (default: "https://api.z.ai")
30
+ "zaiEndpoint": "https://api.z.ai",
31
+
32
+ // Optional: Request timeout in milliseconds (default: 10000)
23
33
  "timeout": 10000,
34
+
35
+ // Optional: Show/hide providers in /usage output
24
36
  "providers": {
25
37
  "openai": true,
26
38
  "proxy": true,
27
- "copilot": true
39
+ "copilot": true,
40
+ "zai": true
28
41
  }
29
42
  }
30
43
  `;
@@ -37,6 +50,7 @@ export async function loadUsageConfig() {
37
50
  openai: true,
38
51
  proxy: true,
39
52
  copilot: true,
53
+ zai: true,
40
54
  },
41
55
  };
42
56
  }
@@ -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,CA2CnF;AAWD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzE;AA6BD,wBAAsB,SAAS,gDAG9B"}
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,CA4CnF;AAYD,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEzE;AA8BD,wBAAsB,SAAS,gDAG9B"}
@@ -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"];
9
+ const CORE_PROVIDERS = ["codex", "proxy", "copilot", "zai-coding-plan"];
10
10
  export async function fetchUsageSnapshots(filter) {
11
11
  const target = resolveFilter(filter);
12
12
  const config = await loadUsageConfig().catch(() => null);
@@ -14,6 +14,8 @@ export async function fetchUsageSnapshots(filter) {
14
14
  const isEnabled = (id) => {
15
15
  if (id === "codex")
16
16
  return toggles.openai !== false;
17
+ if (id === "zai-coding-plan")
18
+ return toggles.zai !== false;
17
19
  return toggles[id] !== false;
18
20
  };
19
21
  const { auths, codexDiagnostics } = await loadMergedAuths();
@@ -51,7 +53,8 @@ function resolveFilter(f) {
51
53
  const aliases = {
52
54
  codex: "codex", openai: "codex", gpt: "codex",
53
55
  proxy: "proxy", agy: "proxy", gemini: "proxy",
54
- copilot: "copilot", github: "copilot"
56
+ copilot: "copilot", github: "copilot",
57
+ zai: "zai-coding-plan", glm: "zai-coding-plan"
55
58
  };
56
59
  return f ? aliases[f.toLowerCase().trim()] : undefined;
57
60
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import type { CodexAuth } from "../providers/codex";
5
5
  import type { CopilotAuthData } from "../providers/copilot/types";
6
+ import type { ZaiAuth } from "../providers/zai/types";
6
7
  export type AuthEntry = {
7
8
  type?: string;
8
9
  access?: string;
@@ -18,6 +19,9 @@ type ProviderAuthEntry = {
18
19
  } | {
19
20
  providerID: "copilot";
20
21
  auth: CopilotAuthData;
22
+ } | {
23
+ providerID: "zai-coding-plan";
24
+ auth: ZaiAuth;
21
25
  };
22
26
  export declare function resolveProviderAuths(auths: AuthRecord, usageToken: string | null): ProviderAuthEntry[];
23
27
  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;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"}
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;AAErD,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,CAAA;AAsCpD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,EAAE,CActG"}
@@ -20,6 +20,14 @@ const providerDescriptors = [
20
20
  refresh: entry.refresh,
21
21
  }),
22
22
  },
23
+ {
24
+ id: "zai-coding-plan",
25
+ authKeys: ["zai-coding-plan", "zai", "glm"],
26
+ requiresOAuth: false,
27
+ buildAuth: (entry) => ({
28
+ key: entry.key || entry.access || "",
29
+ }),
30
+ },
23
31
  ];
24
32
  export function resolveProviderAuths(auths, usageToken) {
25
33
  const entries = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/opencode-usage-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "opencode plugin for tracking AI provider usage, rate limits, and quotas",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",