Skip to content

feat(quota): plugin provider quota cards and OAuth entries - #337

Open
shiranzby wants to merge 1 commit into
router-for-me:mainfrom
shiranzby:feat/plugin-oauth-and-quota
Open

shiranzby wants to merge 1 commit into
router-for-me:mainfrom
shiranzby:feat/plugin-oauth-and-quota

Conversation

@shiranzby

Copy link
Copy Markdown

What this adds

OAuth entry cards and quota cards for the plugin providers bundled by
cpa-multi-plugins —
workbuddy / trae / qoder / zcode / mimo.

  • OAuth page: the five entry cards, plus the credential icon map so these
    providers stop falling back to the Gemini icon.
  • Quota page: a Plugins group rendering package quota and sign-in credits.
  • management_endpoint(): paths that already start with v0/ are passed
    through. Plugin panel routes and the plugin quota API only exist on the v0 mux,
    while the prefix was hardcoded to /v8/management — the client could not reach
    them at all.

Why this does not use the core plugin-quota API (re: #331)

#331 is the right shape long-term, but on the shipped build it cannot render
anything. Measured on GUI v0.3.12 / core v8.0.6 (== main @ 90364e9) with
cpa-multi-plugins v0.12.110:

Probe Result
GET /v8/management/credentials credential carries quota: {"signals": {}} only — no supports_quota / quota_provider
GET /v8/management/plugins all five plugins report "supports_quota": false
POST /v8/management/credentials/quota/fetch (the call #331 adds) 404
POST /v0/management/credentials/quota/fetch 404
POST /v0/management/quota/fetch 501 {"error":"no quota provider available for credential"}
POST /v0/management/quota/reset 501 {"error":"no quota provider available for credential to reset"}

Three consequences:

  1. providerForFile() in feat(quota): show quota for plugin providers such as WorkBuddy #331 keys off supports_quota / quota_provider,
    which no shipped credential sets, so its plugin branch is never taken.
  2. The path it calls does not exist — the real route is /quota/fetch, and only
    on the v0 mux.
  3. Even with the right path the core answers 501: the route exists, the
    capability does not. What is missing is on the plugin side — the plugins
    never implemented the core's quota provider interface, and their numbers are
    reachable only through their own panel API.

So #331 would produce an error row for these credentials rather than quota. It is
worth revisiting once the plugins declare the capability; this PR is the interim
path until then.

What it does instead

POST /v0/management/plugins/<id>/refresh, whose payload is already identical
across the bundled providers:

  • summary.total_remain / summary.total_size / summary.pack_count → package
    quota row
  • summary.<region>_size pairs → per-region rows, only when more than one region
    holds quota
  • accounts[].checkin → sign-in credit row

Verified live against core 8.0.6 + cpa-multi-plugins v0.12.110 (WorkBuddy CN:
29 package, 4949 / 5050 remaining, 300 check-in credits).

Compatibility and risk

  • Additive: claude / codex / kimi / xai / antigravity / devin are
    untouched; plugin is one more member of the QuotaProvider union.
  • The plugin panel API is not a documented contract. If a plugin renames
    those fields the rows stop rendering; the plugin panel
    (/v0/resource/plugins/<id>/panel) stays authoritative.
  • trae / qoder / zcode / mimo currently expose no account, or no panel at
    all (mimo has none), so they simply produce no rows.
  • Icons: workbuddy.png and zcode.png already exist in this repository;
    the trae / qoder / mimo / plugin SVGs are placeholder glyphs, not
    official marks — happy to drop or replace them.

Testing

tsc --noEmit and vite build are clean on this branch, and the quota rows were
verified against a live core.

If you would rather not carry plugin-specific code in this repository, the
alternative is a core-side capability plus the plugin-side implementation, and
this PR can be closed in favour of #331 once that lands.


简体中文

本 PR 为 cpa-multi-plugins 打包的五个插件补齐 OAuth 入口卡片与额度卡片。

关于 #331 的问题:它在 GUI v0.3.12 / core v8.0.6 上渲染不出任何额度,原因有三——
① 凭据上没有 supports_quota / quota_provider,只有 quota: {"signals": {}};
② 五个插件全部 supports_quota: false;
③ 它调用的 POST /credentials/quota/fetch 实测 404(v8 与 v0 均无此路径),
真实路由是 /v0/management/quota/fetch,且返回 501
no quota provider available for credential(/quota/reset 同样 501)。
也就是说内核路由在、插件能力不在——缺的是插件侧实现,因此合入后只会显示错误行,
而不是额度。

本 PR 改为读取插件自己的面板接口 POST /v0/management/plugins/<id>/refresh,
其 payload 在几个插件之间已经同构(summary 总分与分区 + accounts[].checkin 签到积分),
因此不需要为每个插件单独写解析器。

顺带修掉一个既有缺陷:未知 provider 的凭据图标会回落成 Gemini 图标。

对现有六个 provider 无影响;插件面板接口非文档化契约,插件升级改字段时需要跟着调整,
插件面板本身仍是权威视图。

shiranzby added a commit to shiranzby/EasyCLIProxyAPI that referenced this pull request Oct 2, 2026
State up front what this build adds (five plugin OAuth entries + plugin
quota cards), that upstream is followed automatically under the same tag,
and that the UI part is an interim drop-in for the unmerged upstream PR
router-for-me#337.
…mport/export

The bundled cpa-multi-plugins providers (workbuddy / trae / qoder / zcode /
mimo) keep their own quota numbers. The core cannot be asked for them: no
credential carries supports_quota/quota_provider, all five plugins report
supports_quota: false, and POST /v0/management/quota/fetch answers 501
"no quota provider available for credential".

- management_endpoint(): pass v0/ paths through. Plugin panel routes and the
  plugin quota API only exist on the v0 mux, so the client could not reach
  them while the prefix was hardcoded to /v8/management.
- quotaService: a `plugin` quota provider resolved through
  POST /v0/management/plugins/<id>/refresh. The payload is shared by the
  bundled providers; each credential is matched back to its own account so a
  card shows that account's packages rather than the pool total, with the
  pool total kept as a trailing row.
- QuotaPage: a Plugins group for those rows.
- OAuth page: WorkBuddy / Trae / Qoder / ZCode / MiMo entry cards, plus the
  credential icon map so unknown providers stop falling back to the Gemini
  icon.
- Credentials: per-card export (save dialog), and the import handler now
  accepts third-party exports - a JSON array of flat snake_case accounts is
  split and reshaped into one nested credential per account. Single
  CPA-format files take the previous path unchanged.
- i18n: quota.plugin.* and authFiles.export* in zh-CN / en / ja.

Additive: the six existing quota providers are untouched.
@shiranzby
shiranzby force-pushed the feat/plugin-oauth-and-quota branch from 98f752a to efc113f Compare October 2, 2026 16:47
@shiranzby

Copy link
Copy Markdown
Author

Updated the branch (same PR, force-pushed) with three changes:

1. Per-account quota (bug fix for my own first version).
POST /plugins/<id>/refresh returns every account that plugin owns, plus a pooled summary.
The first version rendered summary, so with several accounts every credential card showed the
same total — exactly the pooled numbers. Now each credential is matched back to its own entry in
accounts[] (by auth_index, falling back to auth_id / credential file name) and shows that
account's packages; the pool total moved to a trailing row that only appears when there is more
than one account.

Measured with 7 WorkBuddy CN accounts: pool 15980 / 23810, while the individual accounts are
5159/5260, 3087/3700, 3200/3200, 1899/2950, 1338/3000, 699/2100, 598/3600.

2. Credential export.
There was no way to get a credential back out of the app. Added a per-card export button plus an
export_auth_file command that copies the credential on disk (the credentials list reports paths
relative to the core install directory, so those are resolved first) to a path chosen through the
save dialog. dialog:allow-save was missing from capabilities/default.json.

3. Import compatibility.
The import handler now accepts third-party credential exports: a JSON array of flat snake_case
accounts (for example cockpit-style workbuddy_accounts_*.json) is split and reshaped into one
nested camelCase credential per account — expires_at milliseconds to seconds, region derived
from domain, filename <provider>-<uid>.json. A single file that is already in CPA format
(auth / account present) still takes the previous path byte-for-byte, so existing workflows
are unaffected.

tsc --noEmit and vite build are clean on this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant