Skip to content

Release v5.0.1 - #44

Merged
serialexperimentslainnnn merged 7 commits into
mainfrom
develop
Aug 10, 2026
Merged

serialexperimentslainnnn merged 7 commits into
mainfrom
develop

Conversation

@serialexperimentslainnnn

Copy link
Copy Markdown
Owner

Promotes develop to main for the 5.0.1 patch release. See CHANGELOG.md for the full entry.

What ships

The subscription login now survives a restart (#43). Reported on Linux and Windows, and it was one bug rather than two: the credential persisted correctly in the OS store all along — what expired was the access token inside it, issued for ~10 hours. The refresh token beside it, good for weeks, was never spent, because spending it means the binary rewriting the plaintext credentials file the vault exists to remove.

The fix uses the binary's own non-interactive auth login branch (CLAUDE_CODE_OAUTH_REFRESH_TOKEN + CLAUDE_CODE_OAUTH_SCOPES) to mint a fresh credential with no browser, no TTY and no user, then takes custody of it exactly as every other credential path here does. The plugin still holds no OAuth client, calls no token endpoint and never writes that file back — the vault's invariant is intact, only its cost is gone.

Scope: the subscription (OAuth) credential only. An Anthropic API key lives in a different slot, has no expiry and no refresh token, and is untouched.

Also in the release: plan-limit percentages now render with one decimal in the dashboard bars and composer dots.

Release gates

The full gate runs on this PR (Static analysis, Dependency audit, Plugin verifier, Build plugin and No bot PRs pending on develop are skipped on PRs into develop and only apply here). Every one of them was also run locally on the merged tree:

Gate Result
test koverVerify 754 tests, 0 failures + coverage gates
detekt / spotlessCheck pass
npm test (vitest) 104 tests
npm run lint / format:check pass
npm audit --omit=dev --audit-level=low 0 vulnerabilities
verifyPlugin Compatible: IC-251, IC-252, IU-253, IU-261, IU-262
Artifact assertions 0 node_modules entries; META-INF LICENSE and THIRD-PARTY-NOTICES.md present

To be merged with a merge commit, not a rebase, so the release tag points at a commit that exists on both branches (docs/RELEASE_PROCEDURE.md section 6). Publication remains gated on the marketplace environment approval.

🤖 Generated with Claude Code

Empty commit to open a fresh PR into main and drive release.yml once GitHub
Actions recovers from the outage. No code change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The subscription login did not survive a restart, on Linux and on Windows
alike, and the cause was not persistence. The credential is in the IDE
PasswordSafe and therefore in the OS store (KWallet or GNOME Keyring through
the Secret Service, Keychain, Credential Manager), and it was still there
after the reboot. What expired was the access token inside it - `auth login`
issues one good for about ten hours, so any restart the next day found a
perfect credential that authenticated nothing, `hasUsableToken()` answered
false, and false meant signed out.

The blob always carried a refresh token good for weeks, and nothing was
allowed to spend it, since spending it means the binary rewriting
`~/.claude/.credentials.json` - the file the vault exists to remove. The way
out is in the binary and is a first-class path. With the environment carrying
CLAUDE_CODE_OAUTH_REFRESH_TOKEN and CLAUDE_CODE_OAUTH_SCOPES, `claude auth
login` takes a dedicated non-interactive branch, mints a credential into its
own store and exits. Verified against 2.1.223 that the branch is genuinely
non-interactive - an invalid refresh token fails on the HTTP round-trip and
exits 1, with no browser and no TTY wait.

So renewal is the binary's job, exactly as it always was, and the plugin's job
stays what it was - capture the account while the config is freshest, harvest
the credential off the disk, delete it. The plugin still holds no OAuth
client, calls no token endpoint and never writes that file back.

This is one bug rather than two. The binary's default credential store is its
`plaintext` provider on every platform, so the vault path and the expiry are
identical everywhere. No platform-specific code was needed; the only
Windows-specific care is that the renewal environment strips
CLAUDE_CODE_OAUTH_TOKEN case-insensitively, since environment names are
case-insensitive there.

An expired-but-renewable blob now counts as an identity
(`CredentialsVault.canRenew`), the renewal runs off the EDT in `launch()`
before the env is built and never while a sign-in is in flight, the refresh
token rotates at every renewal so ordinary use extends it indefinitely, and a
failure arms a five-minute cooldown because the boot watcher polls every three
seconds. Also drops a leftover CC-TRACE prefix from a rate-limit debug log.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The usage windows and the extra-credit balance were rounded to a whole number
on the Kotlin side before they ever reached the web app, so the dashboard bars
and the composer dots could only ever read as integers. The percentage now
travels as a Double and the front end formats it with `toFixed(1)`, which also
makes the locale question visible - whether the decimal separator renders as a
comma or a dot is now something the UI can be observed doing rather than
guessed at.

Removes `JcefSessionData.pctOf` and `JcefState.normalizePercent` along with it,
since neither has a caller once the rounding moves to the display layer. The
clamping they performed goes with them; the event-sourced windows are still
multiplied by 100 exactly as `RateLimitInfo.utilizationPercent` did.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 5.0.1 notes described the fix without naming the credential it applies to,
which leaves an API-key user unable to tell whether it concerns them.

It does not. An Anthropic API key is a different identity in a different slot
(`providerApiKey:anthropic` in the same PasswordSafe, not
`CLAUDE_CREDENTIALS_JSON`), it has no expiry and no refresh token, so nothing
was lost across a restart and nothing is renewed now. `CredentialsVault.renew`
reads the `claudeAiOauth` blob and nothing else, and `envOverlay` withdraws
entirely when an API key is present.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-session

fix(auth): renew the vaulted login instead of asking again
Back-merge of the v5.0.0 release merge commit, so develop is up to date with
main and the 5.0.1 release pull request can be merged. Content no-op: main
carries no change develop does not already have.
…op-with-main

chore: back-merge main into develop
@serialexperimentslainnnn
serialexperimentslainnnn merged commit c6bb113 into main Aug 10, 2026
12 checks passed
serialexperimentslainnnn added a commit that referenced this pull request Aug 10, 2026
Merge pull request #44 from serialexperimentslainnnn/develop
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.

1 participant