@youdie006/swapdex 0.160.0 → 0.162.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 +83 -66
  2. package/man/swapdex.1 +5 -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
 
@@ -240,12 +239,33 @@ setup is one keystroke and a name.
240
239
  <img src="https://raw.githubusercontent.com/youdie006/swapdex/main/docs/ui-demo.gif" alt="swapdex ui on a fresh machine: it finds the Claude Code and Codex logins already present, saves them as a profile named main, and shows the account with its 5h and 7d usage bars" width="760" />
241
240
  </div>
242
241
 
242
+ ## Resuming Codex conversations
243
+
244
+ Use `codex resume` normally, or `codex resume --all` to include other working
245
+ directories. Swapdex keeps one stable OpenAI provider across account changes.
246
+ The paying account is shown by `swapdex serve --tool codex --quiet`.
247
+ If the proxy cannot start, the launcher warns that Codex will use its own login
248
+ directly.
249
+
250
+ After updating from a version that created `swapdex` provider IDs, run
251
+ `swapdex shim` to refresh the launcher. It automatically repairs those legacy
252
+ session labels before launching Codex. To inspect or retry the repair directly:
253
+
254
+ ```sh
255
+ swapdex repair-codex-sessions --dry-run
256
+ swapdex repair-codex-sessions
257
+ ```
258
+
259
+ The repair preserves conversation contents and keeps a private recovery journal.
260
+ Open sessions are deferred until they close. Unsupported compressed rollouts
261
+ and unsuccessful repairs are reported rather than silently hidden.
262
+
243
263
  ## Keeping accounts from expiring
244
264
 
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.
265
+ Access tokens expire by design. An idle slot can renew while its refresh token
266
+ remains valid, but provider expiry, revocation or renewal by another credential
267
+ holder can make a new browser sign-in necessary. Keep-alive reduces avoidable
268
+ idle expiry; it cannot guarantee that a login never expires.
249
269
 
250
270
  swapdex renews idle accounts for you, but **only while its proxy is running**,
251
271
  because that is the process holding the timer:
@@ -280,9 +300,9 @@ own slot*. swapdex never copies a token between slots: `swapdex run <name>`
280
300
  `exec`s `claude` with that slot's `CLAUDE_CONFIG_DIR`, and `swapdex use <name>`
281
301
  writes a one-line pointer that a small `claude` shim on your PATH reads. Shared
282
302
  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**.
303
+ the token and history stay per-slot. Independently signed-in slots avoid sharing
304
+ a rotating refresh chain. Copies of one login remain coupled even if they live
305
+ in different directories; the warning below applies to those copies.
286
306
 
287
307
  **Classic snapshots (still supported).** Each CLI also keeps its login in a
288
308
  small on-disk file:
@@ -340,49 +360,48 @@ Already-current accounts and successful or empty runs return 0. Missing or
340
360
  unreadable logins produce a sign-in remedy without an OAuth request.
341
361
 
342
362
  `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.
363
+ session holds a due account, Swapdex leaves its refresh token alone. A verified
364
+ usable native login is shown as managed by Claude or Codex, including
365
+ `renewal_owner` in `ls --json`; this is not an OAuth renewal by Swapdex. When
366
+ that native login cannot be verified, renewal remains deferred and unverified.
367
+ Actual access expiry and recorded refresh rejection are separate warnings.
368
+ An inaccessible macOS Keychain is a read-access problem, not proof that the
369
+ login expired.
370
+
371
+ For an HTTP request rejected with 401, the managed proxy first attempts bounded
372
+ recovery of the same selected account: reread a changed usable native access
373
+ token, or await a coordinated Swapdex renewal for an idle login. It retries
374
+ only with a changed usable token, before any explicitly configured failover.
375
+ An unavailable selected login produces an error instead of silently using the
376
+ client's different account.
377
+
378
+ The launch default and proxy selection control different operations: the first
379
+ affects new native launches, and the second affects subsequent managed HTTP
380
+ requests. Changing a file or default does not switch every existing native
381
+ process, in-flight request or WebSocket conversation. Explicit account pins
382
+ retain their selected account.
348
383
 
349
384
  An external copy can renew without changing any local file. Neither the local
350
385
  access token's issue time nor `last_refresh` reveals that remote event. These
351
386
  checks therefore cannot certify refresh validity after unseen remote activity;
352
387
  external consumers need their own login instead of a copy of a managed slot.
353
388
 
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/).
389
+ ### Network and credential behavior
390
+
391
+ Account selection and listing read local state. Opt-in quota lookups contact
392
+ provider usage endpoints. The optional proxy relays API requests with the
393
+ selected credential, and its scheduled renewal work contacts OAuth endpoints
394
+ for idle logins. It uses `ureq` with rustls and bundled roots; CI excludes heavy
395
+ async runtimes and system-TLS dependencies.
396
+
397
+ Explicit account selection, launch defaults and configured proxy failover are
398
+ separate controls. A local file lock coordinates participating Swapdex callers;
399
+ it cannot lock an independent native CLI or another machine. Native renewal
400
+ ownership and access availability are therefore reported separately.
401
+
402
+ There is no command that prints a saved credential. OAuth request secrets are
403
+ passed to curl on stdin, and diagnostics redact credentials. Native launches
404
+ execute the installed official CLI with the chosen account's configuration.
386
405
 
387
406
  ## MCP (read-only)
388
407
 
@@ -412,18 +431,16 @@ that project's README, July 2026):
412
431
 
413
432
  - [claude-swap](https://github.com/realiti4/claude-swap) -- Claude Code only,
414
433
  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.
434
+ This older comparison should be read alongside the current source review below.
417
435
  - [aisw](https://github.com/burakdede/aisw) -- cross-tool including Gemini,
418
436
  OS-keyring storage, Windows support. More features, bigger surface.
419
437
  - [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.
438
+ cross-tool with a shell wrapper and automatic rotation on rate limits.
422
439
 
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.
440
+ For current Codex switching and renewal mechanisms, see the
441
+ [2026-09-15 source survey](docs/research/2026-09-15-codex-switcher-survey.md):
442
+ pinned implementations, regression-test coverage and the limits of file-based
443
+ switching while native sessions keep running.
427
444
 
428
445
  ## Roadmap
429
446
 
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.162.0"
4
4
  .SH NAME
5
5
  swapdex \- Switch Claude Code / Codex / Gemini / Antigravity login accounts, locally and safely.
6
6
  .SH SYNOPSIS
@@ -16,6 +16,9 @@ Print help
16
16
  Print version
17
17
  .SH SUBCOMMANDS
18
18
  .TP
19
+ swapdex\-repair\-codex\-sessions(1)
20
+ Repair provider metadata written by older Swapdex Codex shims
21
+ .TP
19
22
  swapdex\-add(1)
20
23
  Save the current live login as a named profile
21
24
  .TP
@@ -136,4 +139,4 @@ Print the man page (roff) to stdout
136
139
  swapdex\-help(1)
137
140
  Print this message or the help of the given subcommand(s)
138
141
  .SH VERSION
139
- v0.160.0
142
+ v0.162.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/swapdex",
3
- "version": "0.160.0",
3
+ "version": "0.162.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.162.0",
16
+ "@youdie006/swapdex-darwin-x64": "0.162.0",
17
+ "@youdie006/swapdex-linux-x64": "0.162.0",
18
+ "@youdie006/swapdex-linux-arm64": "0.162.0"
19
19
  },
20
20
  "keywords": [
21
21
  "cli",