10 KiB
shusub2
- 文档层级:客户端工具
- 应用性质:客户端 TUI
- 源码来源:repo 原生
- 运行关系:客户端工具
- 部署模型:无
- 对应服务:无
- 对应 stack:无
- Secret 边界:本地用户配置
- 分发方式:
uvx/uv tool install。 - 包名:
shusub2 - 命令名:
shusub2 - 本地状态路径:
~/.config/shusub2/ - 目标 API:
cliproxy-codex-quota的/api/tui/accounts、可选sub2api-status/api/status,以及可选 Sub2API/api/v1/admin/usage和/api/v1/admin/ops/errors。 - 备注:账号数据无 secret,不需要 SSH、数据库访问、API key、OAuth credentials 或 plaintext env;请求与错误日志可选持有 Sub2API admin API key,仅存本机
~/.config/shusub2/logs-token(0600)或SHUSUB2_LOGS_TOKEN。
Single-page terminal dashboard for the token-safe Sub2API account feed, request logs, and merged cn/us error logs. Dedicated full-table views remain available for each data set.
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_URLSUB2API_QUOTA_TUI_API_URLSHUSUB2_API_URL_FILESHUSUB2_STATUS_URLSHUSUB2_STATUS_URL_FILESHUSUB2_LOGS_URLSHUSUB2_LOGS_URL_FILESHUSUB2_LOGS_TOKENSHUSUB2_LOGS_TOKEN_FILESHUSUB2_LOGS_REFRESH_SECONDSSHUSUB2_LOGS_LIMITSHUSUB2_ERRORS_CN_URLSHUSUB2_ERRORS_CN_URL_FILESHUSUB2_ERRORS_US_URLSHUSUB2_ERRORS_US_URL_FILESHUSUB2_ERRORS_REFRESH_SECONDSSHUSUB2_ERRORS_LIMITSHUSUB2_ERRORS_TIME_RANGESHUSUB2_VERSION_CHECK_URLSHUSUB2_VERSION_CHECK_TIMEOUTSHUSUB2_NO_VERSION_CHECK
Unified Dashboard
shusub2 opens a single dashboard with Accounts, Keys, Logs, and Errors
tables stacked vertically. Press a, k, l, or e to focus a table, / to
filter all four tables, and r to refresh all data immediately. Automatic Accounts,
Keys/Logs, and Errors refresh defaults to every five minutes. The client requests
gzip-compressed JSON and transparently decodes it when the upstream supports it.
The two-line detail area follows the selected row. Accounts, Keys, Logs, and
Errors use green, yellow, magenta, and red section styling respectively.
The dashboard sizes every column from the fetched content so wide terminals show complete keys, accounts, and models. On a narrow terminal, a table scrolls horizontally instead of truncating a field:
ACCOUNT | Group | Today | Daily | 5h | 7d | Avail
KEY | Today | Tokens | Req
LOG KEY | Account | Model | First | Duration | Tok/s | Input | Output | Cache | Tokens | Cost | Time | Age
ERR | Status | Key | Account | Model | Time | Age
The Keys table shows today's usage sorted by actual cost, including key name, tokens, and request count. It uses the same admin API key as Logs and Errors; without that token the table is hidden and the summary remains compact.
Use --accounts, --logs, or --errors to start a dedicated full-table view.
The corresponding --once form still prints only that data set.
Request Logs Page
The middle dashboard table shows request logs, and l focuses it.
shusub2 --logs starts the dedicated logs page, while
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 five minutes by default
(--logs-refresh-seconds / SHUSUB2_LOGS_REFRESH_SECONDS). Columns:
Key | Account | Model | Effort | Type | Input | Output | Cache | Tokens | Cost | First | Duration | Tok/s | Time | Age
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 Duration the total request time, both shown in
seconds. Tok/s is the decode throughput computed as
output_tokens / (duration - first_token); it shows - when there is no
output or no positive decode window. Input, Output, and Cache are token
buckets; Cache combines cache write and cache read. Tokens is their total.
Age is relative to local current time (now, 5m ago, 2h ago, etc.). 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 dashboard Logs
and Errors tables stay empty and show a configuration hint; the Accounts table
keeps working without any secret.
Errors Page
The bottom dashboard table shows merged errors, and e focuses it.
shusub2 --errors starts the dedicated errors page, while
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.
The dashboard and dedicated errors page refresh every five minutes by default
(--errors-refresh-seconds / SHUSUB2_ERRORS_REFRESH_SECONDS). 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 | Age
Age is relative to local current time (now, 5m ago, 2h ago, etc.).
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--errors-refresh-seconds/SHUSUB2_ERRORS_REFRESH_SECONDS--errors-limit/SHUSUB2_ERRORS_LIMIT--errors-time-range/SHUSUB2_ERRORS_TIME_RANGE--accounts/--logs/--errors--save-config--install--refresh-seconds/SUB2API_QUOTA_TUI_REFRESH_SECONDS--timeout/SUB2API_QUOTA_TUI_TIMEOUT
The dashboard reads /api/tui/accounts and can optionally read sub2api-status
/api/status for channel monitor health. The Accounts table does not need SSH,
database access, API keys, OAuth credentials, or plaintext env files. The Keys,
Logs, and Errors tables authenticate to the Sub2API admin APIs 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.
On the dedicated --accounts page, 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.
The dedicated Accounts page keeps the full columns 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 -.