HttpClient.get_text now accepts etag/last_modified and sends If-None-Match/If-Modified-Since; a 304 returns no body and the caller reuses the cached parse. fetch_target recovers validators from the stale cache entry (via new cache::read_raw, TTL-agnostic) and stores whatever the server emits. Verified live: OpenCode/Cloudflare returns no ETag or Last-Modified on either page, so the slots stay None, no headers go out, and 304 never fires. The machinery is correct and ready for the day they add validators.
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.