v0.4.0
What changed
Fix two ways the terminal proxy mishandled what it sits between
An OSC sequence carrying no argument came back out carrying one. The
filter split a collected command into its number and its text and then
always wrote the separator back, so ESC ] 112 BEL reached the terminal
as ESC ] 112 ; BEL. The two are not the same request: OSC 104 resets
the whole palette and OSC 112 the cursor colour, while the ; forms
name nothing to reset and are ignored. A tool putting the cursor colour
back on its way out therefore did not, and the claim that everything
which is not a title is forwarded byte for byte was not true. The
difference between no argument and an empty one is now carried through
split_command and write_command.
A proxy that failed after the tool had started launched a second copy of
it. launch answers an error from run by handing the terminal to the
tool itself, which is right when the pseudoterminal could not be set up
and wrong once spawn has returned: raw mode, the descriptor clones and
the read loop can all fail with the tool already running, and the first
copy was then left in a pseudoterminal nobody was reading while a second
started against the same profile. Everything that can fail past the
spawn has left the tool with no terminal, so there is nothing to keep;
the child is killed and reaped before the error goes up.
Size a notice from a width a wide terminal cannot overflow
notice_height multiplied by 64 before widening, and the width it was
given is a u16, so a terminal past 1023 columns wrapped around before
the division ever happened. A debug build panics on it; a release build
takes the wrapped number and sizes the popup from nonsense. Widening
first costs nothing and the arithmetic no longer depends on how wide the
terminal is.
Say what copying a profile's settings does to the status line
AGENTS.md said statusLine was the one key never copied. It has not
been since indicator::inherit existed: the entry cannot travel because
it names the profile it was installed for, but the status line beneath
it is the user's own and does travel, wrapped in the new profile's
statusline --with. Dropping the key outright is what that change
stopped doing, and README.md has described the current behaviour all
along, so this was the one file left disagreeing with both the code and
its tests.
Also add workspace.rs to the layout table, which has been missing
since the per-directory binding landed.
Make the README easier to find your way around
The prose was fine; getting to the right paragraph was not. Six hundred
lines and thirty headings had no table of contents, so add one grouped
by what a reader came for rather than by document order.
Replace the hand-drawn interface mock with a real one. It was drawn by
hand and had drifted: one footer row was a column short of the others
and three rows were off centre, which is a poor first thing to see. The
new block is the picker's own output captured at eighty columns, with
the sign-in glyphs set to a mix worth illustrating.
Lead with what a profile keeps and what it shares, since that is the
question the tool exists to answer, and put three commands above the
screenshot so the shape of it lands before the scrolling starts.
Give Install a table of the four channels. It read as eight alternating
paragraphs and code blocks with nothing saying which one to take. Break
the forty-eight line block under Command-line usage into named groups,
and turn the launch commands into a table pairing each tool with its
alias and an example of passing arguments through.
Rewrite the Quick start steps, which overlapped and disagreed with each
other about which key does what, and fold two reference passages into
details blocks rather than leaving them across the reader's path.
Windows notes lists three differences, so stop calling them two.
Add every agent Orca runs, step aside under Orca, and a launcher in the picker
Ditto now launches the 29 coding agents Orca runs that it did not already:
Gemini CLI, Qwen Code, OpenClaude, Copilot, Cursor Agent, Grok, Devin, Kimi
Code, Cline, Codebuff, Continue, Command Code, Hermes Agent, OpenClaw,
Mistral Vibe, Rovo Dev, Amp, Droid, Goose, Aider, Crush, Kilo Code, Kiro,
Auggie, Antigravity, MiMo Code, Ante, Trae, and Autohand. Each is one entry
in src/tools.rs: which variable, XDG bases, or private HOME points it at a
profile, which file means it is signed in, what is shared and what is
copied once. One Tool::Generic arm in each module reads the entry. They are
launched by name through one external subcommand, listed by --help, and
picked up by status, paths, sync, and shell-init automatically.
Under Orca (ORCA_PANE_KEY) the pseudoterminal proxy is skipped, since Orca
reads the foreground process and the anchored titles the proxy rewrites,
and the default profile follows an ambient CODEX_HOME so Orca's own Codex
account switcher composes with Ditto.
The picker gains a launcher: Enter or t lists every installed tool,
filtered as you type, with its sign-in state. Tool shortcuts wrap on narrow
terminals. The private-home facade generalises to nested paths and never
mirrors a directory that holds part of the profile.
Also brings in fx support: a private home with the user's own mirrored into
it, and the Keychain refused so the login stays inside the profile.
Install
brew install reyanshgupta/tap/ditto-cli # or: brew upgrade ditto-cli
npm install -g @reyanshgupta/ditto-cli@0.4.0
cargo binstall ditto-cli # or: cargo install ditto-cliThe archives below are the same binaries every channel installs; SHA256SUMS covers them.
Full Changelog: v0.3.7...v0.4.0