@youdie006/swapdex 0.160.0 → 0.161.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +62 -66
  2. package/man/swapdex.1 +2 -2
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -38,21 +38,21 @@ account -- a work seat and a personal subscription, a client's org and your own
38
38
  -- switching means logging out and back in every time.
39
39
 
40
40
  swapdex gives each account its **own permanent space** -- its own
41
- `CLAUDE_CONFIG_DIR` slot -- and flips between them without ever copying a token.
41
+ `CLAUDE_CONFIG_DIR` or `CODEX_HOME` slot -- and switches the default pointer.
42
42
  `swapdex use work` points your default account there and a plain `claude`
43
43
  follows it; `swapdex run work` launches straight into that account (each terminal
44
- can be a different one). Because nothing is copied, **a switch can never log an
45
- account out** -- even if a session is still running when you switch.
44
+ can be a different one). Existing native sessions keep their own slot when the
45
+ default changes.
46
46
  `swapdex onboard` sets this up in a few prompts.
47
47
 
48
- It is a **switcher, not a rotator.** It manages accounts you already own for
49
- distinct purposes, with no feature for cycling them to get around a rate limit
50
- -- see [What it will not do](#what-it-will-not-do).
48
+ It manages accounts you already own, with separate launch defaults, proxy
49
+ selection and configurable failover. See [How it works](#how-it-works) for the
50
+ difference between permanent slots and legacy saved snapshots.
51
51
 
52
- Safety is the design center: in the slot model swapdex never writes a credential
53
- at all -- each account's own login creates and refreshes its token, in its own
54
- slot -- and it only ever hands the official CLI its own credentials: no wrapper,
55
- no proxy, no client spoofing.
52
+ Each account signs in within its own slot. The optional local proxy uses the
53
+ selected account's credential for requests and can renew idle slots in place.
54
+ When an actual native session owns the same login, Swapdex leaves renewal to
55
+ that application and uses a verified, read-only access snapshot when available.
56
56
 
57
57
  ## Concepts
58
58
 
@@ -224,10 +224,9 @@ personal you@personal.com
224
224
 
225
225
  It reads each account's remaining quota from Anthropic's official OAuth usage
226
226
  endpoint using that account's **own** token -- read-only, and it spends zero
227
- message quota. The active account is always live; a saved account whose token
228
- has expired reports so rather than showing a stale number (swapdex never
229
- refreshes tokens -- that is the line between a switcher and a rotator). It is
230
- also in `swapdex ui` under the `%` key.
227
+ message quota. It uses the slot or a verified current native login for that
228
+ account. An unavailable or expired credential reports its state rather than
229
+ inventing current quota. It is also in `swapdex ui` under the `%` key.
231
230
 
232
231
  ### The dashboard
233
232
 
@@ -242,10 +241,10 @@ setup is one keystroke and a name.
242
241
 
243
242
  ## Keeping accounts from expiring
244
243
 
245
- An account nobody opens dies on its own. These refresh tokens go stale when
246
- they are not exercised -- measured across two machines, an idle Codex slot
247
- stops working about ten days after its last run -- and once the refresh token
248
- is gone only a browser sign-in brings the account back.
244
+ Access tokens expire by design. An idle slot can renew while its refresh token
245
+ remains valid, but provider expiry, revocation or renewal by another credential
246
+ holder can make a new browser sign-in necessary. Keep-alive reduces avoidable
247
+ idle expiry; it cannot guarantee that a login never expires.
249
248
 
250
249
  swapdex renews idle accounts for you, but **only while its proxy is running**,
251
250
  because that is the process holding the timer:
@@ -280,9 +279,9 @@ own slot*. swapdex never copies a token between slots: `swapdex run <name>`
280
279
  `exec`s `claude` with that slot's `CLAUDE_CONFIG_DIR`, and `swapdex use <name>`
281
280
  writes a one-line pointer that a small `claude` shim on your PATH reads. Shared
282
281
  config (`settings.json`, global `CLAUDE.md`) is symlinked into each new slot;
283
- the token and history stay per-slot. Because no credential is ever moved, a
284
- token refresh in one account can never revoke another -- **a switch cannot log
285
- you out**.
282
+ the token and history stay per-slot. Independently signed-in slots avoid sharing
283
+ a rotating refresh chain. Copies of one login remain coupled even if they live
284
+ in different directories; the warning below applies to those copies.
286
285
 
287
286
  **Classic snapshots (still supported).** Each CLI also keeps its login in a
288
287
  small on-disk file:
@@ -340,49 +339,48 @@ Already-current accounts and successful or empty runs return 0. Missing or
340
339
  unreadable logins produce a sign-in remedy without an OAuth request.
341
340
 
342
341
  `swapdex refresh --keep-alive` runs the same check without a proxy. If a local
343
- session holds a due account, renewal is deferred to avoid retiring the token
344
- that session holds. The account list and picker then show that renewal is
345
- deferred and its refresh validity is unverified; this does not mean the access
346
- token has expired or the account needs a new login. A confirmed refresh
347
- rejection is reported separately as requiring re-login.
342
+ session holds a due account, Swapdex leaves its refresh token alone. A verified
343
+ usable native login is shown as managed by Claude or Codex, including
344
+ `renewal_owner` in `ls --json`; this is not an OAuth renewal by Swapdex. When
345
+ that native login cannot be verified, renewal remains deferred and unverified.
346
+ Actual access expiry and recorded refresh rejection are separate warnings.
347
+ An inaccessible macOS Keychain is a read-access problem, not proof that the
348
+ login expired.
349
+
350
+ For an HTTP request rejected with 401, the managed proxy first attempts bounded
351
+ recovery of the same selected account: reread a changed usable native access
352
+ token, or await a coordinated Swapdex renewal for an idle login. It retries
353
+ only with a changed usable token, before any explicitly configured failover.
354
+ An unavailable selected login produces an error instead of silently using the
355
+ client's different account.
356
+
357
+ The launch default and proxy selection control different operations: the first
358
+ affects new native launches, and the second affects subsequent managed HTTP
359
+ requests. Changing a file or default does not switch every existing native
360
+ process, in-flight request or WebSocket conversation. Explicit account pins
361
+ retain their selected account.
348
362
 
349
363
  An external copy can renew without changing any local file. Neither the local
350
364
  access token's issue time nor `last_refresh` reveals that remote event. These
351
365
  checks therefore cannot certify refresh validity after unseen remote activity;
352
366
  external consumers need their own login instead of a copy of a managed slot.
353
367
 
354
- ### What it will not do
355
-
356
- These are structural properties, not promises -- the code is built so they
357
- cannot happen:
358
-
359
- - **No HTTP client, no background network.** The binary has no HTTP client in
360
- its dependency graph (CI asserts this on every commit), so it cannot phone
361
- home or exfiltrate a token. Switching, `ls`, `status`, `usage` -- all 100%
362
- local. The one exception is the opt-in `swapdex quota` command, which shells
363
- out to `curl` to read your *own* remaining balance from Anthropic's official
364
- usage endpoint (that account's own token, read-only, spends zero message
365
- quota). It runs only when you type it, sends no data anywhere, and touches no
366
- other endpoint.
367
- - **No auto-rotation.** There is no `--auto`, `--next`, or
368
- `--when-rate-limited` flag. `use` only ever switches to a name you type.
369
- - **No token export.** There is no command that prints a saved credential.
370
- - **No wrapper, no client spoofing.** swapdex swaps the credential file that the
371
- official `claude` / `codex` binary already reads, then gets out of the way. It
372
- never sits between the CLI and the API, never proxies requests, and never
373
- presents itself as the official client. Your traffic is the real CLI's traffic.
374
- (Launching the official tool once, on your explicit pick - `login`'s sign-in
375
- flow, `ui`'s session resume - is a hand-off, not a wrapper: swapdex `exec`s
376
- and is gone.)
377
-
378
- Anthropic and OpenAI both permit multiple accounts for genuinely different
379
- purposes but forbid using multiple accounts to get around a single workload's
380
- rate limit, and forbid routing subscription OAuth tokens through third-party
381
- tools or spoofing the official client. swapdex is built for the former and
382
- structurally cannot do the latter -- it only ever hands the real CLI its own
383
- credentials. See
384
- [Anthropic Usage Policy](https://www.anthropic.com/legal/usage-policy) and
385
- [OpenAI Usage Policies](https://openai.com/policies/usage-policies/).
368
+ ### Network and credential behavior
369
+
370
+ Account selection and listing read local state. Opt-in quota lookups contact
371
+ provider usage endpoints. The optional proxy relays API requests with the
372
+ selected credential, and its scheduled renewal work contacts OAuth endpoints
373
+ for idle logins. It uses `ureq` with rustls and bundled roots; CI excludes heavy
374
+ async runtimes and system-TLS dependencies.
375
+
376
+ Explicit account selection, launch defaults and configured proxy failover are
377
+ separate controls. A local file lock coordinates participating Swapdex callers;
378
+ it cannot lock an independent native CLI or another machine. Native renewal
379
+ ownership and access availability are therefore reported separately.
380
+
381
+ There is no command that prints a saved credential. OAuth request secrets are
382
+ passed to curl on stdin, and diagnostics redact credentials. Native launches
383
+ execute the installed official CLI with the chosen account's configuration.
386
384
 
387
385
  ## MCP (read-only)
388
386
 
@@ -412,18 +410,16 @@ that project's README, July 2026):
412
410
 
413
411
  - [claude-swap](https://github.com/realiti4/claude-swap) -- Claude Code only,
414
412
  a TUI with live usage bars, and *optional auto-switching* near your limit.
415
- If you want auto-rotation, use it -- swapdex deliberately refuses to have
416
- that feature.
413
+ This older comparison should be read alongside the current source review below.
417
414
  - [aisw](https://github.com/burakdede/aisw) -- cross-tool including Gemini,
418
415
  OS-keyring storage, Windows support. More features, bigger surface.
419
416
  - [caam](https://github.com/Dicklesworthstone/coding_agent_account_manager) --
420
- cross-tool with a shell wrapper and automatic rotation on rate limits; the
421
- philosophical opposite of swapdex.
417
+ cross-tool with a shell wrapper and automatic rotation on rate limits.
422
418
 
423
- Pick swapdex if you want the smallest thing that switches your AI CLIs
424
- together, can always undo (`restore`), diagnoses itself (`doctor`), shows
425
- your remaining balance (`quota`), and structurally cannot rotate, proxy, or
426
- spoof the official client.
419
+ For current Codex switching and renewal mechanisms, see the
420
+ [2026-09-15 source survey](docs/research/2026-09-15-codex-switcher-survey.md):
421
+ pinned implementations, regression-test coverage and the limits of file-based
422
+ switching while native sessions keep running.
427
423
 
428
424
  ## Roadmap
429
425
 
package/man/swapdex.1 CHANGED
@@ -1,6 +1,6 @@
1
1
  .ie \n(.g .ds Aq \(aq
2
2
  .el .ds Aq '
3
- .TH swapdex 1 "swapdex 0.160.0"
3
+ .TH swapdex 1 "swapdex 0.161.0"
4
4
  .SH NAME
5
5
  swapdex \- Switch Claude Code / Codex / Gemini / Antigravity login accounts, locally and safely.
6
6
  .SH SYNOPSIS
@@ -136,4 +136,4 @@ Print the man page (roff) to stdout
136
136
  swapdex\-help(1)
137
137
  Print this message or the help of the given subcommand(s)
138
138
  .SH VERSION
139
- v0.160.0
139
+ v0.161.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/swapdex",
3
- "version": "0.160.0",
3
+ "version": "0.161.0",
4
4
  "description": "Switch between multiple Claude Code, Codex, Gemini, and Antigravity login accounts, locally and safely.",
5
5
  "bin": {
6
6
  "swapdex": "bin/swapdex.js"
@@ -12,10 +12,10 @@
12
12
  "man/swapdex.1"
13
13
  ],
14
14
  "optionalDependencies": {
15
- "@youdie006/swapdex-darwin-arm64": "0.160.0",
16
- "@youdie006/swapdex-darwin-x64": "0.160.0",
17
- "@youdie006/swapdex-linux-x64": "0.160.0",
18
- "@youdie006/swapdex-linux-arm64": "0.160.0"
15
+ "@youdie006/swapdex-darwin-arm64": "0.161.0",
16
+ "@youdie006/swapdex-darwin-x64": "0.161.0",
17
+ "@youdie006/swapdex-linux-x64": "0.161.0",
18
+ "@youdie006/swapdex-linux-arm64": "0.161.0"
19
19
  },
20
20
  "keywords": [
21
21
  "cli",