shujakuin 545c1abbe6 feat: merge cn+us ops errors page into shusub2
Add an errors screen that pulls admin ops error logs from sub2apicn and
the server4 fixed origin in parallel, refreshes every 60s while active,
and keeps the 0.2.3 key-usage panel and logs enhancements.
2026-07-24 22:28:19 +08:00
2026-06-09 15:06:26 +08:00
2026-06-09 15:06:26 +08:00

shusub2

  • 文档层级:客户端工具
  • 应用性质:客户端 TUI
  • 源码来源:repo 原生
  • 运行关系:客户端工具
  • 部署模型:无
  • 对应服务:无
  • 对应 stack:无
  • Secret 边界:账号页无 secret;请求日志页可选持有 Sub2API admin API key(仅存本机 ~/.config/shusub2/logs-token0600
  • 分发方式:uvx / uv tool install
  • 包名:shusub2
  • 命令名:shusub2
  • 本地状态路径:~/.config/shusub2/
  • 目标 APIcliproxy-codex-quota/api/tui/accounts、可选 sub2api-status /api/status、可选 Sub2API /api/v1/admin/usage(请求日志页,默认 sub2apicn.shujk.top)。
  • 备注:账号页不需要 SSH、数据库访问、API key、OAuth credentials 或 plaintext env;请求日志页需要 Sub2API admin API key。

Terminal UI for the token-safe Sub2API account feed exposed by cliproxy-codex-quota, plus an optional request-logs page backed by the Sub2API admin usage API.

Quick Start

Run once from a public Git repo with uvx:

uvx --from git+https://gitea.shujk.top/shujakuin/shusub2.git shusub2 \
  --api-url https://codex.server2.shujk.top/1232131231313123/api/tui/accounts

Bootstrap a new machine from uvx: save the API URL, install shusub2 as a user command, then run it later as shusub2:

uvx --from git+https://gitea.shujk.top/shujakuin/shusub2.git shusub2 \
  --api-url https://codex.server2.shujk.top/1232131231313123/api/tui/accounts \
  --install
shusub2

Install as a user command:

uv tool install git+https://gitea.shujk.top/shujakuin/shusub2.git
shusub2 --api-url https://codex.server2.shujk.top/1232131231313123/api/tui/accounts --save-config

Configure the default public API URL for shusub2:

mkdir -p ~/.config/shusub2
chmod 700 ~/.config/shusub2
printf '%s\n' 'https://codex.server2.shujk.top/1232131231313123/api/tui/accounts' > ~/.config/shusub2/api-url
chmod 600 ~/.config/shusub2/api-url
shusub2

Environment variables override the config file:

  • SHUSUB2_API_URL
  • SUB2API_QUOTA_TUI_API_URL
  • SHUSUB2_API_URL_FILE
  • SHUSUB2_STATUS_URL
  • SHUSUB2_STATUS_URL_FILE
  • SHUSUB2_LOGS_URL
  • SHUSUB2_LOGS_URL_FILE
  • SHUSUB2_LOGS_TOKEN
  • SHUSUB2_LOGS_TOKEN_FILE
  • SHUSUB2_LOGS_REFRESH_SECONDS
  • SHUSUB2_LOGS_LIMIT
  • SHUSUB2_ERRORS_CN_URL
  • SHUSUB2_ERRORS_CN_URL_FILE
  • SHUSUB2_ERRORS_US_URL
  • SHUSUB2_ERRORS_US_URL_FILE
  • SHUSUB2_ERRORS_REFRESH_SECONDS
  • SHUSUB2_ERRORS_LIMIT
  • SHUSUB2_ERRORS_TIME_RANGE
  • SHUSUB2_VERSION_CHECK_URL
  • SHUSUB2_VERSION_CHECK_TIMEOUT
  • SHUSUB2_NO_VERSION_CHECK

Request Logs Page

Press l on the accounts page to open the request logs page; press a to go back. shusub2 --logs starts directly on the logs page, and shusub2 --once --logs prints one logs snapshot to stdout.

The logs page reads the latest requests (default 100, --logs-limit) from the Sub2API admin usage API and refreshes every 60 seconds by default (--logs-refresh-seconds / SHUSUB2_LOGS_REFRESH_SECONDS). Columns:

Key | Account | Model | Effort | Type | Tokens | Cost | First | Latency | Tok/s | Time

Type is the Sub2API request_type (sync / stream / ws_v2 / cyber). Tokens is input + output + cache write + cache read; the detail line below the table shows the per-bucket breakdown, actual cost, first-token latency, decode speed, upstream model mapping, user, and request id.

Effort is the request's reasoning_effort (- when absent). First is the first-token latency and Latency the total duration, both shown in seconds. Tok/s is the decode throughput computed as output_tokens / (latency - first_token); it shows - when there is no output or no positive decode window. In the TUI each API key name is rendered in a stable per-key color so rows from the same key are easy to group visually (--once --logs output stays plain text).

The logs URL defaults to https://sub2apicn.shujk.top/api/v1/admin/usage and can be overridden with --logs-url / SHUSUB2_LOGS_URL / ~/.config/shusub2/logs-url.

The page needs a Sub2API admin API key (generated in the Sub2API web UI under Settings). Configure it once:

mkdir -p ~/.config/shusub2 && chmod 700 ~/.config/shusub2
printf '%s\n' '<sub2api-admin-api-key>' > ~/.config/shusub2/logs-token
chmod 600 ~/.config/shusub2/logs-token

or via SHUSUB2_LOGS_TOKEN. The key is sent as the x-api-key header and is never written anywhere else by the client. Without a token the logs page stays empty and shows a configuration hint; the accounts page keeps working without any secret.

Errors Page

Press e from the accounts or logs page to open the merged errors page; press a / l to jump back. shusub2 --errors starts directly on the errors page, and shusub2 --once --errors prints one merged snapshot to stdout.

The page pulls the latest admin ops error logs from both cn and us in parallel, then merges them by created_at:

  • cn default: https://sub2apicn.shujk.top/api/v1/admin/ops/errors
  • us default: https://sub2api.server4.shujk.top:19857/api/v1/admin/ops/errors

sub2apius.shujk.top is the Cloudflare-proxied public name for the same us backend, but Cloudflare often returns 1010 for non-browser clients, so the TUI defaults to the fixed server4 origin while still labeling rows as us.

While the errors page is active it refreshes every 60 seconds by default (--errors-refresh-seconds / SHUSUB2_ERRORS_REFRESH_SECONDS). Leaving the page stops that interval. Query window defaults to 24h (--errors-time-range / SHUSUB2_ERRORS_TIME_RANGE); each source uses page=1 and page_size from --errors-limit (default 100, max 500).

Columns:

Node | Status | Key | Account | Model | Phase | Type | Owner | Time

Auth reuses the same admin API key as the logs page.

Local Development

cd apps/sub2api-quota-tui
uv run shusub2

Run inside zellij:

zellij action new-pane --name sub2api-quota -- \
  bash -lc 'cd /home/shujakuin/infra/apps/sub2api-quota-tui && uv run shusub2'

Configuration:

  • --api-url / SUB2API_QUOTA_TUI_API_URL
  • --status-url / SHUSUB2_STATUS_URL
  • --logs-url / SHUSUB2_LOGS_URL
  • --logs-token / SHUSUB2_LOGS_TOKEN
  • --logs-refresh-seconds / SHUSUB2_LOGS_REFRESH_SECONDS
  • --logs-limit / SHUSUB2_LOGS_LIMIT
  • --save-config
  • --install
  • --refresh-seconds / SUB2API_QUOTA_TUI_REFRESH_SECONDS
  • --timeout / SUB2API_QUOTA_TUI_TIMEOUT

The TUI reads /api/tui/accounts and can optionally read sub2api-status /api/status for channel monitor health. The accounts page does not need SSH, database access, API keys, OAuth credentials, or plaintext env files. The optional request logs page authenticates to the Sub2API admin usage API with an admin API key stored only in ~/.config/shusub2/logs-token (0600) or SHUSUB2_LOGS_TOKEN.

When --status-url is omitted, shusub2 infers a sibling /api/status URL from account URLs ending in /api/tui/accounts, so the public Codex endpoint automatically enables monitor availability. On startup it also checks the public Gitea repo for a newer package version and prints a short upgrade hint when one is available.

Below the accounts table, a per-key panel shows today's usage for each API key (Key | Today | Tokens | Req, sorted by cost, key names in the same per-key colors as the logs page). It combines the Sub2API admin dashboard/api-keys-trend and dashboard/api-keys-usage endpoints and needs the same admin API key as the logs page; without a token the panel stays empty and the status line shows a hint. --once prints the same panel after the accounts table when a token is configured.

Accounts page columns are ordered for scanning inside zellij:

Name | Provider | Group | Daily | Today | Tokens | Req | Kind | 5h | 7d | Reset | Status | Availability

Provider distinguishes openai and anthropic accounts from the public platform field returned by the API.

Daily is shown as used/limit when Sub2API has quota_daily_* fields in accounts.extra; otherwise it is -.

Group is the derived Sub2API tier alias group. Higher tiers win when multiple aliases exist: id < slow < fast < sfast. The table shows sfast first, then fast, slow, id, and ungrouped accounts.

When --status-url is configured, the status line shows channel monitor health, and the selected account detail shows the matching monitor status when one exists. Monitor binding first uses the shared base_url_hash emitted by the account API and sub2api-status; name-token matching remains only as a fallback for older status payloads.

Availability is derived from the bound channel monitor. Accounts without a matching monitor show -.

S
Description
Installable TUI for token-safe Sub2API account quota and daily usage
Readme MIT 1 MiB
Languages
Python 100%