@reyanshgupta/ditto-cli 0.3.5 → 0.3.7

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 (2) hide show
  1. package/README.md +48 -22
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  [![MIT license](https://img.shields.io/badge/license-MIT-6f42c1.svg)](LICENSE)
6
6
  [![Rust 1.85+](https://img.shields.io/badge/rust-1.85%2B-6f42c1.svg)](https://www.rust-lang.org/)
7
7
 
8
- Keep work, personal, and client Claude Code, Codex, opencode, OMP, and Prime Agent logins apart.
8
+ Keep work, personal, and client Claude Code, Codex, opencode, OMP, Prime Agent, and Pi logins apart.
9
9
 
10
- Ditto CLI gives each profile its own authentication and session history while keeping the capabilities you configured once. Pick a profile in the terminal, then launch any of the five tools. Your existing setup stays available as the `default` profile.
10
+ Ditto CLI gives each profile its own authentication and session history while keeping the capabilities you configured once. Pick a profile in the terminal, then launch any of the six tools. Your existing setup stays available as the `default` profile.
11
11
 
12
12
  Ditto CLI takes its name from the shape-shifting Pokémon: one small tool, whichever coding identity you need.
13
13
 
@@ -26,6 +26,7 @@ Ditto CLI takes its name from the shape-shifting Pokémon: one small tool, which
26
26
  │ ││opencode ⠹ Checking │
27
27
  │ ││OMP ○ Sign in required │
28
28
  │ ││Prime Agent ● Signed in │
29
+ │ ││Pi ○ Sign in required │
29
30
  │ ││ │
30
31
  │ ││Profile directories │
31
32
  │ ││Claude Code ~/.ditto/profiles/work/claude │
@@ -33,9 +34,10 @@ Ditto CLI takes its name from the shape-shifting Pokémon: one small tool, which
33
34
  │ ││opencode …/work/opencode/data/opencode │
34
35
  │ ││OMP ~/.omp/profiles/work/agent │
35
36
  │ ││Prime Agent …/.ditto/profiles/work/prime-agent │
37
+ │ ││Pi ~/.ditto/profiles/work/pi │
36
38
  └────────────────────────┘└────────────────────────────────────────────────────┘
37
39
  ┌──────────────────────────────────────────────────────────────────────────────┐
38
- c Claude Code · x Codex · o opencode · p OMP · a Prime
40
+ c Claude Code · x Codex · o opencode · p OMP · a Prime · i Pi
39
41
  │ ↑↓ select · n new · e rename · d default │
40
42
  │ l sign in · L sign out · r refresh · q quit │
41
43
  └──────────────────────────────────────────────────────────────────────────────┘
@@ -43,7 +45,7 @@ Ditto CLI takes its name from the shape-shifting Pokémon: one small tool, which
43
45
 
44
46
  ## How it works
45
47
 
46
- Claude Code, Codex, opencode, OMP, and Prime Agent keep user-level configuration and login state on disk. That works until you need separate accounts for different jobs. Manually moving auth files around is easy to get wrong, and it is hard to tell which account a new session will use.
48
+ Claude Code, Codex, opencode, OMP, Prime Agent, and Pi keep user-level configuration and login state on disk. That works until you need separate accounts for different jobs. Manually moving auth files around is easy to get wrong, and it is hard to tell which account a new session will use.
47
49
 
48
50
  Instead, Ditto CLI launches each tool pointed at the selected profile:
49
51
 
@@ -54,16 +56,17 @@ Instead, Ditto CLI launches each tool pointed at the selected profile:
54
56
  | opencode | `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, and `XDG_STATE_HOME` under `~/.ditto/profiles/<name>/opencode` |
55
57
  | OMP | `omp --profile <name>` and `OMP_PROFILE=<name>` |
56
58
  | Prime Agent | `PRIME_AGENT_CODING_AGENT_DIR=~/.ditto/profiles/<name>/prime-agent` and a matching `PRIME_AGENT_SESSION_DIR` |
59
+ | Pi | `PI_CODING_AGENT_DIR=~/.ditto/profiles/<name>/pi` and a matching `PI_CODING_AGENT_SESSION_DIR` |
57
60
 
58
61
  opencode has no single home variable; it resolves its directories the XDG way, so Ditto CLI pins the three bases that hold credentials, configuration, and session state. `XDG_CACHE_HOME` is deliberately left alone so profiles keep sharing opencode's downloaded tooling. Those variables are set for the launched process and anything it starts, including commands opencode's own tools run.
59
62
 
60
- Prime Agent's own settings can name a session directory, so managed profiles also set `PRIME_AGENT_SESSION_DIR` explicitly. That keeps transcripts, session artifacts, and local harness state inside the selected profile even while reusable Prime Agent settings and capabilities are linked to yours.
63
+ Prime Agent and Pi settings can name a session directory, so managed profiles set `PRIME_AGENT_SESSION_DIR` or `PI_CODING_AGENT_SESSION_DIR` explicitly. That keeps transcripts and local harness state inside the selected profile even while reusable settings and capabilities are linked to yours.
61
64
 
62
65
  No config files are swapped. Profiles remain independent, and switching only affects the process Ditto CLI launched.
63
66
 
64
67
  ## Install
65
68
 
66
- Ditto CLI needs at least one of the supported CLIs to be useful: [Claude Code](https://code.claude.com/docs/en/setup), [OpenAI Codex CLI](https://github.com/openai/codex), [opencode](https://opencode.ai/docs/), [Oh My Pi](https://github.com/can1357/oh-my-pi), or [Prime Agent](https://github.com/PrimeIntellect-ai/prime-agent).
69
+ Ditto CLI needs at least one of the supported CLIs to be useful: [Claude Code](https://code.claude.com/docs/en/setup), [OpenAI Codex CLI](https://github.com/openai/codex), [opencode](https://opencode.ai/docs/), [Oh My Pi](https://github.com/can1357/oh-my-pi), [Prime Agent](https://github.com/PrimeIntellect-ai/prime-agent), or [Pi](https://pi.dev).
67
70
 
68
71
  On macOS and Linux, Homebrew installs the prebuilt binary for your platform, so it needs no Rust toolchain:
69
72
 
@@ -150,7 +153,7 @@ Then:
150
153
  1. Press `n` and name the profile, such as `work`.
151
154
  2. Select the profile and press `l`, then choose Claude Code, Codex, opencode, or Prime Agent. Prime Agent opens directly on its `/login` dialog.
152
155
  3. Press `c` for Claude Code, `x` for Codex, `o` for opencode, or `a` for Prime Agent.
153
- 4. Press `p` for OMP, then use `/login` inside OMP.
156
+ 4. Press `p` for OMP or `i` for Pi, then use `/login` inside it.
154
157
 
155
158
  Each tool keeps its own credentials. Signing in to one does not copy credentials into another.
156
159
 
@@ -164,6 +167,7 @@ Each tool keeps its own credentials. Signing in to one does not copy credentials
164
167
  | `o` | Launch opencode |
165
168
  | `p` | Launch OMP |
166
169
  | `a` | Launch Prime Agent |
170
+ | `i` | Launch Pi |
167
171
  | `l` | Sign in with Claude Code, Codex, opencode, or Prime Agent |
168
172
  | `L` | Sign out, with confirmation |
169
173
  | `n` | Create a profile |
@@ -176,7 +180,7 @@ Sign-in status is checked in the background, so the list stays responsive while
176
180
 
177
181
  The selected profile is remembered for the next run. The `★` default is separate and stays put: it is the profile every command uses when you leave the name out, and running `ditto-cli claude personal` once does not move it. Any profile can be the default, including the built-in `default` one. See [which profile a command uses](#which-profile-a-command-uses).
178
182
 
179
- Renaming keeps the profile's settings, session history, and its Codex, opencode, and Prime Agent logins. Claude Code is the exception, and the rename dialog says so before you commit to it: see [renaming a profile signs Claude Code out](#renaming-a-profile-signs-claude-code-out). The built-in `default` profile cannot be renamed.
183
+ Renaming keeps the profile's settings, session history, and its Codex, opencode, Prime Agent, and Pi logins. Claude Code is the exception, and the rename dialog says so before you commit to it: see [renaming a profile signs Claude Code out](#renaming-a-profile-signs-claude-code-out). The built-in `default` profile cannot be renamed.
180
184
 
181
185
  ## Command-line usage
182
186
 
@@ -188,9 +192,11 @@ ditto-cli create work
188
192
  ditto-cli rename work client-a
189
193
  ditto-cli delete work --yes # removes credentials and sessions for good
190
194
  ditto-cli list
191
- ditto-cli status client-a # sign-in state for all five tools
195
+ ditto-cli status client-a # sign-in state for all six tools
192
196
  ditto-cli paths client-a
193
- ditto-cli sync client-a # re-copy your Claude Code settings into it
197
+ ditto-cli sync client-a # preserve configuration for one profile
198
+ ditto-cli sync --all # preserve it for every managed profile
199
+ ditto-cli sync --all --history # also backfill existing conversations
194
200
 
195
201
  # Launch a tool, with short aliases where shown
196
202
  ditto-cli claude client-a # or: cc
@@ -198,6 +204,7 @@ ditto-cli codex client-a # or: cx
198
204
  ditto-cli opencode client-a # or: oc
199
205
  ditto-cli omp client-a
200
206
  ditto-cli prime-agent client-a # or: pa
207
+ ditto-cli pi client-a
201
208
 
202
209
  # Pass arguments to the underlying CLI after --
203
210
  ditto-cli claude client-a -- --model opus
@@ -205,6 +212,7 @@ ditto-cli codex client-a -- --search
205
212
  ditto-cli opencode client-a -- --model anthropic/claude-opus-5
206
213
  ditto-cli omp client-a -- --model opus
207
214
  ditto-cli prime-agent client-a -- --model claude-opus-4-1
215
+ ditto-cli pi client-a -- --model anthropic/claude-opus-4-6
208
216
 
209
217
  # Bind a directory to a profile
210
218
  ditto-cli workspace # what this directory launches with
@@ -237,10 +245,11 @@ ditto-cli opencode client-a -- auth login
237
245
  ditto-cli prime-agent client-a -- /login
238
246
  ```
239
247
 
240
- OMP exposes login only inside its interface. Launch the selected profile, then run `/login` or `/logout` there:
248
+ OMP and Pi expose login only inside their interfaces. Launch the selected profile, then run `/login` or `/logout` there:
241
249
 
242
250
  ```bash
243
251
  ditto-cli omp client-a
252
+ ditto-cli pi client-a
244
253
  ```
245
254
 
246
255
  Deleting is the one command that destroys something, so it asks to be meant. Without `--yes` it lists the directories it would remove and stops. The built-in `default` profile cannot be deleted; it is your own configuration, which Ditto CLI never created.
@@ -412,7 +421,7 @@ Every tool also names the profile in the window and tab title:
412
421
  ditto:client-a — Codex — my-repo
413
422
  ```
414
423
 
415
- All five tools write their own titles and keep updating them as you work, so a title set once before handing over is overwritten within moments. Instead, Ditto CLI runs the tool in a pseudoterminal and rewrites the title sequences on their way to the terminal, adding `ditto:<profile>` in front of whatever the tool called itself. You keep the tool's own title and gain the profile.
424
+ All six tools write their own titles and keep updating them as you work, so a title set once before handing over is overwritten within moments. Instead, Ditto CLI runs the tool in a pseudoterminal and rewrites the title sequences on their way to the terminal, adding `ditto:<profile>` in front of whatever the tool called itself. You keep the tool's own title and gain the profile.
416
425
 
417
426
  Everything else is forwarded byte for byte. Colours, hyperlinks, clipboard writes, mouse reporting, and anything the tool draws are untouched, and the tool still gets a real terminal, the right window size, and your keystrokes as it always did. Ditto CLI exits with the tool's own exit status.
418
427
 
@@ -448,12 +457,13 @@ ditto-cli --json status client-a
448
457
  { "tool": "codex", "label": "Codex", "status": "signed_out", "signed_in": false },
449
458
  { "tool": "opencode", "label": "opencode", "status": "signed_in", "signed_in": true },
450
459
  { "tool": "omp", "label": "OMP", "status": "signed_out", "signed_in": false },
451
- { "tool": "prime-agent", "label": "Prime Agent", "status": "signed_in", "signed_in": true }
460
+ { "tool": "prime-agent", "label": "Prime Agent", "status": "signed_in", "signed_in": true },
461
+ { "tool": "pi", "label": "Pi", "status": "signed_out", "signed_in": false }
452
462
  ]
453
463
  }
454
464
  ```
455
465
 
456
- `list`, `status`, `paths`, `create`, `rename`, `delete`, `default`, `workspace`, and `indicator` all answer in JSON. Errors become `{"error": "..."}` on stderr, and every failure exits 1. `shell-init` prints a script for a shell to read rather than a report, so `--json` has nothing to do there.
466
+ `list`, `status`, `paths`, `create`, `rename`, `delete`, `sync`, `default`, `workspace`, and `indicator` all answer in JSON. Errors become `{"error": "..."}` on stderr, and every failure exits 1. `shell-init` prints a script for a shell to read rather than a report, so `--json` has nothing to do there.
457
467
 
458
468
  Running `ditto-cli` with no subcommand opens the picker, which needs an interactive terminal. Without one it exits 1 and names the commands to use instead, rather than failing on a terminal that was never there.
459
469
 
@@ -473,11 +483,12 @@ So creating a profile copies `~/.claude/settings.json` into it. What Ditto CLI i
473
483
  From then on the profile's settings are its own. Change the model in one profile and the others keep theirs; a later `ditto-cli sync` fills in settings the profile has never answered and leaves the ones it has:
474
484
 
475
485
  ```bash
476
- ditto-cli sync client-a # bring it up to date, keeping its own answers
486
+ ditto-cli sync client-a # bring one profile up to date
487
+ ditto-cli sync --all # bring every managed profile up to date
477
488
  ditto-cli sync client-a --overwrite # your configuration wins outright
478
489
  ```
479
490
 
480
- `sync` is also how profiles created before this behaviour existed catch up.
491
+ Naming a profile preserves configuration for that profile only; `--all` makes the scope every managed profile. `sync` is also how profiles created before this behaviour existed catch up, including tool directories added by a newer Ditto release.
481
492
 
482
493
  ## Skills, subagents, and everything else you set up once
483
494
 
@@ -490,8 +501,18 @@ A profile exists to be signed in as somebody else, not to be a different working
490
501
  | opencode | the whole configuration directory |
491
502
  | OMP | `config.yml`, `extensions` |
492
503
  | Prime Agent | `settings.json`, `keybindings.json`, instructions, prompts, skills, extensions, themes, packages, and the global harness |
504
+ | Pi | `settings.json`, `keybindings.json`, project trust, instructions, prompts, skills, extensions, themes, packages, and managed tools |
493
505
 
494
- These are symbolic links, so a skill you write tomorrow is in every profile the moment you save it, with nothing to sync and no copies to drift apart. Everything else — `.claude.json`, `auth.json`, sessions, session artifacts, history, `agent.db` — stays inside the profile, which is the whole of what a profile keeps to itself. Prime Agent's `models.json` also stays private because custom provider definitions are allowed to contain literal API keys and secret headers.
506
+ These are symbolic links, so a skill you write tomorrow is in every profile the moment you save it, with nothing to sync and no copies to drift apart. Everything else — `.claude.json`, `auth.json`, sessions, session artifacts, history, `agent.db` — stays inside the profile, which is the whole of what a profile keeps to itself. Prime Agent and Pi keep `models.json` private too, because custom provider definitions may contain literal API keys and secret headers.
507
+
508
+ Conversation history is not linked: chats can contain account- or client-specific work, and shared writable session stores would make every profile's future activity visible to every other profile. Existing Claude Code, Codex, opencode, OMP, Prime Agent, and Pi conversations can instead be copied once, without replacing anything already in the destination. Choose one profile explicitly or all managed profiles explicitly:
509
+
510
+ ```bash
511
+ ditto-cli sync client-a --history
512
+ ditto-cli sync --all --history
513
+ ```
514
+
515
+ After the copy, every tool keeps writing to that profile's own history store.
495
516
 
496
517
  What is shared is a named list rather than everything-but-the-credentials. Ditto CLI learning about a new extension directory late costs you a missing feature; sharing a new credential file by accident would cost you the isolation the tool exists for.
497
518
 
@@ -499,6 +520,7 @@ Profiles created before this have real directories where the links go. `sync` re
499
520
 
500
521
  ```bash
501
522
  ditto-cli sync client-a # link what can be linked, report what cannot
523
+ ditto-cli sync --all # do that for every managed profile
502
524
  ditto-cli sync client-a --adopt # replace the profile's own copies too
503
525
  ```
504
526
 
@@ -518,13 +540,14 @@ ditto-cli: repaired claude/skills/apple-design; it was installed pointing at not
518
540
 
519
541
  ## Where credentials and files are stored
520
542
 
521
- Ditto CLI does not ask for passwords, parse OAuth tokens, or keep credentials in its state file. Claude Code, Codex, and opencode authentication still runs through their installed CLIs, and OMP and Prime Agent authentication through `/login` inside their interfaces. Each tool stores the result wherever it normally would, under the directory Ditto CLI pointed it at:
543
+ Ditto CLI does not ask for passwords, parse OAuth tokens, or keep credentials in its state file. Claude Code, Codex, and opencode authentication still runs through their installed CLIs, and OMP, Prime Agent, and Pi authentication through `/login` inside their interfaces. Each tool stores the result wherever it normally would, under the directory Ditto CLI pointed it at:
522
544
 
523
545
  - **Claude Code** uses the selected `CLAUDE_CONFIG_DIR`. On macOS the credentials themselves stay in the system Keychain, keyed to that directory's path, which is what keeps two profiles from sharing one login — and why [renaming a profile signs Claude Code out](#renaming-a-profile-signs-claude-code-out).
524
546
  - **Codex** keeps its auth state under the selected `CODEX_HOME`.
525
547
  - **opencode** writes `auth.json` into the selected data directory.
526
548
  - **OMP** keeps auth, settings, sessions, and caches under `~/.omp/profiles/<name>/agent`.
527
549
  - **Prime Agent** keeps ordinary provider credentials in the selected agent directory's `auth.json`; its sessions and session artifacts stay below the same profile.
550
+ - **Pi** keeps provider credentials in the selected agent directory's `auth.json`; `PI_CODING_AGENT_SESSION_DIR` keeps its transcripts below the same profile.
528
551
 
529
552
  Prime Agent currently has two upstream exceptions to that boundary. Prime Inference login uses the Prime CLI credential at `~/.prime/config.json`, for which Prime Agent exposes no path override; that one provider therefore remains shared across Ditto profiles. `PRIME_API_KEY` and other API-key environment variables are shared for the same reason any inherited environment credential is. Prime Agent also uses one user-wide background-service socket, so its `agents`, `list`, and `attach` views can see running agents from other profiles even though each agent receives its selected auth and session roots. Ditto's status report counts provider credentials in the isolated `auth.json`, not these ambient sources.
530
553
 
@@ -542,19 +565,21 @@ Ditto CLI's own files are laid out like this:
542
565
  │ │ ├── config/opencode/
543
566
  │ │ ├── data/opencode/ # auth.json lives here
544
567
  │ │ └── state/opencode/
545
- └── prime-agent/ # auth.json and sessions live here
568
+ ├── prime-agent/ # auth.json and sessions live here
569
+ │ └── pi/ # auth.json and sessions live here
546
570
  └── personal/
547
571
  ├── claude/
548
572
  ├── codex/
549
573
  ├── opencode/
550
- └── prime-agent/
574
+ ├── prime-agent/
575
+ └── pi/
551
576
  ```
552
577
 
553
578
  The nested `opencode/` directory is opencode's own doing: it appends its name to every XDG base it is given. OMP profiles are the one thing kept outside this tree, since OMP manages its own profile directory.
554
579
 
555
580
  Directories are created with user-only permissions on macOS and Linux; see [Windows notes](#windows-notes) for the difference there.
556
581
 
557
- The `default` profile points to `~/.claude`, `~/.codex`, opencode's own `~/.local/share/opencode` and `~/.config/opencode` (or wherever your `XDG_*` variables already send them), OMP's native `~/.omp/agent` profile, and Prime Agent's `~/.prime/agent` directory (or `PRIME_AGENT_CODING_AGENT_DIR` when set). It exposes your existing setup without copying or migrating anything. For opencode the `default` profile resolves the same XDG bases opencode would pick on its own, so pointing at it changes nothing.
582
+ The `default` profile points to `~/.claude`, `~/.codex`, opencode's own `~/.local/share/opencode` and `~/.config/opencode` (or wherever your `XDG_*` variables already send them), OMP's native `~/.omp/agent` profile, Prime Agent's `~/.prime/agent` directory (or `PRIME_AGENT_CODING_AGENT_DIR` when set), and Pi's `~/.pi/agent` directory (or `PI_CODING_AGENT_DIR` when set). It exposes your existing setup without copying or migrating anything. For opencode the `default` profile resolves the same XDG bases opencode would pick on its own, so pointing at it changes nothing.
558
583
 
559
584
  ## Environment variables
560
585
 
@@ -566,6 +591,7 @@ The `default` profile points to `~/.claude`, `~/.codex`, opencode's own `~/.loca
566
591
  | `DITTO_OPENCODE_BIN` | Override the `opencode` executable |
567
592
  | `DITTO_OMP_BIN` | Override the `omp` executable |
568
593
  | `DITTO_PRIME_AGENT_BIN` | Override the `prime-agent` executable |
594
+ | `DITTO_PI_BIN` | Override the `pi` executable |
569
595
  | `DITTO_PROFILE` | Selected profile name exported to every launched tool, and what Claude Code's status line reports |
570
596
  | `DITTO_NO_PROXY` | Hand the terminal straight to the tool, leaving the title to it (macOS and Linux) |
571
597
  | `HERDR_PANE_ID` | Read, not set: herdr names the pane it opened, and Ditto CLI steps aside and reports the profile to herdr. See [Under herdr](#under-herdr) |
@@ -589,7 +615,7 @@ Ditto CLI warns before the rename and tells you how to get back in:
589
615
  ditto-cli claude client-a -- auth login
590
616
  ```
591
617
 
592
- Codex, opencode, and Prime Agent keep their ordinary credentials in files inside the profile, so they survive a rename untouched.
618
+ Codex, opencode, Prime Agent, and Pi keep their ordinary credentials in files inside the profile, so they survive a rename untouched.
593
619
 
594
620
  ## Windows notes
595
621
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reyanshgupta/ditto-cli",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Switch between Claude Code, Codex, opencode, OMP, and Prime Agent accounts",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -33,9 +33,9 @@
33
33
  "node": ">=18"
34
34
  },
35
35
  "optionalDependencies": {
36
- "@reyanshgupta/ditto-cli-darwin-arm64": "0.3.5",
37
- "@reyanshgupta/ditto-cli-darwin-x64": "0.3.5",
38
- "@reyanshgupta/ditto-cli-linux-x64": "0.3.5",
39
- "@reyanshgupta/ditto-cli-win32-x64": "0.3.5"
36
+ "@reyanshgupta/ditto-cli-darwin-arm64": "0.3.7",
37
+ "@reyanshgupta/ditto-cli-darwin-x64": "0.3.7",
38
+ "@reyanshgupta/ditto-cli-linux-x64": "0.3.7",
39
+ "@reyanshgupta/ditto-cli-win32-x64": "0.3.7"
40
40
  }
41
41
  }