Skip to content

feat: persist quota state across restarts and add TUI account reorder - #4

Closed
rlawjdghksdlqslek wants to merge 2 commits into
KarpelesLab:masterfrom
rlawjdghksdlqslek:feat/quota-state-persistence
Closed

rlawjdghksdlqslek wants to merge 2 commits into
KarpelesLab:masterfrom
rlawjdghksdlqslek:feat/quota-state-persistence

Conversation

@rlawjdghksdlqslek

Copy link
Copy Markdown

Summary

Two related quality-of-life improvements for TeamClaude's account management:

1. Persist quota state across server restarts

Previously, quota counters (5h/7d unified usage, token limits, reset timestamps)
were reset to zero every time the server restarted. This made it impossible to
track remaining quota accurately after a restart.

  • Adds exportQuota() to AccountManager to serialize quota fields safe for config storage
  • Saves quota state to savedQuota in the config file every 60 seconds via a periodic
    interval
  • Restores saved quota on startup when loading accounts
  • Flushes quota state to disk on graceful shutdown (SIGINT, SIGTERM, and TUI quit)

2. TUI account reorder with o key

Adds an interactive reorder mode to the TUI so users can reorganize the account
list without manually editing the config file.

  • Press o in normal mode to enter reorder mode
  • Navigate with ↑/↓ (or j/k), press Enter to grab an account
  • Move the grabbed account up/down, press Enter to confirm or Esc to cancel
  • Saves the new order to config on confirm
  • Updates currentIndex correctly when accounts are moved around

Files Changed

  • src/account-manager.js — exportQuota(), moveAccount(), quota restore on init
  • src/index.js — periodic quota save, flush on shutdown
  • src/tui.js — reorder mode, _keyReorder(), _doSaveReorder(), footer hint update

Test Plan

  • Start server, make some requests to accumulate quota usage, restart — verify quota
    values are preserved in TUI
  • In TUI, press o, reorder accounts, confirm — verify new order persists after restart
  • In TUI, press o, reorder, press Esc — verify order is reverted
  • Verify currentIndex stays on the correct account after reordering

@MagicalTux

Copy link
Copy Markdown
Member

Thanks for this — both ideas were good. Superseding it with two focused changes rather than merging directly, since the branch predates a lot of churn (org-aware accounts, rotation priority) and is conflicting.

  • Quota persistence → reimplemented in Persist observed quota across restarts (state file) #30. Same goal, but the runtime quota is written to a separate teamclaude.state.json sibling rather than a savedQuota blob in config.json, so the hand-editable config stays clean and isn't rewritten every 60s. State is keyed by account identity and stale windows are discarded on restore. You're credited in the PR.
  • TUI account reorder → dropped, because rotation order is now controlled by the priority command/field (Org-aware account identity, removal, and rotation priority (#6, #7) #28). The reorder save path here also used the pre-org-aware identity matching, which would mis-handle one email across multiple orgs.

Really appreciate the contribution.

@MagicalTux MagicalTux closed this Jun 18, 2026
MagicalTux added a commit that referenced this pull request Jun 18, 2026
Quota learned passively from upstream responses was lost on every restart,
forcing the proxy to re-probe and mis-rotate until it re-learned each account's
window. It now persists that state and restores it on startup — no API calls,
fully consistent with the passive-only design.

- config.js: getStatePath/loadState/saveState — a `teamclaude.state.json`
  sibling of the config, so volatile runtime state stays out of the
  hand-editable config and config isn't rewritten on every save.
- account-manager.js: exportQuotaState/restoreQuotaState keyed by account
  identity (sameIdentity), persisting only utilization + reset windows
  (PERSISTED_QUOTA_FIELDS); transient state and credentials are excluded.
  Restored accounts with a known weekly window are no longer marked "probing".
- index.js: restore on startup; persist every 60s (unref'd) and once more on
  SIGINT/SIGTERM/quit. Stale windows are cleared on first use by the existing
  _clearExpiredQuotas, so a long downtime can't restore an expired window.
- Tests: round-trip, identity-keyed (not positional) matching, stale-window
  clearing, bad-payload guard, state-path derivation.

Adapted from the quota-persistence half of #4, reworked to a separate state
file; the account-reorder half of #4 is dropped as superseded by `priority`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MagicalTux added a commit that referenced this pull request Jun 18, 2026
Quota learned passively from upstream responses was lost on every restart,
forcing the proxy to re-probe and mis-rotate until it re-learned each account's
window. It now persists that state and restores it on startup — no API calls,
fully consistent with the passive-only design.

- config.js: getStatePath/loadState/saveState — a `teamclaude.state.json`
  sibling of the config, so volatile runtime state stays out of the
  hand-editable config and config isn't rewritten on every save.
- account-manager.js: exportQuotaState/restoreQuotaState keyed by account
  identity (sameIdentity), persisting only utilization + reset windows
  (PERSISTED_QUOTA_FIELDS); transient state and credentials are excluded.
  Restored accounts with a known weekly window are no longer marked "probing".
- index.js: restore on startup; persist every 60s (unref'd) and once more on
  SIGINT/SIGTERM/quit. Stale windows are cleared on first use by the existing
  _clearExpiredQuotas, so a long downtime can't restore an expired window.
- Tests: round-trip, identity-keyed (not positional) matching, stale-window
  clearing, bad-payload guard, state-path derivation.

Adapted from the quota-persistence half of #4, reworked to a separate state
file; the account-reorder half of #4 is dropped as superseded by `priority`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants