@ekworp/opencode-mystatus 1.2.7 → 1.2.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 +19 -6
- package/README.zh-CN.md +20 -7
- package/dist/plugin/lib/config.d.ts +6 -0
- package/dist/plugin/lib/config.js +29 -0
- package/dist/plugin/lib/copilot.d.ts +0 -1
- package/dist/plugin/lib/deepseek.d.ts +3 -0
- package/dist/plugin/lib/deepseek.js +46 -0
- package/dist/plugin/lib/google.d.ts +0 -1
- package/dist/plugin/lib/i18n.d.ts +12 -3
- package/dist/plugin/lib/i18n.js +14 -4
- package/dist/plugin/lib/openai.d.ts +0 -1
- package/dist/plugin/lib/opencode-auth.d.ts +9 -0
- package/dist/plugin/lib/opencode-auth.js +48 -0
- package/dist/plugin/lib/types.d.ts +6 -1
- package/dist/plugin/lib/utils.d.ts +0 -1
- package/dist/plugin/lib/zhipu.d.ts +0 -1
- package/dist/plugin/mystatus.d.ts +2 -3
- package/dist/plugin/mystatus.js +45 -19
- package/package.json +13 -9
package/README.md
CHANGED
|
@@ -14,10 +14,11 @@ An [OpenCode](https://opencode.ai) plugin to query account quota usage for multi
|
|
|
14
14
|
|
|
15
15
|
| Platform | Account Type | Data Source |
|
|
16
16
|
| ------------ | ----------------- | ---------------------------------------------- |
|
|
17
|
-
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/
|
|
18
|
-
| Zhipu AI | Coding Plan | `~/.local/share/opencode/
|
|
19
|
-
| Z.ai | Coding Plan | `~/.local/share/opencode/
|
|
20
|
-
|
|
|
17
|
+
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/opencode.db` |
|
|
18
|
+
| Zhipu AI | Coding Plan | `~/.local/share/opencode/opencode.db` |
|
|
19
|
+
| Z.ai | Coding Plan | `~/.local/share/opencode/opencode.db` |
|
|
20
|
+
| DeepSeek | API balance | `~/.local/share/opencode/opencode.db` |
|
|
21
|
+
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/opencode.db` |
|
|
21
22
|
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |
|
|
22
23
|
|
|
23
24
|
## Installation
|
|
@@ -164,9 +165,21 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
|
|
|
164
165
|
|
|
165
166
|
No additional configuration required. The plugin automatically reads credentials from:
|
|
166
167
|
|
|
167
|
-
- **OpenAI, Zhipu AI, Z.ai & GitHub Copilot**: `~/.local/share/opencode/
|
|
168
|
+
- **OpenAI, Zhipu AI, Z.ai, DeepSeek & GitHub Copilot**: `~/.local/share/opencode/opencode.db`
|
|
168
169
|
- **Google Cloud**: `~/.config/opencode/antigravity-accounts.json`
|
|
169
170
|
|
|
171
|
+
### Disable providers
|
|
172
|
+
|
|
173
|
+
Create `~/.config/opencode/mystatus.json` to skip selected providers:
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"disabledProviders": ["deepseek", "google"]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Available names: `openai`, `zhipuai-coding-plan`, `zai-coding-plan`, `deepseek`, `google`, `github-copilot`.
|
|
182
|
+
|
|
170
183
|
### Google Cloud Setup
|
|
171
184
|
|
|
172
185
|
To query Google Cloud (Antigravity) account quota, you need to install the [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) plugin first to authenticate your Google account.
|
|
@@ -177,7 +190,7 @@ This plugin is safe to use:
|
|
|
177
190
|
|
|
178
191
|
**Local Files Accessed (read-only):**
|
|
179
192
|
|
|
180
|
-
- `~/.local/share/opencode/
|
|
193
|
+
- `~/.local/share/opencode/opencode.db` - OpenCode V2's official credential storage
|
|
181
194
|
- `~/.config/opencode/antigravity-accounts.json` - Antigravity plugin's account storage
|
|
182
195
|
|
|
183
196
|
**API Endpoints (all official):**
|
package/README.zh-CN.md
CHANGED
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
| 平台 | 账号类型 | 数据来源 |
|
|
16
16
|
| ------------ | ----------------- | ---------------------------------------------- |
|
|
17
|
-
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/
|
|
18
|
-
| 智谱 AI | Coding Plan | `~/.local/share/opencode/
|
|
19
|
-
| Z.ai | Coding Plan | `~/.local/share/opencode/
|
|
20
|
-
|
|
|
17
|
+
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/opencode.db` |
|
|
18
|
+
| 智谱 AI | Coding Plan | `~/.local/share/opencode/opencode.db` |
|
|
19
|
+
| Z.ai | Coding Plan | `~/.local/share/opencode/opencode.db` |
|
|
20
|
+
| DeepSeek | API 余额 | `~/.local/share/opencode/opencode.db` |
|
|
21
|
+
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/opencode.db` |
|
|
21
22
|
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |
|
|
22
23
|
|
|
23
24
|
## 安装
|
|
@@ -161,11 +162,23 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
|
|
|
161
162
|
|
|
162
163
|
## 配置
|
|
163
164
|
|
|
164
|
-
|
|
165
|
+
插件自动从以下位置读取认证信息:
|
|
165
166
|
|
|
166
|
-
- **OpenAI、智谱 AI、Z.ai 和 GitHub Copilot**: `~/.local/share/opencode/
|
|
167
|
+
- **OpenAI、智谱 AI、Z.ai、DeepSeek 和 GitHub Copilot**: `~/.local/share/opencode/opencode.db`
|
|
167
168
|
- **Google Cloud**: `~/.config/opencode/antigravity-accounts.json`
|
|
168
169
|
|
|
170
|
+
### 禁用平台
|
|
171
|
+
|
|
172
|
+
可创建 `~/.config/opencode/mystatus.json`,过滤不需要查询的平台:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"disabledProviders": ["deepseek", "google"]
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
可用名称:`openai`、`zhipuai-coding-plan`、`zai-coding-plan`、`deepseek`、`google`、`github-copilot`。
|
|
181
|
+
|
|
169
182
|
### Google Cloud 设置
|
|
170
183
|
|
|
171
184
|
如需查询 Google Cloud (Antigravity) 账号额度,需要先安装 [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) 插件来完成 Google 账号认证。
|
|
@@ -176,7 +189,7 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
|
|
|
176
189
|
|
|
177
190
|
**读取的本地文件(只读):**
|
|
178
191
|
|
|
179
|
-
- `~/.local/share/opencode/
|
|
192
|
+
- `~/.local/share/opencode/opencode.db` - OpenCode V2 官方认证存储
|
|
180
193
|
- `~/.config/opencode/antigravity-accounts.json` - Antigravity 插件的账号存储
|
|
181
194
|
|
|
182
195
|
**请求的 API 接口(均为官方接口):**
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type ProviderId = "openai" | "zhipuai-coding-plan" | "zai-coding-plan" | "deepseek" | "google" | "github-copilot";
|
|
2
|
+
declare const CONFIG_PATH: string;
|
|
3
|
+
/** Read optional provider filters. Invalid or missing config means enabled all. */
|
|
4
|
+
export declare function readMystatusConfig(): Promise<Set<ProviderId>>;
|
|
5
|
+
export declare function isProviderEnabled(disabledProviders: Set<ProviderId>, provider: ProviderId): boolean;
|
|
6
|
+
export { CONFIG_PATH };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const CONFIG_PATH = join(homedir(), ".config/opencode/mystatus.json");
|
|
5
|
+
/** Read optional provider filters. Invalid or missing config means enabled all. */
|
|
6
|
+
export async function readMystatusConfig() {
|
|
7
|
+
try {
|
|
8
|
+
const content = await readFile(CONFIG_PATH, "utf8");
|
|
9
|
+
const config = JSON.parse(content);
|
|
10
|
+
if (!Array.isArray(config.disabledProviders))
|
|
11
|
+
return new Set();
|
|
12
|
+
const validProviders = [
|
|
13
|
+
"openai",
|
|
14
|
+
"zhipuai-coding-plan",
|
|
15
|
+
"zai-coding-plan",
|
|
16
|
+
"deepseek",
|
|
17
|
+
"google",
|
|
18
|
+
"github-copilot",
|
|
19
|
+
];
|
|
20
|
+
return new Set(config.disabledProviders.filter((provider) => validProviders.includes(provider)));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return new Set();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function isProviderEnabled(disabledProviders, provider) {
|
|
27
|
+
return !disabledProviders.has(provider);
|
|
28
|
+
}
|
|
29
|
+
export { CONFIG_PATH };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** DeepSeek account balance query module. */
|
|
2
|
+
import { t } from "./i18n";
|
|
3
|
+
import { fetchWithTimeout, maskString } from "./utils";
|
|
4
|
+
const DEEPSEEK_BALANCE_URL = "https://api.deepseek.com/user/balance";
|
|
5
|
+
async function fetchBalance(apiKey) {
|
|
6
|
+
const response = await fetchWithTimeout(DEEPSEEK_BALANCE_URL, {
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${apiKey}`,
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
"User-Agent": "OpenCode-Status-Plugin/1.0",
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const errorText = await response.text();
|
|
15
|
+
throw new Error(t.deepseekApiError(response.status, errorText));
|
|
16
|
+
}
|
|
17
|
+
return (await response.json());
|
|
18
|
+
}
|
|
19
|
+
function formatBalance(data, apiKey) {
|
|
20
|
+
const lines = [
|
|
21
|
+
`${t.account} ${maskString(apiKey)} (${t.deepseekAccountName})`,
|
|
22
|
+
"",
|
|
23
|
+
];
|
|
24
|
+
if (!data.is_available || !data.balance_infos?.length) {
|
|
25
|
+
lines.push(t.deepseekNoBalance);
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
for (const balance of data.balance_infos) {
|
|
29
|
+
lines.push(`${t.deepseekBalance}: ${balance.total_balance} ${balance.currency}`);
|
|
30
|
+
}
|
|
31
|
+
return lines.join("\n");
|
|
32
|
+
}
|
|
33
|
+
export async function queryDeepSeekUsage(authData) {
|
|
34
|
+
if (authData?.type !== "api" || !authData.key)
|
|
35
|
+
return null;
|
|
36
|
+
try {
|
|
37
|
+
const balance = await fetchBalance(authData.key);
|
|
38
|
+
return { success: true, output: formatBalance(balance, authData.key) };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
error: err instanceof Error ? err.message : String(err),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -26,17 +26,22 @@ export declare const t: {
|
|
|
26
26
|
readonly apiError: (status: number, text: string) => string;
|
|
27
27
|
readonly timeoutError: (seconds: number) => string;
|
|
28
28
|
readonly tokenExpired: "⚠️ OAuth 授权已过期,请在 OpenCode 中使用一次 OpenAI 模型以刷新授权。";
|
|
29
|
-
readonly noAccounts: "未找到任何已配置的账号。\n\n支持的账号类型:\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)";
|
|
29
|
+
readonly noAccounts: "未找到任何已配置的账号。\n\n支持的账号类型:\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- DeepSeek\n- Google Cloud (Antigravity)";
|
|
30
30
|
readonly queryFailed: "❌ 查询失败的账号:\n";
|
|
31
31
|
readonly openaiTitle: "## OpenAI 账号额度";
|
|
32
32
|
readonly zhipuTitle: "## 智谱 AI 账号额度";
|
|
33
33
|
readonly zaiTitle: "## Z.ai 账号额度";
|
|
34
|
+
readonly deepseekTitle: "## DeepSeek 账户余额";
|
|
34
35
|
readonly zhipuApiError: (status: number, text: string) => string;
|
|
35
36
|
readonly zaiApiError: (status: number, text: string) => string;
|
|
36
37
|
readonly zhipuTokensLimit: "5 小时 Token 限额";
|
|
37
38
|
readonly zhipuMcpLimit: "MCP 月度配额";
|
|
38
39
|
readonly zhipuAccountName: "Coding Plan";
|
|
39
40
|
readonly zaiAccountName: "Z.ai";
|
|
41
|
+
readonly deepseekApiError: (status: number, text: string) => string;
|
|
42
|
+
readonly deepseekAccountName: "API 账户";
|
|
43
|
+
readonly deepseekBalance: "账户余额";
|
|
44
|
+
readonly deepseekNoBalance: "暂无余额数据";
|
|
40
45
|
readonly noQuotaData: "暂无配额数据";
|
|
41
46
|
readonly googleTitle: "## Google Cloud 账号额度";
|
|
42
47
|
readonly googleApiError: (status: number, text: string) => string;
|
|
@@ -70,17 +75,22 @@ export declare const t: {
|
|
|
70
75
|
readonly apiError: (status: number, text: string) => string;
|
|
71
76
|
readonly timeoutError: (seconds: number) => string;
|
|
72
77
|
readonly tokenExpired: "⚠️ OAuth token expired. Please use an OpenAI model in OpenCode to refresh authorization.";
|
|
73
|
-
readonly noAccounts: "No configured accounts found.\n\nSupported account types:\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)";
|
|
78
|
+
readonly noAccounts: "No configured accounts found.\n\nSupported account types:\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- DeepSeek\n- Google Cloud (Antigravity)";
|
|
74
79
|
readonly queryFailed: "❌ Failed to query accounts:\n";
|
|
75
80
|
readonly openaiTitle: "## OpenAI Account Quota";
|
|
76
81
|
readonly zhipuTitle: "## Zhipu AI Account Quota";
|
|
77
82
|
readonly zaiTitle: "## Z.ai Account Quota";
|
|
83
|
+
readonly deepseekTitle: "## DeepSeek Account Balance";
|
|
78
84
|
readonly zhipuApiError: (status: number, text: string) => string;
|
|
79
85
|
readonly zaiApiError: (status: number, text: string) => string;
|
|
80
86
|
readonly zhipuTokensLimit: "5-hour token limit";
|
|
81
87
|
readonly zhipuMcpLimit: "MCP monthly quota";
|
|
82
88
|
readonly zhipuAccountName: "Coding Plan";
|
|
83
89
|
readonly zaiAccountName: "Z.ai";
|
|
90
|
+
readonly deepseekApiError: (status: number, text: string) => string;
|
|
91
|
+
readonly deepseekAccountName: "API account";
|
|
92
|
+
readonly deepseekBalance: "Account balance";
|
|
93
|
+
readonly deepseekNoBalance: "No balance data available";
|
|
84
94
|
readonly noQuotaData: "No quota data available";
|
|
85
95
|
readonly googleTitle: "## Google Cloud Account Quota";
|
|
86
96
|
readonly googleApiError: (status: number, text: string) => string;
|
|
@@ -99,4 +109,3 @@ export declare const t: {
|
|
|
99
109
|
readonly copilotQuotaUnavailable: string;
|
|
100
110
|
readonly copilotQuotaWorkaround: string;
|
|
101
111
|
};
|
|
102
|
-
//# sourceMappingURL=i18n.d.ts.map
|
package/dist/plugin/lib/i18n.js
CHANGED
|
@@ -50,16 +50,17 @@ const translations = {
|
|
|
50
50
|
unknown: "未知",
|
|
51
51
|
used: "已用",
|
|
52
52
|
// 错误信息
|
|
53
|
-
authError: (path, err) => `❌
|
|
53
|
+
authError: (path, err) => `❌ 无法读取 OpenCode 凭证数据库: ${path}\n错误: ${err}`,
|
|
54
54
|
apiError: (status, text) => `OpenAI API 请求失败 (${status}): ${text}`,
|
|
55
55
|
timeoutError: (seconds) => `请求超时 (${seconds}秒)`,
|
|
56
56
|
tokenExpired: "⚠️ OAuth 授权已过期,请在 OpenCode 中使用一次 OpenAI 模型以刷新授权。",
|
|
57
|
-
noAccounts: "未找到任何已配置的账号。\n\n支持的账号类型:\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)",
|
|
57
|
+
noAccounts: "未找到任何已配置的账号。\n\n支持的账号类型:\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- DeepSeek\n- Google Cloud (Antigravity)",
|
|
58
58
|
queryFailed: "❌ 查询失败的账号:\n",
|
|
59
59
|
// 平台标题
|
|
60
60
|
openaiTitle: "## OpenAI 账号额度",
|
|
61
61
|
zhipuTitle: "## 智谱 AI 账号额度",
|
|
62
62
|
zaiTitle: "## Z.ai 账号额度",
|
|
63
|
+
deepseekTitle: "## DeepSeek 账户余额",
|
|
63
64
|
// 智谱 AI 相关
|
|
64
65
|
zhipuApiError: (status, text) => `智谱 API 请求失败 (${status}): ${text}`,
|
|
65
66
|
zaiApiError: (status, text) => `Z.ai API 请求失败 (${status}): ${text}`,
|
|
@@ -67,6 +68,10 @@ const translations = {
|
|
|
67
68
|
zhipuMcpLimit: "MCP 月度配额",
|
|
68
69
|
zhipuAccountName: "Coding Plan",
|
|
69
70
|
zaiAccountName: "Z.ai",
|
|
71
|
+
deepseekApiError: (status, text) => `DeepSeek API 请求失败 (${status}): ${text}`,
|
|
72
|
+
deepseekAccountName: "API 账户",
|
|
73
|
+
deepseekBalance: "账户余额",
|
|
74
|
+
deepseekNoBalance: "暂无余额数据",
|
|
70
75
|
noQuotaData: "暂无配额数据",
|
|
71
76
|
// Google 相关
|
|
72
77
|
googleTitle: "## Google Cloud 账号额度",
|
|
@@ -111,16 +116,17 @@ const translations = {
|
|
|
111
116
|
unknown: "unknown",
|
|
112
117
|
used: "Used",
|
|
113
118
|
// 错误信息
|
|
114
|
-
authError: (path, err) => `❌ Failed to read
|
|
119
|
+
authError: (path, err) => `❌ Failed to read OpenCode credential database: ${path}\nError: ${err}`,
|
|
115
120
|
apiError: (status, text) => `OpenAI API request failed (${status}): ${text}`,
|
|
116
121
|
timeoutError: (seconds) => `Request timeout (${seconds}s)`,
|
|
117
122
|
tokenExpired: "⚠️ OAuth token expired. Please use an OpenAI model in OpenCode to refresh authorization.",
|
|
118
|
-
noAccounts: "No configured accounts found.\n\nSupported account types:\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)",
|
|
123
|
+
noAccounts: "No configured accounts found.\n\nSupported account types:\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- DeepSeek\n- Google Cloud (Antigravity)",
|
|
119
124
|
queryFailed: "❌ Failed to query accounts:\n",
|
|
120
125
|
// 平台标题
|
|
121
126
|
openaiTitle: "## OpenAI Account Quota",
|
|
122
127
|
zhipuTitle: "## Zhipu AI Account Quota",
|
|
123
128
|
zaiTitle: "## Z.ai Account Quota",
|
|
129
|
+
deepseekTitle: "## DeepSeek Account Balance",
|
|
124
130
|
// 智谱 AI 相关
|
|
125
131
|
zhipuApiError: (status, text) => `Zhipu API request failed (${status}): ${text}`,
|
|
126
132
|
zaiApiError: (status, text) => `Z.ai API request failed (${status}): ${text}`,
|
|
@@ -128,6 +134,10 @@ const translations = {
|
|
|
128
134
|
zhipuMcpLimit: "MCP monthly quota",
|
|
129
135
|
zhipuAccountName: "Coding Plan",
|
|
130
136
|
zaiAccountName: "Z.ai",
|
|
137
|
+
deepseekApiError: (status, text) => `DeepSeek API request failed (${status}): ${text}`,
|
|
138
|
+
deepseekAccountName: "API account",
|
|
139
|
+
deepseekBalance: "Account balance",
|
|
140
|
+
deepseekNoBalance: "No balance data available",
|
|
131
141
|
noQuotaData: "No quota data available",
|
|
132
142
|
// Google 相关
|
|
133
143
|
googleTitle: "## Google Cloud Account Quota",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read credentials from OpenCode V2's SQLite database.
|
|
3
|
+
*
|
|
4
|
+
* The sqlite3 CLI is used instead of adding a native Node SQLite dependency.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProviderId } from "./config";
|
|
7
|
+
import type { AuthData } from "./types";
|
|
8
|
+
/** Read active V2 credentials without modifying the database. */
|
|
9
|
+
export declare function readV2AuthData(databasePath?: string, disabledProviders?: Set<ProviderId>): Promise<AuthData>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read credentials from OpenCode V2's SQLite database.
|
|
3
|
+
*
|
|
4
|
+
* The sqlite3 CLI is used instead of adding a native Node SQLite dependency.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
const DATABASE_PATH = `${homedir()}/.local/share/opencode/opencode.db`;
|
|
11
|
+
/** Read active V2 credentials without modifying the database. */
|
|
12
|
+
export async function readV2AuthData(databasePath = DATABASE_PATH, disabledProviders = new Set()) {
|
|
13
|
+
const providerIds = [
|
|
14
|
+
"openai",
|
|
15
|
+
"zhipuai-coding-plan",
|
|
16
|
+
"zai-coding-plan",
|
|
17
|
+
"github-copilot",
|
|
18
|
+
"deepseek",
|
|
19
|
+
].filter((provider) => !disabledProviders.has(provider));
|
|
20
|
+
if (providerIds.length === 0)
|
|
21
|
+
return {};
|
|
22
|
+
const sql = `SELECT integration_id, value FROM credential WHERE (active IS NULL OR active != 0) AND integration_id IN (${providerIds.map((provider) => `'${provider}'`).join(", ")}) ORDER BY time_updated DESC;`;
|
|
23
|
+
try {
|
|
24
|
+
const { stdout } = await execFileAsync("sqlite3", ["-json", `file:${databasePath}?mode=ro`, sql], { maxBuffer: 1024 * 1024, windowsHide: true });
|
|
25
|
+
const rows = JSON.parse(stdout);
|
|
26
|
+
const authData = {};
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
if (!row.integration_id || typeof row.value !== "string")
|
|
29
|
+
continue;
|
|
30
|
+
try {
|
|
31
|
+
const value = JSON.parse(row.value);
|
|
32
|
+
if (value &&
|
|
33
|
+
typeof value === "object" &&
|
|
34
|
+
!(row.integration_id in authData)) {
|
|
35
|
+
// Integration IDs are the same provider IDs used by auth.json.
|
|
36
|
+
authData[row.integration_id] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Ignore malformed rows and continue reading other providers.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return authData;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -28,6 +28,11 @@ export interface ZhipuAuthData {
|
|
|
28
28
|
type: string;
|
|
29
29
|
key?: string;
|
|
30
30
|
}
|
|
31
|
+
/** DeepSeek API key authentication data */
|
|
32
|
+
export interface DeepSeekAuthData {
|
|
33
|
+
type: string;
|
|
34
|
+
key?: string;
|
|
35
|
+
}
|
|
31
36
|
/**
|
|
32
37
|
* GitHub Copilot 认证数据
|
|
33
38
|
*/
|
|
@@ -81,6 +86,7 @@ export interface AntigravityAccountsFile {
|
|
|
81
86
|
*/
|
|
82
87
|
export interface AuthData {
|
|
83
88
|
openai?: OpenAIAuthData;
|
|
89
|
+
deepseek?: DeepSeekAuthData;
|
|
84
90
|
"zhipuai-coding-plan"?: ZhipuAuthData;
|
|
85
91
|
"zai-coding-plan"?: ZhipuAuthData;
|
|
86
92
|
"github-copilot"?: CopilotAuthData;
|
|
@@ -89,4 +95,3 @@ export interface AuthData {
|
|
|
89
95
|
export declare const HIGH_USAGE_THRESHOLD = 80;
|
|
90
96
|
/** API 请求超时时间(毫秒) */
|
|
91
97
|
export declare const REQUEST_TIMEOUT_MS = 10000;
|
|
92
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenCode 额度状态查询插件
|
|
3
3
|
*
|
|
4
|
-
* [输入]:
|
|
4
|
+
* [输入]: OpenCode V2 SQLite 凭证和 ~/.config/opencode/antigravity-accounts.json 中的认证信息
|
|
5
5
|
* [输出]: 带进度条的额度使用情况展示
|
|
6
6
|
* [定位]: 通过 mystatus 工具查询各账号额度
|
|
7
|
-
* [同步]: lib/openai.ts, lib/zhipu.ts, lib/google.ts, lib/types.ts, lib/i18n.ts
|
|
7
|
+
* [同步]: lib/openai.ts, lib/zhipu.ts, lib/deepseek.ts, lib/google.ts, lib/types.ts, lib/i18n.ts
|
|
8
8
|
*/
|
|
9
9
|
import { Plugin } from "@opencode/plugin";
|
|
10
10
|
declare const _default: Plugin.Plugin;
|
|
11
11
|
export default _default;
|
|
12
|
-
//# sourceMappingURL=mystatus.d.ts.map
|
package/dist/plugin/mystatus.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenCode 额度状态查询插件
|
|
3
3
|
*
|
|
4
|
-
* [输入]:
|
|
4
|
+
* [输入]: OpenCode V2 SQLite 凭证和 ~/.config/opencode/antigravity-accounts.json 中的认证信息
|
|
5
5
|
* [输出]: 带进度条的额度使用情况展示
|
|
6
6
|
* [定位]: 通过 mystatus 工具查询各账号额度
|
|
7
|
-
* [同步]: lib/openai.ts, lib/zhipu.ts, lib/google.ts, lib/types.ts, lib/i18n.ts
|
|
7
|
+
* [同步]: lib/openai.ts, lib/zhipu.ts, lib/deepseek.ts, lib/google.ts, lib/types.ts, lib/i18n.ts
|
|
8
8
|
*/
|
|
9
|
-
import { readFile } from "node:fs/promises";
|
|
10
9
|
import { homedir } from "node:os";
|
|
11
10
|
import { join } from "node:path";
|
|
12
11
|
import { Plugin } from "@opencode/plugin";
|
|
12
|
+
import { isProviderEnabled, readMystatusConfig, } from "./lib/config";
|
|
13
13
|
import { queryCopilotUsage } from "./lib/copilot";
|
|
14
|
+
import { queryDeepSeekUsage } from "./lib/deepseek";
|
|
14
15
|
import { queryGoogleUsage } from "./lib/google";
|
|
15
16
|
import { t } from "./lib/i18n";
|
|
16
17
|
import { queryOpenAIUsage } from "./lib/openai";
|
|
18
|
+
import { readV2AuthData } from "./lib/opencode-auth";
|
|
17
19
|
import { queryZaiUsage, queryZhipuUsage } from "./lib/zhipu";
|
|
18
20
|
// ============================================================================
|
|
19
21
|
// V2 插件导出
|
|
@@ -24,32 +26,54 @@ export default Plugin.define({
|
|
|
24
26
|
await ctx.tool.transform((editor) => {
|
|
25
27
|
editor.add({
|
|
26
28
|
name: "mystatus",
|
|
27
|
-
description: "Query account quota usage for all configured AI platforms. Returns remaining quota percentages, usage stats, and reset countdowns
|
|
29
|
+
description: "Query account quota usage for all configured AI platforms. Returns remaining quota percentages, usage stats, balances, and reset countdowns. Currently supports OpenAI (ChatGPT/Codex), Zhipu AI, Z.ai, DeepSeek, Google Antigravity, and GitHub Copilot.",
|
|
28
30
|
input: {
|
|
29
31
|
type: "object",
|
|
30
32
|
properties: {},
|
|
31
33
|
additionalProperties: false,
|
|
32
34
|
},
|
|
33
35
|
async execute() {
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
// V2 stores credentials and refreshed OAuth tokens in SQLite.
|
|
37
|
+
const databasePath = join(homedir(), ".local/share/opencode/opencode.db");
|
|
38
|
+
const disabledProviders = await readMystatusConfig();
|
|
39
|
+
const authData = await readV2AuthData(databasePath, disabledProviders);
|
|
40
|
+
const providers = [
|
|
41
|
+
"openai",
|
|
42
|
+
"zhipuai-coding-plan",
|
|
43
|
+
"zai-coding-plan",
|
|
44
|
+
"deepseek",
|
|
45
|
+
"google",
|
|
46
|
+
"github-copilot",
|
|
47
|
+
];
|
|
48
|
+
const hasEnabledProvider = providers.some((provider) => isProviderEnabled(disabledProviders, provider));
|
|
49
|
+
if (!hasEnabledProvider)
|
|
50
|
+
return { content: t.noAccounts };
|
|
51
|
+
if (Object.keys(authData).length === 0 &&
|
|
52
|
+
!isProviderEnabled(disabledProviders, "google")) {
|
|
42
53
|
return {
|
|
43
|
-
content: t.authError(
|
|
54
|
+
content: t.authError(databasePath, "OpenCode V2 credentials were not found in the credential table"),
|
|
44
55
|
};
|
|
45
56
|
}
|
|
46
57
|
// 2. 并行查询所有平台(Google 不依赖 authData)
|
|
47
|
-
const [openaiResult, zhipuResult, zaiResult, googleResult, copilotResult,] = await Promise.all([
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
const [openaiResult, zhipuResult, zaiResult, deepseekResult, googleResult, copilotResult,] = await Promise.all([
|
|
59
|
+
isProviderEnabled(disabledProviders, "openai")
|
|
60
|
+
? queryOpenAIUsage(authData.openai)
|
|
61
|
+
: null,
|
|
62
|
+
isProviderEnabled(disabledProviders, "zhipuai-coding-plan")
|
|
63
|
+
? queryZhipuUsage(authData["zhipuai-coding-plan"])
|
|
64
|
+
: null,
|
|
65
|
+
isProviderEnabled(disabledProviders, "zai-coding-plan")
|
|
66
|
+
? queryZaiUsage(authData["zai-coding-plan"])
|
|
67
|
+
: null,
|
|
68
|
+
isProviderEnabled(disabledProviders, "deepseek")
|
|
69
|
+
? queryDeepSeekUsage(authData.deepseek)
|
|
70
|
+
: null,
|
|
71
|
+
isProviderEnabled(disabledProviders, "google")
|
|
72
|
+
? queryGoogleUsage()
|
|
73
|
+
: null,
|
|
74
|
+
isProviderEnabled(disabledProviders, "github-copilot")
|
|
75
|
+
? queryCopilotUsage(authData["github-copilot"])
|
|
76
|
+
: null,
|
|
53
77
|
]);
|
|
54
78
|
// 3. 收集结果
|
|
55
79
|
const results = [];
|
|
@@ -60,6 +84,8 @@ export default Plugin.define({
|
|
|
60
84
|
collectResult(zhipuResult, t.zhipuTitle, results, errors);
|
|
61
85
|
// 处理 Z.ai 结果
|
|
62
86
|
collectResult(zaiResult, t.zaiTitle, results, errors);
|
|
87
|
+
// 处理 DeepSeek 结果
|
|
88
|
+
collectResult(deepseekResult, t.deepseekTitle, results, errors);
|
|
63
89
|
// 处理 Google 结果
|
|
64
90
|
collectResult(googleResult, t.googleTitle, results, errors);
|
|
65
91
|
// 处理 GitHub Copilot 结果
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekworp/opencode-mystatus",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
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",
|
|
@@ -17,6 +17,17 @@
|
|
|
17
17
|
"README.md",
|
|
18
18
|
"LICENSE"
|
|
19
19
|
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"test": "pnpm build && node --loader ./tests/extension-loader.mjs --test tests/*.test.js",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"lint": "biome check .",
|
|
25
|
+
"lint:fix": "biome check --write .",
|
|
26
|
+
"format": "biome format --write .",
|
|
27
|
+
"prepublishOnly": "pnpm run lint && pnpm run build",
|
|
28
|
+
"publish:npm": "npm publish --access public --registry=https://registry.npmjs.org",
|
|
29
|
+
"prepare": "husky"
|
|
30
|
+
},
|
|
20
31
|
"keywords": [
|
|
21
32
|
"opencode",
|
|
22
33
|
"plugin",
|
|
@@ -54,12 +65,5 @@
|
|
|
54
65
|
},
|
|
55
66
|
"engines": {
|
|
56
67
|
"node": ">=18.0.0"
|
|
57
|
-
},
|
|
58
|
-
"scripts": {
|
|
59
|
-
"build": "tsc",
|
|
60
|
-
"typecheck": "tsc --noEmit",
|
|
61
|
-
"lint": "biome check .",
|
|
62
|
-
"lint:fix": "biome check --write .",
|
|
63
|
-
"format": "biome format --write ."
|
|
64
68
|
}
|
|
65
|
-
}
|
|
69
|
+
}
|