@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 +4 -2
- package/README.zh-CN.md +4 -2
- package/dist/plugin/lib/config.d.ts +5 -1
- package/dist/plugin/lib/config.js +11 -4
- package/dist/plugin/lib/deepseek.js +3 -1
- package/dist/plugin/lib/google.js +1 -1
- package/dist/plugin/lib/utils.d.ts +2 -0
- package/dist/plugin/lib/utils.js +7 -0
- package/dist/plugin/mystatus.js +32 -7
- package/package.json +6 -5
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/
|
|
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/
|
|
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<
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
package/dist/plugin/lib/utils.js
CHANGED
|
@@ -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
|
}
|
package/dist/plugin/mystatus.js
CHANGED
|
@@ -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
|
|
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.
|
|
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/
|
|
48
|
+
"url": "git+https://github.com/ekworp/opencode-mystatus.git"
|
|
49
49
|
},
|
|
50
50
|
"bugs": {
|
|
51
|
-
"url": "https://github.com/
|
|
51
|
+
"url": "https://github.com/ekworp/opencode-mystatus/issues"
|
|
52
52
|
},
|
|
53
|
-
"homepage": "https://github.com/
|
|
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",
|