Skip to content

v0.5.0

Choose a tag to compare

@g1mn g1mn released this 28 Aug 17:26
· 10 commits to main since this release

Added

  • agyswap alias: standalone alias management (agyswap alias, agyswap alias <slot> <name>, agyswap alias <slot> --unset)
  • agyswap enable / agyswap disable: hold a slot out of blind rotation (agyswap switch with no target) without removing its credentials; explicit agyswap switch <slot> still works on a disabled slot
  • agyswap quota: per-account, per-model Gemini API quota tracking (--refresh, --json), TTL-cached (45s) and merge-safe — never clobbers other accounts' cached data on write
  • agyswap tui / agyswap watch: live, keyboard-driven terminal dashboard with real-time per-model quota bars (rich + textual)

Changed

  • Data directory moved from ~/.agy-swap/ to ~/.agyswap/ — automatically migrated in place on first run; the old path collided with an unrelated third-party tool of a similar name
  • requires-python raised to >=3.9 (matches rich/textual's actual floor; CI already only tested 3.9+)
  • rich and textual are now required dependencies (used only by tui/watch) — agyswap is no longer zero-dependency
  • Fixed a packaging bug where the wheel only ever included agyswap.py and silently dropped modules/ (meaning agyswap ctx ... was likely already broken for pip/pipx installs); [tool.hatch.build.targets.wheel] now explicitly includes modules/**/*.py and modules/**/*.tcss
  • Fixed the same modules/ gap for Homebrew (Formula/agyswap.rb now installs modules/ alongside the binary) and the curl installer (install.sh now fetches modules/ from the repo tarball); agyswap.py now resolves its own real install location (following symlinks) to find modules/ regardless of install method
  • docs/index.html (GitHub Pages): updated for the above — new Command Reference cards for alias/enable/disable/quota/tui/watch, corrected "zero dependencies" claims, updated storage layout + a migration note, rich/textual install caveats on the Homebrew/curl tabs, 3 new FAQ entries, and fixed a pre-existing duplicate section-letter bug (two sections were both labeled "G")
  • docs/index.html's Interactive Architecture Topology (section A): added a "Live TUI Dashboard" node and a new "Live TUI Dashboard Path" preset, added a 5th Engine Core bullet for the quota cache + TUI safety layer, and extended the Google endpoints node to show the quota API — verified visually in a real browser (no overlap/clipping, presets highlight correctly)
  • assets/architecture.svg / docs/assets/architecture.svg (README's Architecture Overview image, two files kept byte-identical per RELEASING.md): same Live TUI Dashboard node + quota cache bullet + quota API line as above, fixed a stray ~/.agy-swap/ (legacy path) it still showed, fixed the "Zero Dependencies" footer, and fixed its header badge which was still stuck at "V0.1.0" despite the Engine Core box already saying v0.4.0 — verified visually
  • assets/banner.svg / docs/assets/banner.svg: fixed the "DEPENDENCIES: 0 External Deps" feature pill to say "rich+textual (TUI)" — verified visually. logo.svg/logo-icon.svg checked, no stale claims found

Fixed (cross-review pass)

  • migrate_legacy_data_dir(): config.json now moves last, not first — an interrupted migration (crash, disk full) used to permanently strand slots//backup/ in the legacy directory since the "already migrated" guard only checked for the new config.json
  • agyswap quota --json (with a target/slot given) no longer dumps every cached account — it's now scoped to the requested account(s), matching the human-readable output
  • modules/quota.py's quota_cache.json read-modify-write is now protected by a file lock — concurrent writers (the TUI's background poller and a CLI agyswap quota call) could previously clobber each other's just-written updates
  • A permanently-failing account (e.g. revoked token) is now retried at most once per TTL window instead of on every single call/poll tick
  • A malformed/unexpected API response shape no longer crashes agyswap quota or the TUI's refresh worker with a raw traceback — it degrades to stale cached data like any other transient failure
  • modules/tui/actions.py's mutation functions now wrap every StorageManager call and re-raise as ActionError, so a corrupted-config or disk-full error can no longer escape past the TUI's error-handling layer and crash the whole dashboard
  • The TUI no longer runs blocking, lock-acquiring account mutations (disable/enable/remove) directly on the UI thread — they now run in a background worker like switch/add already did
  • Switching accounts from the TUI now shows the same "token expiring soon" warning the CLI already shows
  • Fixed a _menu_stack leak in the TUI dashboard that made "Back" require an extra Escape press after every completed disable/enable/remove action
  • Fixed a race where a forced TUI refresh (after an account action) could run concurrently with an in-flight periodic refresh instead of replacing it
  • agyswap.py's bundled-package bootstrap now requires a marker file (modules/quota.py) instead of a bare directory check, so it can't be fooled into loading an unrelated modules/ folder
  • install.sh's modules/ fetch now stages the new copy before removing the old one, so a failed download can't leave an existing install with no modules/ at all
  • agyswap rename now rejects an empty alias (previously silently cleared it, inconsistent with agyswap alias's explicit --unset)
  • StorageManager.load_config()'s corrupted-config recovery no longer calls print() directly — it could garble the TUI's rendered screen since this runs on background worker threads too