Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ An [OpenCode](https://opencode.ai) plugin to query account quota usage for multi

## Supported Platforms

| Platform | Account Type | Data Source |
| ------------ | ----------------- | ---------------------------------------------- |
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/auth.json` |
| Zhipu AI | Coding Plan | `~/.local/share/opencode/auth.json` |
| Z.ai | Coding Plan | `~/.local/share/opencode/auth.json` |
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/auth.json` |
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |
| Platform | Account Type | Data Source |
| ------------ | --------------------------- | ---------------------------------------------- |
| Anthropic | Claude Code / Pro / Max | `~/.local/share/opencode/auth.json` |
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/auth.json` |
| Zhipu AI | Coding Plan | `~/.local/share/opencode/auth.json` |
| Z.ai | Coding Plan | `~/.local/share/opencode/auth.json` |
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/auth.json` |
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |

## Installation

Expand Down Expand Up @@ -104,6 +105,18 @@ OpenCode will automatically use the mystatus tool to answer your question.
## Output Example

```
## Anthropic Account Quota

Account: Claude

5-hour limit
██████████████████████████░░░░ 86% remaining
Resets in: 4h 42m

7-day limit
█████████████████████████████░ 96% remaining
Resets in: 6d 23h 42m

## OpenAI Account Quota

Account: user@example.com (team)
Expand Down Expand Up @@ -161,9 +174,13 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░

No additional configuration required. The plugin automatically reads credentials from:

- **OpenAI, Zhipu AI, Z.ai & GitHub Copilot**: `~/.local/share/opencode/auth.json`
- **Anthropic, OpenAI, Zhipu AI, Z.ai & GitHub Copilot**: `~/.local/share/opencode/auth.json`
- **Google Cloud**: `~/.config/opencode/antigravity-accounts.json`

### Anthropic Setup

To query Anthropic quota, install and authenticate [opencode-claude-auth](https://github.com/griffinmartin/opencode-claude-auth) first so Claude OAuth credentials are synced into OpenCode auth storage.

### Google Cloud Setup

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.
Expand All @@ -177,8 +194,9 @@ This plugin is safe to use:
- `~/.local/share/opencode/auth.json` - OpenCode's official auth storage
- `~/.config/opencode/antigravity-accounts.json` - Antigravity plugin's account storage

**API Endpoints (all official):**
**API Endpoints:**

- `https://api.anthropic.com/api/oauth/usage` - Anthropic OAuth quota endpoint
- `https://chatgpt.com/backend-api/wham/usage` - OpenAI official quota API
- `https://bigmodel.cn/api/monitor/usage/quota/limit` - Zhipu AI official quota API
- `https://api.z.ai/api/monitor/usage/quota/limit` - Z.ai official quota API
Expand All @@ -192,6 +210,10 @@ This plugin is safe to use:
- Sensitive information (API keys) is automatically masked in output
- Source code is fully open for review

### Anthropic Notes

Anthropic quota support relies on OAuth credentials made available by Claude Code / [opencode-claude-auth](https://github.com/griffinmartin/opencode-claude-auth) and a private quota endpoint. It may change if Anthropic changes their OAuth infrastructure.

## Google Cloud Models

The plugin displays quota for these models:
Expand Down
40 changes: 31 additions & 9 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@

## 支持的平台

| 平台 | 账号类型 | 数据来源 |
| ------------ | ----------------- | ---------------------------------------------- |
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/auth.json` |
| 智谱 AI | Coding Plan | `~/.local/share/opencode/auth.json` |
| Z.ai | Coding Plan | `~/.local/share/opencode/auth.json` |
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/auth.json` |
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |
| 平台 | 账号类型 | 数据来源 |
| ------------ | ---------------------------- | ---------------------------------------------- |
| Anthropic | Claude Code / Pro / Max | `~/.local/share/opencode/auth.json` |
| OpenAI | Plus / Team / Pro | `~/.local/share/opencode/auth.json` |
| 智谱 AI | Coding Plan | `~/.local/share/opencode/auth.json` |
| Z.ai | Coding Plan | `~/.local/share/opencode/auth.json` |
| GitHub Copilot | Individual / Business | `~/.local/share/opencode/auth.json` |
| Google Cloud | Antigravity | `~/.config/opencode/antigravity-accounts.json` |

## 安装

Expand Down Expand Up @@ -104,6 +105,18 @@ OpenCode 会自动调用 mystatus 工具来回答你的问题。
## 输出示例

```
## Anthropic 账号额度

Account: Claude

5小时限额
██████████████████████████░░░░ 剩余 86%
重置: 4小时42分钟后

7天限额
█████████████████████████████░ 剩余 96%
重置: 6天23小时42分钟后

## OpenAI 账号额度

Account: user@example.com (team)
Expand Down Expand Up @@ -161,9 +174,13 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░

无需额外配置。插件自动从以下位置读取认证信息:

- **OpenAI、智谱 AI、Z.ai 和 GitHub Copilot**: `~/.local/share/opencode/auth.json`
- **Anthropic、OpenAI、智谱 AI、Z.ai 和 GitHub Copilot**: `~/.local/share/opencode/auth.json`
- **Google Cloud**: `~/.config/opencode/antigravity-accounts.json`

### Anthropic 设置

如需查询 Anthropic 额度,请先安装并完成 [opencode-claude-auth](https://github.com/griffinmartin/opencode-claude-auth) 认证,让 Claude OAuth 凭据同步到 OpenCode 的认证存储中。

### Google Cloud 设置

如需查询 Google Cloud (Antigravity) 账号额度,需要先安装 [opencode-antigravity-auth](https://github.com/NoeFabris/opencode-antigravity-auth) 插件来完成 Google 账号认证。
Expand All @@ -177,8 +194,9 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
- `~/.local/share/opencode/auth.json` - OpenCode 官方认证存储
- `~/.config/opencode/antigravity-accounts.json` - Antigravity 插件的账号存储

**请求的 API 接口(均为官方接口):**
**请求的 API 接口:**

- `https://api.anthropic.com/api/oauth/usage` - Anthropic OAuth 额度接口
- `https://chatgpt.com/backend-api/wham/usage` - OpenAI 官方额度查询接口
- `https://bigmodel.cn/api/monitor/usage/quota/limit` - 智谱 AI 官方额度查询接口
- `https://api.z.ai/api/monitor/usage/quota/limit` - Z.ai 官方额度查询接口
Expand All @@ -192,6 +210,10 @@ Claude 2d 9h ░░░░░░░░░░░░░░░░░░░
- 敏感信息(API Key)在输出时自动脱敏显示
- 源代码完全开源,可随时审查

### Anthropic 说明

Anthropic 额度支持依赖 Claude Code / [opencode-claude-auth](https://github.com/griffinmartin/opencode-claude-auth) 提供的 OAuth 凭据以及一个私有额度接口。如果 Anthropic 调整 OAuth 基础设施,这部分功能可能会失效。

## Google Cloud 模型

插件显示以下模型的额度:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "opencode-mystatus",
"version": "1.2.4",
"description": "Check all your AI subscription quotas in one command. Supports OpenAI, Zhipu AI, Z.ai, and Google Antigravity. More platforms coming soon.",
"description": "Check all your AI subscription quotas in one command. Supports Anthropic, OpenAI, Zhipu AI, Z.ai, GitHub Copilot, and Google Antigravity.",
"type": "module",
"main": "dist/plugin/mystatus.js",
"types": "dist/plugin/mystatus.d.ts",
Expand Down
133 changes: 133 additions & 0 deletions plugin/lib/anthropic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { t } from "./i18n";
import { type AnthropicAuthData, type QueryResult } from "./types";
import {
calcRemainPercent,
createProgressBar,
fetchWithTimeout,
formatDuration,
getResetAfterSeconds,
} from "./utils";

interface AnthropicUsageWindow {
utilization: number;
resets_at?: string;
}

interface AnthropicExtraUsage {
is_enabled?: boolean;
used_credits?: number;
monthly_limit?: number;
}

interface AnthropicUsageResponse {
five_hour?: AnthropicUsageWindow;
seven_day?: AnthropicUsageWindow;
extra_usage?: AnthropicExtraUsage;
}

const ANTHROPIC_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
const ANTHROPIC_BETA = "oauth-2025-04-20";

function formatCredits(cents: number): string {
return `$${(cents / 100).toFixed(2)}`;
}

function formatWindow(
title: string,
window: AnthropicUsageWindow | undefined,
): string[] {
if (!window)
return [];

const remainPercent = calcRemainPercent(window.utilization);
const progressBar = createProgressBar(remainPercent);
const lines = [title, `${progressBar} ${t.remaining(remainPercent)}`];
const resetAfterSeconds = getResetAfterSeconds(window.resets_at);

if (resetAfterSeconds !== null) {
lines.push(t.resetIn(formatDuration(resetAfterSeconds)));
}

return lines;
}

async function fetchAnthropicUsage(
accessToken: string,
): Promise<AnthropicUsageResponse> {
const response = await fetchWithTimeout(ANTHROPIC_USAGE_URL, {
headers: {
Authorization: `Bearer ${accessToken}`,
"anthropic-beta": ANTHROPIC_BETA,
"Content-Type": "application/json",
"User-Agent": "OpenCode-Status-Plugin/1.0",
},
});

if (!response.ok) {
const errorText = await response.text();
throw new Error(t.anthropicApiError(response.status, errorText));
}

return response.json() as Promise<AnthropicUsageResponse>;
}

function formatAnthropicUsage(data: AnthropicUsageResponse): string {
const lines: string[] = [];

lines.push(`${t.account} ${t.anthropicAccountName}`);

const fiveHourLines = formatWindow(t.fiveHourLimit, data.five_hour);
const sevenDayLines = formatWindow(t.sevenDayLimit, data.seven_day);

if (fiveHourLines.length > 0) {
lines.push("");
lines.push(...fiveHourLines);
}

if (sevenDayLines.length > 0) {
lines.push("");
lines.push(...sevenDayLines);
}

if (data.extra_usage?.is_enabled && data.extra_usage.monthly_limit) {
lines.push("");
lines.push(
`${t.extraUsage}: ${formatCredits(data.extra_usage.used_credits || 0)} / ${formatCredits(data.extra_usage.monthly_limit)}`,
);
}

if (lines.length === 1) {
lines.push("");
lines.push(t.noQuotaData);
}

return lines.join("\n");
}

export async function queryAnthropicUsage(
authData: AnthropicAuthData | undefined,
): Promise<QueryResult | null> {
if (!authData || authData.type !== "oauth" || !authData.access) {
return null;
}

if (authData.expires && authData.expires < Date.now()) {
return {
success: false,
error: t.anthropicTokenExpired,
};
}

try {
const usage = await fetchAnthropicUsage(authData.access);
return {
success: true,
output: formatAnthropicUsage(usage),
};
} catch (err) {
return {
success: false,
error: err instanceof Error ? err.message : String(err),
};
}
}
22 changes: 20 additions & 2 deletions plugin/lib/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ const translations = {
// 限额相关
hourLimit: (h: number) => `${h}小时限额`,
dayLimit: (d: number) => `${d}天限额`,
fiveHourLimit: "5小时限额",
sevenDayLimit: "7天限额",
remaining: (p: number) => `剩余 ${p}%`,
resetIn: (t: string) => `重置: ${t}后`,
limitReached: "⚠️ 已达到限额上限!",
extraUsage: "额外用量",

// 通用
account: "Account:",
Expand All @@ -67,17 +70,23 @@ const translations = {
`❌ 无法读取认证文件: ${path}\n错误: ${err}`,
apiError: (status: number, text: string) =>
`OpenAI API 请求失败 (${status}): ${text}`,
anthropicApiError: (status: number, text: string) =>
`Anthropic API 请求失败 (${status}): ${text}`,
timeoutError: (seconds: number) => `请求超时 (${seconds}秒)`,
tokenExpired:
"⚠️ OAuth 授权已过期,请在 OpenCode 中使用一次 OpenAI 模型以刷新授权。",
anthropicTokenExpired:
"⚠️ Claude OAuth 授权已过期,请在 OpenCode 中使用一次 Anthropic 模型以刷新授权。",
noAccounts:
"未找到任何已配置的账号。\n\n支持的账号类型:\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- Google Cloud (Antigravity)",
"未找到任何已配置的账号。\n\n支持的账号类型:\n- Anthropic (Claude Code / Pro / Max)\n- OpenAI (Plus/Team/Pro 订阅用户)\n- 智谱 AI (Coding Plan)\n- Z.ai (Coding Plan)\n- GitHub Copilot\n- Google Cloud (Antigravity)",
queryFailed: "❌ 查询失败的账号:\n",

// 平台标题
anthropicTitle: "## Anthropic 账号额度",
openaiTitle: "## OpenAI 账号额度",
zhipuTitle: "## 智谱 AI 账号额度",
zaiTitle: "## Z.ai 账号额度",
anthropicAccountName: "Claude",

// 智谱 AI 相关
zhipuApiError: (status: number, text: string) =>
Expand Down Expand Up @@ -131,9 +140,12 @@ const translations = {
// 限额相关
hourLimit: (h: number) => `${h}-hour limit`,
dayLimit: (d: number) => `${d}-day limit`,
fiveHourLimit: "5-hour limit",
sevenDayLimit: "7-day limit",
remaining: (p: number) => `${p}% remaining`,
resetIn: (t: string) => `Resets in: ${t}`,
limitReached: "⚠️ Rate limit reached!",
extraUsage: "Extra usage",

// 通用
account: "Account:",
Expand All @@ -145,17 +157,23 @@ const translations = {
`❌ Failed to read auth file: ${path}\nError: ${err}`,
apiError: (status: number, text: string) =>
`OpenAI API request failed (${status}): ${text}`,
anthropicApiError: (status: number, text: string) =>
`Anthropic API request failed (${status}): ${text}`,
timeoutError: (seconds: number) => `Request timeout (${seconds}s)`,
tokenExpired:
"⚠️ OAuth token expired. Please use an OpenAI model in OpenCode to refresh authorization.",
anthropicTokenExpired:
"⚠️ Claude OAuth token expired. Please use an Anthropic model in OpenCode to refresh authorization.",
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)",
"No configured accounts found.\n\nSupported account types:\n- Anthropic (Claude Code / Pro / Max)\n- OpenAI (Plus/Team/Pro subscribers)\n- Zhipu AI (Coding Plan)\n- Z.ai (Coding Plan)\n- GitHub Copilot\n- Google Cloud (Antigravity)",
queryFailed: "❌ Failed to query accounts:\n",

// 平台标题
anthropicTitle: "## Anthropic Account Quota",
openaiTitle: "## OpenAI Account Quota",
zhipuTitle: "## Zhipu AI Account Quota",
zaiTitle: "## Z.ai Account Quota",
anthropicAccountName: "Claude",

// 智谱 AI 相关
zhipuApiError: (status: number, text: string) =>
Expand Down
11 changes: 11 additions & 0 deletions plugin/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export interface OpenAIAuthData {
expires?: number;
}

/**
* Anthropic OAuth 认证数据
*/
export interface AnthropicAuthData {
type: string;
access?: string;
refresh?: string;
expires?: number;
}

/**
* 智谱 AI API 认证数据
*/
Expand Down Expand Up @@ -97,6 +107,7 @@ export interface AntigravityAccountsFile {
* 完整认证数据结构
*/
export interface AuthData {
anthropic?: AnthropicAuthData;
openai?: OpenAIAuthData;
"zhipuai-coding-plan"?: ZhipuAuthData;
"zai-coding-plan"?: ZhipuAuthData;
Expand Down
Loading