OpenCode rejects a dead auth cookie with HTTP 302 to /auth/authorize (or 401/403). The HTTP client now disables redirect following so this surfaces as a FetchError::Unauthorized instead of a 200 login page that fails to parse. ocd health probes each account's cookie against its default workspace Zen page and reports alive/dead/errored/misconfigured with a total count. Exit is 0 only when all accounts are alive. The main walk (pretty/raw/fetch) also classifies a dead cookie as the new ReportStatus::CookieDead, labels it [cookie dead] in pretty output and cookie_dead in raw output, and continues with the valid accounts rather than aborting. Verified live: valid account surfaces [ok], dead account surfaces [cookie dead], unfilled account surfaces [cookie dead]. |
||
|---|---|---|
| examples | ||
| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| DESIGN.md | ||
| README.md | ||
ocd
Console dashboard for opencode account limits and balance.
ocd reads a config of opencode accounts and auth cookies. It scrapes the
opencode Zen page for balance and the Go page for limits. It prints usage for
the 5-hour, week, and month time frames, each reset time, the next update time,
and remaining balance.
Install
cargo install --path .
Configure
ocd config init
$EDITOR ocd.toml
ocd config check # lists accounts and workspaces, no network
Each account section carries default_workspace and optional extra_workspaces.
[[account]]
name = "work"
cookie = "${OCD_COOKIE_WORK}"
default_workspace = "wrk_01KYNTSGXF7GFXMAMT36N3GH21"
extra_workspaces = ["wrk_02KYNTSGXF7GFXMAMT36N3GH21"]
${VAR} expands from the environment so cookies stay out of the file.
Run
ocd pretty # default terminal output
ocd raw json # one JSON object for widgets and agent plugins
ocd raw plain # TSV-ish lines for shell and awk
ocd fetch # update cache, print nothing; for cron
ocd cache ls | clear
ocd -a work -w wrk_02KYNTSGXF7GFXMAMT36N3GH21 pretty # one account, one workspace
Politeness
Per workspace two requests run at once (Zen, Go). The walk paces 500 ms between
workspaces. Cache TTL defaults to 180 s. Use --force-refresh to bypass.
Status
The HTTP client, cache, pacing, and renderer work. The src/scrape.rs
selectors target the real Zen balance element and the Go usage frames, and
parse correctly against captured pages (see the scrape::tests unit test).
Live fetching needs a valid account cookie and a workspace id. Conditional GET
headers are not yet sent; the TTL cache handles politeness alone. See
DESIGN.md.