tui-plugins
Plugins for tmui and stui, open source (MIT). Another CLI's output as a table in the tool, and its commands on keys and on the command line inside it.
A plugin brings another CLI into tmui or
stui: its output as a view in the tool's table, and its
commands on keys and on the : line. A plugin is one file, plugin.json, and
nothing runs that the file does not spell out. tmui and stui read the same
files. The plugins, the format (SPEC.md,
plugin.json v 1) and the checker are in
sophonz-labs/tui-plugins (MIT).
Installing
tmui ext install gh-prs # from the repository's main branch
tmui ext install ./my-plugin # a directory with a plugin.json, or a path or URL to one
tmui ext list # the plugins, and what was left out of them
tmui ext remove gh-prsstui takes the same commands: stui ext install gh-prs. The command is ext
in both because stui plugin was already taken: it installs stui's
orchestration skills for coding agents.
Before writing anything, install checks the file against the spec, prints
every command the plugin will run, and asks y/N (-y skips the question). It
writes to the tool's own directory, ~/.config/<tool>/plugins/<name>/. A
plugin you put in ~/.config/tui-plugins/<name>/ by hand is read by both tools;
when both directories have one of the same name, the tool's own wins.
Inside the tool, :ext lists the plugins, what each one added and what was
left out, and ? shows the keys. A plugin view opens with :<name>, such as
:prs. In stui, a key a plugin puts on panes works on the agents view too.
The plugins
| Plugin | Needs | Adds |
|---|---|---|
gh-prs | gh | :prs, the pane's repository's pull requests (P on a pane or window): o browser, d diff, c checks, C check out |
gh-runs | gh | :gh-runs, its GitHub Actions runs (A on a pane or window): w watch in a popup, o browser, L failed logs, r rerun failed |
docker-ps | docker | :containers: L logs, e shell, i inspect, S stop |
kubectl-pods | kubectl | :pods in the current context: L logs, d describe, e shell, D delete |
git-status | git | :git-status of the pane's directory (S on a pane or window): d diff, a stage, u unstage |
lazygit | lazygit | L on a session, window or pane, and :lazygit, in the pane's directory |
A plugin whose program is not on PATH still loads, and :ext says what is
missing.
Writing one
A plugin has v, name and at least one of views, actions and commands.
This one lists the files in the pane's directory and opens one in less:
{
"v": 1,
"name": "files",
"description": "Files in the pane's directory.",
"views": [
{
"name": "files",
"run": ["ls", "-1"],
"format": "lines",
"cwd": "pane"
}
],
"actions": [
{ "key": "F", "title": "files", "scopes": ["panes", "windows"], "open": "files" },
{ "key": "v", "title": "view", "scopes": ["files"], "run": ["less", "{line}"], "mode": "foreground" }
]
}- Views run a command and show its output as a table:
json(an array, or one object per line),tsvwith a header line, orlines. Fields of the row under the cursor are placeholders, here{line}; so are{session},{window},{pane},{pane_cwd}and{pane_command}. - Actions are keys on some views, which run a command or open a view.
Commands are
:<name> [args]. runis argv with no shell. A placeholder fills part of one argument and never splits it, so a field holdingx; rm -rf ~runs nothing.modeisbackground(the default),foreground(the command gets the terminal) orpopup(a tmux popup).confirmasks y/N first.- Unknown fields are an error, so a misspelt
"confirm"cannot quietly run without asking.
Some keys are reserved on every view and a manifest that binds one is invalid:
j k g G h l q / : ? enter esc ctrl-b ctrl-f ctrl-r ctrl-c ctrl-e y Y and the
digits. y copies the row's value (on a plugin view, its url field when it
has one, else its id) and Y the whole row. A key the tool uses on its own
views, or one another plugin already took there, is left out and reported in
:ext; the tool's own key always wins.
Everything else (refresh, timeouts, nested JSON fields, literal braces) is in SPEC.md.
To try a plugin, install it from its directory:
tmui ext install ./my-pluginIn a clone of tui-plugins, go run ./check . checks every
plugins/<name>/plugin.json the way the repository's CI does: the spec, the
views each action names, no two plugins taking one : name, and a line for each
in the README.
Sending one to the repository
A pull request adds the plugin's directory under plugins/ and its line in the
README's table. How to send one is in
CONTRIBUTING.md.