[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-77810":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":12,"stars90d":14,"forks30d":14,"starsTrendScore":12,"compositeScore":15,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":14,"starSnapshotCount":14,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},77810,"UsageBoard","marsmay\u002FUsageBoard","marsmay","macOS menu bar app for aggregating API usage quotas via plugin scripts",null,"Swift",126,9,1,0,3,7,"MIT License",false,"main",true,[],"2026-06-12 02:03:44","# UsageBoard\n\n**[English](README_EN.md)**\n\nUsageBoard 是一个原生 macOS 菜单栏应用，用于聚合展示 API、模型服务、搜索服务、代理服务等各类用量配额。每个数据源都以插件形式存在，主程序负责定时执行插件、解析 stdout JSON，并以进度条展示用量。\n\n## 功能特性\n\n- 菜单栏常驻，点击图标打开快速预览。\n- 支持分组展示和标签页展示。\n- 支持手动刷新、定时刷新、单卡片刷新、退出按钮。\n- 系统休眠时暂停定时刷新，唤醒后继续调度。\n- 插件化用量查询，插件可独立配置刷新间隔和参数。\n- 插件图标支持，从元数据配置加载远程图片并缓存。\n- 订阅级别徽章显示（黑底白字圆角标签）。\n- 插件设置界面从脚本元数据自动生成参数表单，支持分段选择控件和目录选择器。\n- 新增插件默认不启用，启用前会检查必填参数。\n- 插件数据按 `stateID` 缓存到磁盘，启动后可展示上次成功数据。\n- 首次启动会把内置插件安装到用户插件目录。\n- 设置页支持开机启动、插件拖拽排序、插件帮助文档、检查更新和在线更新。\n- 用量展示支持百分比或数字占比，支持重置时间、进度条颜色和可选 token 统计图。\n- 插件可用 `{\"error\": \"错误信息\"}` 返回失败原因，错误会直接显示在卡片内容区。\n- 支持中英文切换，App UI 和插件元数据均可按语言展示。\n\n## 截图\n\n\u003Ctable>\n  \u003Ctr>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Ftabs-claude.jpg\" alt=\"Claude 标签页\" width=\"360\" \u002F>\u003C\u002Ftd>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Ftabs-minimax.jpg\" alt=\"MiniMax 标签页\" width=\"360\" \u002F>\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd align=\"center\">Claude 标签页\u003C\u002Ftd>\n    \u003Ctd align=\"center\">MiniMax 标签页\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Fgrouped.jpg\" alt=\"分组展示\" width=\"360\" \u002F>\u003C\u002Ftd>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Fgrouped-glm.jpg\" alt=\"展开统计图\" width=\"360\" \u002F>\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd align=\"center\">分组展示\u003C\u002Ftd>\n    \u003Ctd align=\"center\">分组展开统计 GLM\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Fgrouped-codex.jpg\" alt=\"Codex 统计图\" width=\"360\" \u002F>\u003C\u002Ftd>\n    \u003Ctd>\u003Cimg src=\"Screenshots\u002Fsettings.jpg\" alt=\"插件设置\" width=\"360\" \u002F>\u003C\u002Ftd>\n  \u003C\u002Ftr>\n  \u003Ctr>\n    \u003Ctd align=\"center\">分组展开统计 Codex\u003C\u002Ftd>\n    \u003Ctd align=\"center\">插件设置\u003C\u002Ftd>\n  \u003C\u002Ftr>\n\u003C\u002Ftable>\n\n## 内置插件\n\n| 插件 | 脚本 | 用途 |\n| --- | --- | --- |\n| 智谱 | `glm-usage-plugin.py` | 查询智谱 \u002F ZAI Coding Plan 用量和统计 |\n| Claude | `claude-usage-plugin.py` | 查询 Claude 订阅用量和统计 |\n| Codex | `codex-usage-plugin.py` | 查询 OpenAI Codex CLI 用量和统计 |\n| MiniMax | `minimax-usage-plugin.py` | 查询 MiniMax Coding Plan 用量 |\n| DeepSeek | `deepseek-usage-plugin.py` | 查询 DeepSeek 账户余额 |\n| Tavily | `tavily-usage-plugin.py` | 查询 Tavily Search 月度用量 |\n\n内置插件源文件位于 [Resources\u002FBundledPlugins](Resources\u002FBundledPlugins)，其中 `_common.py` 是插件共享的公共模块，提供参数解析、翻译、HTTP 错误处理等工具函数。打包后它们会位于 app 包的 `Contents\u002FResources\u002FPlugins\u002F`。\n\n## 运行时目录\n\nUsageBoard 默认使用：\n\n```text\n~\u002FLibrary\u002FApplication Support\u002FUsageBoard\u002F\n```\n\n目录内容：\n\n- `config.json`：主配置文件。\n- `plugins\u002F`：用户插件目录。添加插件时文件选择器默认打开这里。\n- `states\u002F`：插件数据缓存目录。\n\n当前实现会在启动时向 `plugins\u002F` 目录创建内置插件的同名符号链接（以 `_` 开头的内部模块文件除外），来源是 app 包内的 `Contents\u002FResources\u002FPlugins\u002F`，开发运行时则 fallback 到项目的 `Resources\u002FBundledPlugins\u002F`。\n\n## 配置文件\n\n主配置 JSON 当前结构：\n\n```json\n{\n  \"schemaVersion\": 1,\n  \"language\": \"zh-Hans\",\n  \"overviewDisplayMode\": \"tabs\",\n  \"launchAtLogin\": false,\n  \"plugins\": [\n    {\n      \"stateID\": \"stable-cache-id\",\n      \"name\": \"Example\",\n      \"enabled\": false,\n      \"executablePath\": \"~\u002FLibrary\u002FApplication Support\u002FUsageBoard\u002Fplugins\u002Fexample-plugin.py\",\n      \"refreshIntervalSeconds\": 300,\n      \"metadata\": {\n        \"name\": \"Example\",\n        \"description\": \"示例插件\",\n        \"description@zh-Hans\": \"示例插件\",\n        \"description@en\": \"Example plugin\",\n        \"parameters\": [\n          {\n            \"name\": \"API_KEY\",\n            \"label\": \"Api Key\",\n            \"label@zh-Hans\": \"Api Key\",\n            \"label@en\": \"API Key\",\n            \"type\": \"secret\",\n            \"required\": true,\n            \"placeholder\": \"Service API Key\"\n          },\n          {\n            \"name\": \"STAT_PERIOD\",\n            \"label\": \"统计周期\",\n            \"label@zh-Hans\": \"统计周期\",\n            \"label@en\": \"Stats Period\",\n            \"type\": \"choice\",\n            \"required\": true,\n            \"defaultValue\": \"7d\",\n            \"options\": [\n              {\"label\": \"7 天\", \"label@zh-Hans\": \"7 天\", \"label@en\": \"7 days\", \"value\": \"7d\"},\n              {\"label\": \"15 天\", \"label@zh-Hans\": \"15 天\", \"label@en\": \"15 days\", \"value\": \"15d\"},\n              {\"label\": \"30 天\", \"label@zh-Hans\": \"30 天\", \"label@en\": \"30 days\", \"value\": \"30d\"}\n            ]\n          }\n        ]\n      },\n      \"parameterValues\": {\n        \"API_KEY\": \"\",\n        \"STAT_PERIOD\": \"7d\"\n      }\n    }\n  ]\n}\n```\n\n说明：\n\n- `overviewDisplayMode` 支持 `grouped` 和 `tabs`。\n- `language` 支持 `zh-Hans` 和 `en`，修改后重启生效。\n- `launchAtLogin` 控制开机启动。\n- `plugins[].stateID` 是插件缓存 ID，会持久化。\n- `plugins[].enabled` 为 `false` 时不执行插件。\n- `plugins[].metadata` 通常由插件脚本头部注释块解析生成。\n- `plugins[].parameterValues` 保存设置界面填写的插件参数。\n\n## 插件开发\n\n插件推荐使用 Python 脚本。主程序执行 `.py` 插件时使用：\n\n```text\n\u002Fusr\u002Fbin\u002Fenv python3 \u002Fpath\u002Fto\u002Fplugin.py --usageboard-param KEY=value --usageboard-param USAGEBOARD_LANGUAGE=zh-Hans\n```\n\n插件必须向 stdout 输出 UsageBoard 可解析的 JSON。stderr 可用于调试；退出码非 0、超时或 stdout 非法 JSON 都会显示为插件错误。插件也可以向 stdout 输出 `{\"error\": \"错误信息\"}` 表示失败，UsageBoard 会把该错误展示在插件卡片内容区。\n\n更完整的说明见 [插件编写说明](Resources\u002FPluginAuthoringGuide.html)。\n\n### 参数元数据\n\n在脚本开头放入 `UsageBoardPlugin` 注释块，UsageBoard 会读取它并生成设置表单：\n\n```python\n#!\u002Fusr\u002Fbin\u002Fenv python3\n# UsageBoardPlugin:\n# {\n#   \"name\": \"Example\",\n#   \"icon\": \"https:\u002F\u002Fexample.com\u002Ficon.png\",\n#   \"description\": \"示例插件\",\n#   \"description@zh-Hans\": \"示例插件\",\n#   \"description@en\": \"Example plugin\",\n#   \"parameters\": [\n#     {\n#       \"name\": \"API_KEY\",\n#       \"label\": \"Api Key\",\n#       \"label@zh-Hans\": \"Api Key\",\n#       \"label@en\": \"API Key\",\n#       \"type\": \"secret\",\n#       \"required\": true,\n#       \"placeholder\": \"Service API Key\"\n#     },\n#     {\n#       \"name\": \"STAT_PERIOD\",\n#       \"label\": \"统计周期\",\n#       \"label@zh-Hans\": \"统计周期\",\n#       \"label@en\": \"Stats Period\",\n#       \"type\": \"choice\",\n#       \"required\": true,\n#       \"defaultValue\": \"7d\",\n#       \"options\": [\n#         {\"label\": \"7 天\", \"label@zh-Hans\": \"7 天\", \"label@en\": \"7 days\", \"value\": \"7d\"},\n#         {\"label\": \"15 天\", \"label@zh-Hans\": \"15 天\", \"label@en\": \"15 days\", \"value\": \"15d\"},\n#         {\"label\": \"30 天\", \"label@zh-Hans\": \"30 天\", \"label@en\": \"30 days\", \"value\": \"30d\"}\n#       ]\n#     }\n#   ]\n# }\n# \u002FUsageBoardPlugin\n```\n\n涉及展示的插件元数据字段支持同级多语言字段，例如 `name@zh-Hans`、`name@en`、`description@zh-Hans`、`description@en`、`label@zh-Hans`、`label@en`、`placeholder@zh-Hans`、`placeholder@en`。当前语言对应字段缺失或为空时，UsageBoard 会回退到不带语言后缀的基础字段。\n\n支持的参数类型：\n\n- `string`\n- `secret`\n- `integer`\n- `boolean`\n- `choice`\n- `directory`\n- `file`\n\n`choice` 参数在设置页显示为分段控件；`directory` 参数显示为路径输入框和文件夹选择器；`file` 参数显示为路径输入框和文件选择器。\n\n插件读取参数示例：\n\n```python\nfrom _common import parse_usageboard_params, get_app_language, make_translator, success, failure\n\ndef main():\n    params = parse_usageboard_params(sys.argv[1:])\n    language = get_app_language(sys.argv[1:])\n    translate = make_translator({\n        \"my_plugin_name\": {\"zh-Hans\": \"我的插件\", \"en\": \"My Plugin\"},\n    })\n\n    api_key = params.get(\"API_KEY\")\n    if not api_key:\n        return failure(translate(language, \"missing_api_key\"))\n\n    # ... 调用 API ...\n    return success(items)\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n```\n\n`_common.py` 提供了参数解析（`parse_usageboard_params`）、语言检测（`get_app_language`）、翻译工厂（`make_translator`）、输出函数（`success`\u002F`failure`）、颜色\u002F状态计算（`color_for`\u002F`status_for`\u002F`numeric`）以及统一的 HTTP 错误处理（`handle_http_error`\u002F`handle_url_error`）。新插件应直接引用这些工具，不要重复实现。完整的公共函数列表见 `_common.py` 源码。\n\nUsageBoard 会额外传入当前 app 语言参数：`--usageboard-param USAGEBOARD_LANGUAGE=zh-Hans` 或 `--usageboard-param USAGEBOARD_LANGUAGE=en`。脚本应读取这个保留参数，并直接返回对应语言的展示文本。\n\n### 返回数据格式\n\n```json\n{\n  \"updatedAt\": \"2026-04-29T00:00:00Z\",\n  \"items\": [\n    {\n      \"id\": \"requests\",\n      \"name\": \"Requests\",\n      \"used\": 1200,\n      \"limit\": 1500,\n      \"displayStyle\": \"ratio\",\n      \"resetAt\": \"2026-04-29T05:00:00Z\",\n      \"status\": \"normal\",\n      \"color\": \"blue\"\n    }\n  ],\n  \"badge\": \"PRO\",\n  \"chart\": {\n    \"kind\": \"line\",\n    \"period\": \"30d\",\n    \"bucketUnit\": \"day\",\n    \"buckets\": [\n      {\n        \"id\": \"2026-05-01\",\n        \"label\": \"05-01\",\n        \"segments\": [\n          {\"model\": \"glm-4.5\", \"tokens\": 1200},\n          {\"model\": \"glm-4.6\", \"tokens\": 800}\n        ]\n      }\n    ],\n    \"message\": null\n  }\n}\n```\n\n失败时也可以返回：\n\n```json\n{\n  \"error\": \"API Key 无效，请检查配置\"\n}\n```\n\n字段说明：\n\n- `updatedAt`：插件数据更新时间，ISO 8601 格式。\n- `items[].id`：用量项目稳定 ID。\n- `items[].name`：界面显示名称。\n- `items[].used` \u002F `items[].limit`：已用量和总额度。\n- `items[].displayStyle`：`percent` 显示百分比，`ratio` 显示数字占比。\n- `items[].resetAt`：可选重置时间，ISO 8601 格式。\n- `items[].status`：`normal`、`warning`、`critical`、`unknown`。\n- `items[].color`：可选进度条颜色，支持 `blue`、`yellow`、`orange`、`red`、`green`，缺省蓝色。\n- `badge`：可选字符串，显示在插件卡片标题旁的黑色圆角徽章中（白色大写加粗文字）。\n- `chart`：可选 token 统计图，当前支持 `kind: \"line\"`。\n- `chart.period`：统计周期标识，例如 `7d`、`15d`、`30d`。\n- `chart.bucketUnit`：时间桶单位，支持 `hour` 或 `day`。\n- `chart.buckets[].segments[]`：每个时间桶的模型分段，包含 `model` 和 `tokens`。\n- `chart.message`：可选提示文案，统计数据为空或不可用时显示。\n- `error`：可选顶层错误信息；存在且非空时，该插件本次运行会被视为失败，错误文本显示在卡片内容区。\n\n内置智谱、Claude 和 Codex 插件提供 `STAT_PERIOD` 参数，支持 `7d`、`15d`、`30d`。智谱插件统一使用国内站 API 查询，兼容智谱和 ZAI 的 Coding Plan Key。Claude 插件通过 OAuth API 获取订阅用量，支持 `CLAUDE_ONLY` 开关过滤第三方模型，并可通过 `DATA_DIR` 指定 `~\u002F.claude` 数据目录。Codex 插件通过 `DATA_DIR` 参数指定数据目录（默认 `~\u002F.codex`），从中读取 `auth.json` 获取认证令牌，并解析会话文件生成 token 统计。Claude 和 Codex 插件使用增量缓存策略，缓存存放在数据目录中，且每次运行都会重新扫描当天数据。DeepSeek 插件提供 `LIMIT` 参数用于设置余额展示上限，并按余额占上限比例显示进度条颜色。\n\n## 安装\n\n通过 Homebrew 安装：\n\n```bash\nbrew tap marsmay\u002Fusageboard\nbrew install --cask usageboard\n```\n\n首次打开时，macOS 可能提示\"无法验证开发者\"。在\"系统设置 → 隐私与安全性\"中点击\"仍要打开\"，或在终端执行：\n\n```bash\nxattr -cr \u002FApplications\u002FUsageBoard.app\n```\n\n## 系统要求\n\n运行：\n\n- macOS 13.0 或更高版本\n- 系统可用 `python3`，用于执行 Python 插件\n\n开发：\n\n- Xcode\n- Swift 6.3 toolchain\n\n## 构建与测试\n\nDebug 构建：\n\n```bash\nswift build\n```\n\n运行测试：\n\n```bash\nswift test\n```\n\nRelease 构建：\n\n```bash\nswift build -c release\n```\n\n本地构建、签名并启动 `dist\u002FUsageBoard.app`：\n\n```bash\nbash scripts\u002Fbuild.sh\n```\n\n`scripts\u002Fbuild.sh` 会停止正在运行的 UsageBoard，构建 release，复制二进制和内置插件到 `dist\u002FUsageBoard.app`，通过 PlistBuddy 向 Info.plist 注入更新检查 URL，执行 ad-hoc 签名，然后启动 app。可通过 `UB_UPDATE_CHECK_URL` 环境变量自定义更新检查地址。\n\n## 发布\n\n生成并上传新版本：\n\n```bash\nbash scripts\u002Frelease.sh\n```\n\n指定版本：\n\n```bash\nbash scripts\u002Frelease.sh 0.1.6\n```\n\n发布脚本会：\n\n1. 从 `dist\u002FUsageBoard.app\u002FContents\u002FInfo.plist` 读取当前版本。\n2. 生成新版本号。\n3. 自动从上个 release tag 到 HEAD 的提交生成更新说明（也可通过第二个参数手动传入）。\n4. 构建 release。\n5. 复制二进制和内置插件。\n6. 通过 PlistBuddy 向 Info.plist 注入更新检查 URL。\n7. 重新签名并验证 app。\n8. 生成 `UsageBoard-\u003Cversion>.zip`。\n9. 生成 `version.json`。\n10. 上传到脚本中配置的服务器路径。\n11. 清理远端旧 zip。\n\n当前发布产物示例：\n\n- `dist\u002FUsageBoard-0.1.20.zip`\n- `dist\u002Fversion.json`\n\n## 项目结构\n\n```text\nSources\u002F\n  UsageBoardCore\u002F       配置、模型、插件执行、缓存、更新等核心逻辑\n  UsageBoardApp\u002F        SwiftUI + AppKit macOS app\nTests\u002F\n  UsageBoardTests\u002F      XCTest 单元测试\nResources\u002F\n  BundledPlugins\u002F       内置 Python 插件\n  PluginAuthoringGuide.html\n  UsageBoard.icns\nscripts\u002F\n  build.sh              本地构建、签名、启动\n  release.sh            发布脚本\ndist\u002F\n  UsageBoard.app        本地测试 app bundle\n```\n\n## 许可证\n\n[MIT](LICENSE)\n","UsageBoard 是一个 macOS 菜单栏应用，用于聚合展示各类 API 用量配额。其核心功能包括支持插件化查询、定时刷新和手动刷新、系统休眠时暂停刷新等。该应用通过插件脚本获取数据，并以进度条形式在菜单栏中展示用量情况。每个插件可独立配置刷新间隔和参数，且支持远程图标加载和缓存。此外，UsageBoard 提供了丰富的设置选项，如开机启动、插件排序及帮助文档查看等功能。适用于需要监控多个服务 API 使用情况的开发者或运维人员，尤其适合频繁使用 API 的场景。",2,"2026-06-11 03:56:05","CREATED_QUERY"]