Skip to content

v0.29.0

Choose a tag to compare

@errhythm errhythm released this 21 Aug 08:40
· 67 commits to main since this release
ce27f66

Syncs two commits from upstream realiti4/claude-swap through 3c3f2b8, plus the macOS test fixes that landed here after 0.28.0.

Fixed

  • A custom CLAUDE_CONFIG_DIR no longer reads another account's token. The active-credential read resolved its Keychain item from the fixed "Claude Code" service name, while the identity read one layer up honors CLAUDE_CONFIG_DIR — so under a custom profile the store reported one account's identity against a different account's credential, silently, for every consumer of that read. It now resolves the item the way Claude Code does for the same environment (session.keychain_service_name, the derivation the delete, session-read and capture paths already share). This is not a corner case here: ccswap run launches Claude Code with a per-session CLAUDE_CONFIG_DIR, which is exactly the custom-profile shape. Thanks to @jamesvillarrubia upstream (#237).
  • The managed-key Keychain read is now default-profile-only. Same item, gated rather than redirected — there is no pinned derivation for Claude's managed-key service name under a custom profile, and capture already refuses it for that reason. A custom profile's own primaryApiKey is still read from its own config, so a managed key there is still found.
  • The test suite stopped leaking a temp directory per worker per run. _ISOLATED_HOME was a module-level mkdtemp() with no cleanup, reached once per process — so pytest-xdist made one per worker and nothing ever removed them (37,948 stray dirs measured on one upstream host). It is now allocated through tmp_path_factory, inside pytest's basetemp, where pytest's own retention reclaims it. Thanks to @codeslake upstream (#267).
  • The three tests that only ever ran on Linux now run everywhere. Noted as a known failure in 0.28.0's release notes: each assumed the Linux shape of something the platform picks (a backup .enc that macOS never writes because the bytes go to the Keychain; the XDG backup root that macOS does not use). Nothing was wrong with the code they cover — the tests now pin the backend they need and resolve the backup root through paths.get_backup_root() instead of naming a layout.

Notes

  • No behavior change for a default-profile install: the resolved Keychain item is the same unsuffixed one, and an explicit CLAUDE_CONFIG_DIR naming the default profile tries the hashed item first and then falls back to the unsuffixed one.
  • The on-disk layout is unchanged and still uses upstream's claude-swap directory names (~/.claude-swap-backup, $XDG_DATA_HOME/claude-swap), so existing installs need no migration.
  • Suite on macOS: 2146 passed, 3 skipped, 0 failed — the three macOS failures called out in 0.28.0 are gone.

Credits

Upstream work by @realiti4 and contributors.