@reyanshgupta/ditto-cli 0.3.4 → 0.3.6
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.
- package/README.md +46 -19
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
[](https://www.rust-lang.org/)
|
|
7
7
|
|
|
8
|
-
Keep work, personal, and client Claude Code, Codex, opencode, OMP,
|
|
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
|
|
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
|
-
│
|
|
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,
|
|
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
|
|
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),
|
|
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
|
|
|
@@ -131,7 +134,7 @@ ditto-cli update --check # compare versions without installing
|
|
|
131
134
|
ditto-cli update --git # install from the Git repository instead
|
|
132
135
|
```
|
|
133
136
|
|
|
134
|
-
`update` runs `cargo install` for you, so it needs Rust on your `PATH`. It stops early when you already have the newest release. Asking crates.io for the published version needs a network connection; without one it says so and installs anyway.
|
|
137
|
+
`update` runs `cargo install` for you, so it needs Rust on your `PATH`. It stops early when you already have the newest release. During a build it shows a compact animated status instead of Cargo's full compilation log; if the build fails, it prints that log so the error is not hidden. Asking crates.io for the published version needs a network connection; without one it says so and installs anyway.
|
|
135
138
|
|
|
136
139
|
`update` only replaces a copy in Cargo's own bin directory. Run it against a Homebrew install, or a binary from the [releases page](https://github.com/reyanshgupta/ditto-cli/releases), and it says so before it starts, then leaves that copy alone: a `cargo install` would land in a different directory and shadow the existing binary rather than replace it. Use `brew upgrade ditto-cli` or the newer archive instead.
|
|
137
140
|
|
|
@@ -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
|
|
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,
|
|
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,7 +192,7 @@ 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
|
|
195
|
+
ditto-cli status client-a # sign-in state for all six tools
|
|
192
196
|
ditto-cli paths client-a
|
|
193
197
|
ditto-cli sync client-a # re-copy your Claude Code settings into it
|
|
194
198
|
|
|
@@ -198,6 +202,7 @@ ditto-cli codex client-a # or: cx
|
|
|
198
202
|
ditto-cli opencode client-a # or: oc
|
|
199
203
|
ditto-cli omp client-a
|
|
200
204
|
ditto-cli prime-agent client-a # or: pa
|
|
205
|
+
ditto-cli pi client-a
|
|
201
206
|
|
|
202
207
|
# Pass arguments to the underlying CLI after --
|
|
203
208
|
ditto-cli claude client-a -- --model opus
|
|
@@ -205,6 +210,7 @@ ditto-cli codex client-a -- --search
|
|
|
205
210
|
ditto-cli opencode client-a -- --model anthropic/claude-opus-5
|
|
206
211
|
ditto-cli omp client-a -- --model opus
|
|
207
212
|
ditto-cli prime-agent client-a -- --model claude-opus-4-1
|
|
213
|
+
ditto-cli pi client-a -- --model anthropic/claude-opus-4-6
|
|
208
214
|
|
|
209
215
|
# Bind a directory to a profile
|
|
210
216
|
ditto-cli workspace # what this directory launches with
|
|
@@ -237,10 +243,11 @@ ditto-cli opencode client-a -- auth login
|
|
|
237
243
|
ditto-cli prime-agent client-a -- /login
|
|
238
244
|
```
|
|
239
245
|
|
|
240
|
-
OMP
|
|
246
|
+
OMP and Pi expose login only inside their interfaces. Launch the selected profile, then run `/login` or `/logout` there:
|
|
241
247
|
|
|
242
248
|
```bash
|
|
243
249
|
ditto-cli omp client-a
|
|
250
|
+
ditto-cli pi client-a
|
|
244
251
|
```
|
|
245
252
|
|
|
246
253
|
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 +419,7 @@ Every tool also names the profile in the window and tab title:
|
|
|
412
419
|
ditto:client-a — Codex — my-repo
|
|
413
420
|
```
|
|
414
421
|
|
|
415
|
-
All
|
|
422
|
+
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
423
|
|
|
417
424
|
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
425
|
|
|
@@ -448,7 +455,8 @@ ditto-cli --json status client-a
|
|
|
448
455
|
{ "tool": "codex", "label": "Codex", "status": "signed_out", "signed_in": false },
|
|
449
456
|
{ "tool": "opencode", "label": "opencode", "status": "signed_in", "signed_in": true },
|
|
450
457
|
{ "tool": "omp", "label": "OMP", "status": "signed_out", "signed_in": false },
|
|
451
|
-
{ "tool": "prime-agent", "label": "Prime Agent", "status": "signed_in", "signed_in": true }
|
|
458
|
+
{ "tool": "prime-agent", "label": "Prime Agent", "status": "signed_in", "signed_in": true },
|
|
459
|
+
{ "tool": "pi", "label": "Pi", "status": "signed_out", "signed_in": false }
|
|
452
460
|
]
|
|
453
461
|
}
|
|
454
462
|
```
|
|
@@ -490,8 +498,9 @@ A profile exists to be signed in as somebody else, not to be a different working
|
|
|
490
498
|
| opencode | the whole configuration directory |
|
|
491
499
|
| OMP | `config.yml`, `extensions` |
|
|
492
500
|
| Prime Agent | `settings.json`, `keybindings.json`, instructions, prompts, skills, extensions, themes, packages, and the global harness |
|
|
501
|
+
| Pi | `settings.json`, `keybindings.json`, project trust, instructions, prompts, skills, extensions, themes, packages, and managed tools |
|
|
493
502
|
|
|
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
|
|
503
|
+
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.
|
|
495
504
|
|
|
496
505
|
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
506
|
|
|
@@ -502,15 +511,30 @@ ditto-cli sync client-a # link what can be linked, report what cannot
|
|
|
502
511
|
ditto-cli sync client-a --adopt # replace the profile's own copies too
|
|
503
512
|
```
|
|
504
513
|
|
|
514
|
+
### Downloaded skills
|
|
515
|
+
|
|
516
|
+
Sharing a directory by linking it has one cost, and Ditto CLI pays it for you.
|
|
517
|
+
|
|
518
|
+
A skill installer — `npx skills add`, and anything else that installs into more than one agent — puts the skill somewhere central and then records it in each agent's skills directory as a *relative* link, computed from the directory the agent was pointed at. Under a profile that directory is one of the links above, so the operating system writes the record into your own configuration instead, where the same relative path leads somewhere else. The skill lands on disk intact and is readable from nowhere, in every profile at once.
|
|
519
|
+
|
|
520
|
+
Ditto CLI is what moved the directory, so Ditto CLI is what can say where those links meant to point. Launching a tool repairs its own, which is the moment before it reads them, and says so:
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
ditto-cli: repaired claude/skills/apple-design; it was installed pointing at nothing
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
`ditto-cli sync <profile>` does the same for every tool at once and reports them under `repaired`. A link is only rewritten when reading it against the path the installer was given names something that exists, so a link that is relative and broken for reasons of its own is left exactly as it is.
|
|
527
|
+
|
|
505
528
|
## Where credentials and files are stored
|
|
506
529
|
|
|
507
|
-
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
|
|
530
|
+
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:
|
|
508
531
|
|
|
509
532
|
- **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).
|
|
510
533
|
- **Codex** keeps its auth state under the selected `CODEX_HOME`.
|
|
511
534
|
- **opencode** writes `auth.json` into the selected data directory.
|
|
512
535
|
- **OMP** keeps auth, settings, sessions, and caches under `~/.omp/profiles/<name>/agent`.
|
|
513
536
|
- **Prime Agent** keeps ordinary provider credentials in the selected agent directory's `auth.json`; its sessions and session artifacts stay below the same profile.
|
|
537
|
+
- **Pi** keeps provider credentials in the selected agent directory's `auth.json`; `PI_CODING_AGENT_SESSION_DIR` keeps its transcripts below the same profile.
|
|
514
538
|
|
|
515
539
|
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.
|
|
516
540
|
|
|
@@ -528,19 +552,21 @@ Ditto CLI's own files are laid out like this:
|
|
|
528
552
|
│ │ ├── config/opencode/
|
|
529
553
|
│ │ ├── data/opencode/ # auth.json lives here
|
|
530
554
|
│ │ └── state/opencode/
|
|
531
|
-
│
|
|
555
|
+
│ ├── prime-agent/ # auth.json and sessions live here
|
|
556
|
+
│ └── pi/ # auth.json and sessions live here
|
|
532
557
|
└── personal/
|
|
533
558
|
├── claude/
|
|
534
559
|
├── codex/
|
|
535
560
|
├── opencode/
|
|
536
|
-
|
|
561
|
+
├── prime-agent/
|
|
562
|
+
└── pi/
|
|
537
563
|
```
|
|
538
564
|
|
|
539
565
|
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.
|
|
540
566
|
|
|
541
567
|
Directories are created with user-only permissions on macOS and Linux; see [Windows notes](#windows-notes) for the difference there.
|
|
542
568
|
|
|
543
|
-
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,
|
|
569
|
+
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.
|
|
544
570
|
|
|
545
571
|
## Environment variables
|
|
546
572
|
|
|
@@ -552,6 +578,7 @@ The `default` profile points to `~/.claude`, `~/.codex`, opencode's own `~/.loca
|
|
|
552
578
|
| `DITTO_OPENCODE_BIN` | Override the `opencode` executable |
|
|
553
579
|
| `DITTO_OMP_BIN` | Override the `omp` executable |
|
|
554
580
|
| `DITTO_PRIME_AGENT_BIN` | Override the `prime-agent` executable |
|
|
581
|
+
| `DITTO_PI_BIN` | Override the `pi` executable |
|
|
555
582
|
| `DITTO_PROFILE` | Selected profile name exported to every launched tool, and what Claude Code's status line reports |
|
|
556
583
|
| `DITTO_NO_PROXY` | Hand the terminal straight to the tool, leaving the title to it (macOS and Linux) |
|
|
557
584
|
| `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) |
|
|
@@ -575,7 +602,7 @@ Ditto CLI warns before the rename and tells you how to get back in:
|
|
|
575
602
|
ditto-cli claude client-a -- auth login
|
|
576
603
|
```
|
|
577
604
|
|
|
578
|
-
Codex, opencode,
|
|
605
|
+
Codex, opencode, Prime Agent, and Pi keep their ordinary credentials in files inside the profile, so they survive a rename untouched.
|
|
579
606
|
|
|
580
607
|
## Windows notes
|
|
581
608
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reyanshgupta/ditto-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
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.
|
|
37
|
-
"@reyanshgupta/ditto-cli-darwin-x64": "0.3.
|
|
38
|
-
"@reyanshgupta/ditto-cli-linux-x64": "0.3.
|
|
39
|
-
"@reyanshgupta/ditto-cli-win32-x64": "0.3.
|
|
36
|
+
"@reyanshgupta/ditto-cli-darwin-arm64": "0.3.6",
|
|
37
|
+
"@reyanshgupta/ditto-cli-darwin-x64": "0.3.6",
|
|
38
|
+
"@reyanshgupta/ditto-cli-linux-x64": "0.3.6",
|
|
39
|
+
"@reyanshgupta/ditto-cli-win32-x64": "0.3.6"
|
|
40
40
|
}
|
|
41
41
|
}
|