@ekworp/opencode-mystatus 1.2.8 → 1.2.10

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 CHANGED
@@ -28,7 +28,7 @@ An [OpenCode](https://opencode.ai) plugin to query account quota usage for multi
28
28
  Paste this into any LLM agent (Claude Code, OpenCode, Cursor, etc.):
29
29
 
30
30
  ```
31
- Install the opencode-mystatus plugin by following: https://raw.githubusercontent.com/vbgate/opencode-mystatus/main/README.md
31
+ Install the opencode-mystatus plugin by following: https://raw.githubusercontent.com/ekworp/opencode-mystatus/main/README.md
32
32
  ```
33
33
 
34
34
  <details>
@@ -174,11 +174,13 @@ Create `~/.config/opencode/mystatus.json` to skip selected providers:
174
174
 
175
175
  ```json
176
176
  {
177
- "disabledProviders": ["deepseek", "google"]
177
+ "disabledProviders": ["deepseek", "google"],
178
+ "useOpenCodeProxy": true
178
179
  }
179
180
  ```
180
181
 
181
182
  Available names: `openai`, `zhipuai-coding-plan`, `zai-coding-plan`, `deepseek`, `google`, `github-copilot`.
183
+ `useOpenCodeProxy` defaults to `true` and uses the proxy environment configured for the OpenCode service.
182
184
 
183
185
  ### Google Cloud Setup
184
186
 
package/README.zh-CN.md CHANGED
@@ -28,7 +28,7 @@
28
28
  将以下内容粘贴到任意 AI 代理(Claude Code、OpenCode、Cursor 等):
29
29
 
30
30
  ```
31
- Install the opencode-mystatus plugin by following: https://raw.githubusercontent.com/vbgate/opencode-mystatus/main/README.md
31
+ Install the opencode-mystatus plugin by following: https://raw.githubusercontent.com/ekworp/opencode-mystatus/main/README.md
32
32
  ```
33
33
 
34
34
  <details>
@@ -173,11 +173,13 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
173
173
 
174
174
  ```json
175
175
  {
176
- "disabledProviders": ["deepseek", "google"]
176
+ "disabledProviders": ["deepseek", "google"],
177
+ "useOpenCodeProxy": true
177
178
  }
178
179
  ```
179
180
 
180
181
  可用名称:`openai`、`zhipuai-coding-plan`、`zai-coding-plan`、`deepseek`、`google`、`github-copilot`。
182
+ `useOpenCodeProxy` 默认为 `true`,会使用 OpenCode 服务配置的代理环境变量。
181
183
 
182
184
  ### Google Cloud 设置
183
185
 
@@ -1,6 +1,10 @@
1
1
  export type ProviderId = "openai" | "zhipuai-coding-plan" | "zai-coding-plan" | "deepseek" | "google" | "github-copilot";
2
+ export interface MystatusConfig {
3
+ disabledProviders: Set<ProviderId>;
4
+ useOpenCodeProxy: boolean;
5
+ }
2
6
  declare const CONFIG_PATH: string;
3
7
  /** Read optional provider filters. Invalid or missing config means enabled all. */
4
- export declare function readMystatusConfig(): Promise<Set<ProviderId>>;
8
+ export declare function readMystatusConfig(): Promise<MystatusConfig>;
5
9
  export declare function isProviderEnabled(disabledProviders: Set<ProviderId>, provider: ProviderId): boolean;
6
10
  export { CONFIG_PATH };
@@ -7,8 +7,12 @@ export async function readMystatusConfig() {
7
7
  try {
8
8
  const content = await readFile(CONFIG_PATH, "utf8");
9
9
  const config = JSON.parse(content);
10
- if (!Array.isArray(config.disabledProviders))
11
- return new Set();
10
+ if (!Array.isArray(config.disabledProviders)) {
11
+ return {
12
+ disabledProviders: new Set(),
13
+ useOpenCodeProxy: config.useOpenCodeProxy !== false,
14
+ };
15
+ }
12
16
  const validProviders = [
13
17
  "openai",
14
18
  "zhipuai-coding-plan",
@@ -17,10 +21,13 @@ export async function readMystatusConfig() {
17
21
  "google",
18
22
  "github-copilot",
19
23
  ];
20
- return new Set(config.disabledProviders.filter((provider) => validProviders.includes(provider)));
24
+ return {
25
+ disabledProviders: new Set(config.disabledProviders.filter((provider) => validProviders.includes(provider))),
26
+ useOpenCodeProxy: config.useOpenCodeProxy !== false,
27
+ };
21
28
  }
22
29
  catch {
23
- return new Set();
30
+ return { disabledProviders: new Set(), useOpenCodeProxy: true };
24
31
  }
25
32
  }
26
33
  export function isProviderEnabled(disabledProviders, provider) {
@@ -31,7 +31,9 @@ function formatBalance(data, apiKey) {
31
31
  return lines.join("\n");
32
32
  }
33
33
  export async function queryDeepSeekUsage(authData) {
34
- if (authData?.type !== "api" || !authData.key)
34
+ // OpenCode stores API-key credentials with type "key" in V2.
35
+ // Keep accepting the older "api" shape for compatibility.
36
+ if (!authData?.key || !["key", "api"].includes(authData.type))
35
37
  return null;
36
38
  try {
37
39
  const balance = await fetchBalance(authData.key);
@@ -102,7 +102,7 @@ async function refreshAccessToken(refreshToken) {
102
102
  refresh_token: refreshToken,
103
103
  grant_type: "refresh_token",
104
104
  });
105
- const response = await fetch(GOOGLE_TOKEN_REFRESH_URL, {
105
+ const response = await fetchWithTimeout(GOOGLE_TOKEN_REFRESH_URL, {
106
106
  method: "POST",
107
107
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
108
108
  body: params,
@@ -4,6 +4,8 @@
4
4
  * [定位]: 被所有平台模块共享使用的工具函数
5
5
  * [同步]: openai.ts, zhipu.ts, google.ts
6
6
  */
7
+ /** Use the proxy environment inherited from the OpenCode service by default. */
8
+ export declare function configureOpenCodeProxy(enabled: boolean): void;
7
9
  /**
8
10
  * 将秒数转换为人类可读的时间格式
9
11
  */
@@ -4,8 +4,14 @@
4
4
  * [定位]: 被所有平台模块共享使用的工具函数
5
5
  * [同步]: openai.ts, zhipu.ts, google.ts
6
6
  */
7
+ import { Agent, EnvHttpProxyAgent } from "undici";
7
8
  import { currentLang, t } from "./i18n";
8
9
  import { REQUEST_TIMEOUT_MS } from "./types";
10
+ let httpDispatcher = new EnvHttpProxyAgent();
11
+ /** Use the proxy environment inherited from the OpenCode service by default. */
12
+ export function configureOpenCodeProxy(enabled) {
13
+ httpDispatcher = enabled ? new EnvHttpProxyAgent() : new Agent();
14
+ }
9
15
  // ============================================================================
10
16
  // 时间格式化
11
17
  // ============================================================================
@@ -74,6 +80,7 @@ export async function fetchWithTimeout(url, options, timeoutMs = REQUEST_TIMEOUT
74
80
  const response = await fetch(url, {
75
81
  ...options,
76
82
  signal: controller.signal,
83
+ dispatcher: httpDispatcher,
77
84
  });
78
85
  return response;
79
86
  }
@@ -16,6 +16,7 @@ import { queryGoogleUsage } from "./lib/google";
16
16
  import { t } from "./lib/i18n";
17
17
  import { queryOpenAIUsage } from "./lib/openai";
18
18
  import { readV2AuthData } from "./lib/opencode-auth";
19
+ import { configureOpenCodeProxy } from "./lib/utils";
19
20
  import { queryZaiUsage, queryZhipuUsage } from "./lib/zhipu";
20
21
  // ============================================================================
21
22
  // V2 插件导出
@@ -35,7 +36,9 @@ export default Plugin.define({
35
36
  async execute() {
36
37
  // V2 stores credentials and refreshed OAuth tokens in SQLite.
37
38
  const databasePath = join(homedir(), ".local/share/opencode/opencode.db");
38
- const disabledProviders = await readMystatusConfig();
39
+ const config = await readMystatusConfig();
40
+ const { disabledProviders } = config;
41
+ configureOpenCodeProxy(config.useOpenCodeProxy);
39
42
  const authData = await readV2AuthData(databasePath, disabledProviders);
40
43
  const providers = [
41
44
  "openai",
@@ -57,22 +60,22 @@ export default Plugin.define({
57
60
  // 2. 并行查询所有平台(Google 不依赖 authData)
58
61
  const [openaiResult, zhipuResult, zaiResult, deepseekResult, googleResult, copilotResult,] = await Promise.all([
59
62
  isProviderEnabled(disabledProviders, "openai")
60
- ? queryOpenAIUsage(authData.openai)
63
+ ? retryQuery(() => queryOpenAIUsage(authData.openai))
61
64
  : null,
62
65
  isProviderEnabled(disabledProviders, "zhipuai-coding-plan")
63
- ? queryZhipuUsage(authData["zhipuai-coding-plan"])
66
+ ? retryQuery(() => queryZhipuUsage(authData["zhipuai-coding-plan"]))
64
67
  : null,
65
68
  isProviderEnabled(disabledProviders, "zai-coding-plan")
66
- ? queryZaiUsage(authData["zai-coding-plan"])
69
+ ? retryQuery(() => queryZaiUsage(authData["zai-coding-plan"]))
67
70
  : null,
68
71
  isProviderEnabled(disabledProviders, "deepseek")
69
- ? queryDeepSeekUsage(authData.deepseek)
72
+ ? retryQuery(() => queryDeepSeekUsage(authData.deepseek))
70
73
  : null,
71
74
  isProviderEnabled(disabledProviders, "google")
72
- ? queryGoogleUsage()
75
+ ? retryQuery(() => queryGoogleUsage())
73
76
  : null,
74
77
  isProviderEnabled(disabledProviders, "github-copilot")
75
- ? queryCopilotUsage(authData["github-copilot"])
78
+ ? retryQuery(() => queryCopilotUsage(authData["github-copilot"]))
76
79
  : null,
77
80
  ]);
78
81
  // 3. 收集结果
@@ -124,3 +127,25 @@ function collectResult(result, title, results, errors) {
124
127
  errors.push(result.error);
125
128
  }
126
129
  }
130
+ /** Retry transient provider failures before displaying an error. */
131
+ async function retryQuery(query) {
132
+ const maxAttempts = 3;
133
+ let result = null;
134
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
135
+ try {
136
+ result = await query();
137
+ }
138
+ catch (err) {
139
+ result = {
140
+ success: false,
141
+ error: err instanceof Error ? err.message : String(err),
142
+ };
143
+ }
144
+ // null means the provider is not configured; it should not be retried.
145
+ if (!result || result.success || attempt === maxAttempts)
146
+ return result;
147
+ // 500ms, then 1s. Avoid hammering a temporarily unavailable API.
148
+ await new Promise((resolve) => setTimeout(resolve, attempt * 500));
149
+ }
150
+ return result;
151
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekworp/opencode-mystatus",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "Check all your AI subscription quotas in one command. Supports OpenAI, Zhipu AI, Z.ai, and Google Antigravity. More platforms coming soon.",
5
5
  "type": "module",
6
6
  "main": "dist/plugin/mystatus.js",
@@ -45,14 +45,15 @@
45
45
  "license": "MIT",
46
46
  "repository": {
47
47
  "type": "git",
48
- "url": "git+https://github.com/vbgate/opencode-mystatus.git"
48
+ "url": "git+https://github.com/ekworp/opencode-mystatus.git"
49
49
  },
50
50
  "bugs": {
51
- "url": "https://github.com/vbgate/opencode-mystatus/issues"
51
+ "url": "https://github.com/ekworp/opencode-mystatus/issues"
52
52
  },
53
- "homepage": "https://github.com/vbgate/opencode-mystatus#readme",
53
+ "homepage": "https://github.com/ekworp/opencode-mystatus#readme",
54
54
  "dependencies": {
55
- "@opencode/plugin": "2.0.25"
55
+ "@opencode/plugin": "2.0.25",
56
+ "undici": "^6.29.0"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@biomejs/biome": "^2.5.15",