
Screenshot: weave --- bun run dev --- bun run test
weave is a CLI/TUI for running multiple long-running commands and “weaving” together their output. I use it to solve a persistent pain point of mine — running multiple dev servers / watchers / etc. at once.
I wrote it as a weekend project after being inspired by a coworker’s comment about Ink, a library for writing CLI UIs with React.
At a high level, the syntax is:
weave --- [command1] [...args] --- [command2] [..args] --- etc.
In other words, you separate each of the commands you want to run with a triple-hyphen.
weave
will split the list of arguments into multiple commands, run them separately, and launch a persistent terminal UI to monitor the process output.
So, weave --- bun run dev --- bun run test
will:
- Launch a
weave
process with terminal UI. - Create a
bun run dev
subprocess. - Create a
bun run test
subprocess. - Display the output of the subprocesses.
It also has support for scrolling through the output, restarting subprocesses, and saving log output to a file.
One of my favorite things about weave
is that it’s available as a single-file executable for multiple platforms, thanks to Bun’s single-file executable mode. That means you don’t need any dependencies (node
, etc.) to install weave
— just download the executable from the latest release and you’re good to go.
You can read the README for more details about features, installation, etc.
Learnings / Tricky business
I wanted to implement mouse support for weave
, specifically the ability to scroll with the mouse wheel. While I did eventually get this working (using a fork of the ink-mouse library), it also caused some problems.
For one, captured mouse input is no longer sent to the actual terminal, meaning you can’t do normal mouse things like selecting text.
Also, the escape codes for mouse input are incidentally fed into the Ink standard useInput
hook used to capture keyboard input, which caused me a fair bit of confusion at first.
Ultimately I’m not sure if the ability to scroll with the mouse wheel is worth losing the ability to select text, so in the future “mouse mode” might become an option instead of the default behavior.
The other issue I ran into was with emojis (like the ✨ in the screenshot at the top of this post). A single emoji can render as two characters wide, but the string length algorithm in Ink seems to treat them as just a single character width. This results in confusing behavior around lines wrapping when they shouldn’t.
It seems this is an evergreen issue, as it’s seemingly been fixed in the past, but there is also a new open issue about it.
I’m sympathetic to the complexity of character width and rendering issues, so in the end I just worked around this in weave
by removing the vertical borders that were causing problems.
Overall, though, I was quite impressed by Ink and the strange magic of using React to write CLI apps.