@vigent/cli 0.2.2 → 0.3.0
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 +86 -28
- package/dist/agents.js +29 -0
- package/dist/app.js +565 -21
- package/dist/attach.js +102 -0
- package/dist/choices.js +4 -1
- package/dist/cli-engines.js +15 -5
- package/dist/cli.js +25 -15
- package/dist/config.js +26 -2
- package/dist/diffview.js +1 -1
- package/dist/engines.js +18 -11
- package/dist/float.js +1 -1
- package/dist/hunk-review.js +218 -0
- package/dist/hunks.js +60 -0
- package/dist/icons.js +1 -0
- package/dist/keys.js +4 -1
- package/dist/main.js +16 -0
- package/dist/markdown.js +1 -1
- package/dist/notify.js +33 -0
- package/dist/pi-sdk.js +45 -0
- package/dist/pi-ui.js +78 -0
- package/dist/picker.js +92 -47
- package/dist/serve-page.js +247 -0
- package/dist/serve.js +267 -0
- package/dist/session.js +145 -10
- package/dist/settings.js +1 -1
- package/dist/templates.js +125 -0
- package/dist/theme.js +2 -0
- package/dist/tui.js +13 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A vim-style, lightweight terminal app for running several coding agents at once, built on the [pi](https://github.com/badlogic/pi-mono) engine. It can also drive the Claude Code, Codex and OpenCode CLIs you already have installed, with their own logins.
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
|
|
7
|
-

|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -14,10 +14,19 @@ npm install -g @vigent/cli
|
|
|
14
14
|
|
|
15
15
|
The package is `@vigent/cli` (npm doesn't accept the plain name `vigent`, which it finds too close to `vitest`); the command is `vigent`. Run `vigent` in a project, or `vigent <folder>` (`vigent .`, `vigent ~/code/app`) from anywhere.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
If you only run Claude Code, Codex or OpenCode, the light install leaves out the built-in pi engine and its model SDKs. It is 4 MB instead of about 200 MB. npm ignores `--omit=optional` with `-g`, so this installs into a folder of its own:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
20
|
+
npm install --prefix ~/.vigent --omit=optional @vigent/cli
|
|
21
|
+
ln -s ~/.vigent/node_modules/.bin/vigent ~/.local/bin/vigent # or put ~/.vigent/node_modules/.bin on PATH
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
pi then shows as not installed; the same command without `--omit=optional` adds it back. The light install also leaves out the bundled riftri, so worktrees are plain git ones unless riftri is on your PATH.
|
|
25
|
+
|
|
26
|
+
Requires Node.js 20 or newer and git. On Node 22.1 or newer, vigent keeps Node's compile cache, which makes later starts faster. Then, inside any git repository:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
vigent # your signed-in CLI (Claude Code, Codex, OpenCode), or pi with ANTHROPIC_API_KEY (or OPENAI_API_KEY / GEMINI_API_KEY)
|
|
21
30
|
vigent --engine claude # new agents run your installed Claude Code (also: codex, opencode, pi)
|
|
22
31
|
vigent --demo # scripted agents, nothing needed
|
|
23
32
|
vigent --help
|
|
@@ -29,13 +38,47 @@ vigent --help
|
|
|
29
38
|
|
|
30
39
|
Like LazyVim, vigent opens on a dashboard. Press `i` and type a task, `n` to name a new agent, `t` for themes, `s` for settings, `m` / `e` for model and effort, `c` to check engines, `?` for every key, or `q` to quit. Press `Space` (the leader) and pause, and a which-key panel lists every key that can follow and what it does. `Esc` closes it, and `:set nowhichkey` turns it off.
|
|
31
40
|
|
|
32
|
-

|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
### While several agents run
|
|
46
|
+
|
|
47
|
+
When an agent finishes, fails or needs you while you're looking at another one (or at another window), vigent rings the bell. In iTerm2, WezTerm, Ghostty and kitty it also sends a desktop notification, inside tmux too. The message line says which agent and the key to open it, and the agent gets a ◆ in the sidebar until you do. Set `notify` in `[ui]` (or `:settings`) to `"bell"`, `"desktop"` or `"off"`.
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
The statusline shows what the agent on screen has used, like `74.8k tok · $0.50`, and `:dash` adds up every agent. `:cost` lists each agent with its engine, tokens and cost, and the total. Costs are what each engine reports: Claude Code prices what it used at API rates even on a subscription, OpenCode prices each step, pi uses its model prices, and Codex reports tokens only. CLI agents keep their totals across restarts.
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
### From your phone
|
|
56
|
+
|
|
57
|
+
**`:serve`** lets you follow your agents from your phone, or start `vigent --serve` to have it on from the beginning. vigent shows an address on your network and an 8-character access code. Open the address on your phone and type the code, or open the link that already has the code in it.
|
|
58
|
+
|
|
59
|
+
The page uses your theme's colors. It lists your agents with their state, branch, changes and cost, and follows a reply as it streams. You can send a follow-up (it waits its turn if the agent is busy), stop an agent, or start a new one.
|
|
60
|
+
|
|
61
|
+

|
|
33
62
|
|
|
34
|
-
|
|
63
|
+
The code is new each time, and every request needs it. Prompts and stops need it in a header, so no other web page can send them through your browser. After 10 wrong codes the server stops answering. It's plain HTTP, so use it on your own Wi-Fi or over a VPN like Tailscale, not on public Wi-Fi. `:serve local` listens on this machine only, for an SSH tunnel. `:serve 9000` picks the port (the default is 8377). `:serve stop` ends it and retires the code.
|
|
35
64
|
|
|
36
65
|
### First agent
|
|
37
66
|
|
|
38
|
-
Inside a git repository, press `i`, type what you want done, and press Enter. An agent starts on it in its own worktree, using
|
|
67
|
+
Inside a git repository, press `i`, type what you want done, and press Enter. An agent starts on it in its own worktree, using the first CLI you're signed in to (Claude Code, Codex, OpenCode), with its own login and settings, or else pi if it has an API key (`:checkhealth` shows which). Watch it work, press `i` again to follow up, and `Esc` to go back to NORMAL mode. `:new <task> --engine codex` starts more agents, and `]s` / `[s` or `1`–`9` switch between them.
|
|
68
|
+
|
|
69
|
+
### Pointing an agent at files
|
|
70
|
+
|
|
71
|
+
Type `@` in a prompt and a file picker opens over it with the files in the agent's worktree (what git tracks plus new files, never what `.gitignore` hides). Type to narrow it, `Enter` writes `@src/cart.js`, `Esc` keeps a plain `@`, and `Backspace` takes the `@` back. Each engine gets the files its own way: Claude Code reads `@path` itself, OpenCode gets them with `-f`, and for Codex and pi vigent adds each file's contents under your prompt (text files up to 100 KB; the transcript notes any it left out). The transcript shows what you typed, with the mentions highlighted.
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
### Templates
|
|
78
|
+
|
|
79
|
+
For prompts you use often, `:new -t fix the cart total is off by one` starts an agent and sends it the `fix` template with your task filled in. Four are built in: `fix` (failing test first, then the fix), `test`, `review` (changes nothing) and `explain`. `:templates` (`Space T`, or `T` on the start screen) picks one. Add your own under `[templates.<name>]` in config.toml, each with an optional engine, model and effort ([docs/config.md](docs/config.md#templates)).
|
|
80
|
+
|
|
81
|
+

|
|
39
82
|
|
|
40
83
|
## From source
|
|
41
84
|
|
|
@@ -68,9 +111,9 @@ Bump `version` in package.json, merge, then push a matching tag (`git tag v0.2.0
|
|
|
68
111
|
|
|
69
112
|
Copies go to the system clipboard through the terminal (OSC 52), so they work over SSH too. `:help` lists every active key, including yours.
|
|
70
113
|
|
|
71
|
-

|
|
72
115
|
|
|
73
|
-

|
|
74
117
|
|
|
75
118
|
## Engines: pi, Claude Code, Codex, OpenCode
|
|
76
119
|
|
|
@@ -82,11 +125,11 @@ pi runs inside vigent. Claude Code, Codex and OpenCode are the CLIs you may alre
|
|
|
82
125
|
:checkhealth " installed? signed in? how to connect the rest
|
|
83
126
|
```
|
|
84
127
|
|
|
85
|
-
The sidebar's ENGINES block shows each one: `●` signed in, `◐` installed but not signed in (with the command to sign in, like `codex login`), `○` not installed. Without `--engine`, new agents use `engine` from the config. Its default, `"auto"`, picks pi if it has an API key,
|
|
128
|
+
The sidebar's ENGINES block shows each one: `●` signed in, `◐` installed but not signed in (with the command to sign in, like `codex login`), `○` not installed. Without `--engine`, new agents use `engine` from the config. Its default, `"auto"`, picks the first signed-in CLI, otherwise pi if it has an API key. With neither, vigent starts nothing and says what to run (`claude auth login`, `codex login`) or export (`ANTHROPIC_API_KEY`) to connect one. **`:engine`** (`<Space>E`, or `E` on the dashboard) switches it while vigent runs: a menu lists auto, pi, Claude Code, Codex and OpenCode with which are ready, and `:engine claude` sets it directly. Agents already open keep their engine, since their conversation lives there; `:new <task>` starts one on the new engine. A CLI agent survives a restart too: vigent saves the CLI's conversation id and continues that conversation. Its earlier messages stay in the CLI's own history.
|
|
86
129
|
|
|
87
|
-

|
|
88
131
|
|
|
89
|
-

|
|
90
133
|
|
|
91
134
|
| Engine | vigent runs | Default extra arguments |
|
|
92
135
|
|---|---|---|
|
|
@@ -96,10 +139,20 @@ The sidebar's ENGINES block shows each one: `●` signed in, `◐` installed but
|
|
|
96
139
|
|
|
97
140
|
**Model and effort:** `:model` (`<Space>M`) opens a picker with the models the agent's engine offers (Claude Code's model names, Codex's own catalog from `codex debug models`, OpenCode's `opencode models`, or pi's for the providers you have a key for). In the picker, `j`/`k` move, `g`/`G` jump to the top or bottom, Enter picks and `q` or Esc closes. Press `/` to search, or to type any model name. `:effort` (`<Space>e`) sets the reasoning effort (pi: thinking level). Both apply from the next prompt, show in the winbar and survive a restart. With no agent open, they set the defaults for new agents.
|
|
98
141
|
|
|
99
|
-

|
|
100
143
|
|
|
101
144
|
Change the arguments or the model per engine in `[engines.<id>]` ([docs/config.md](https://github.com/farming-labs/vigent/blob/main/docs/config.md#engines)).
|
|
102
145
|
|
|
146
|
+
### pi extensions, skills and prompt templates
|
|
147
|
+
|
|
148
|
+
A pi agent loads what pi itself would load. That covers extensions from `~/.pi/agent/extensions/` and `.pi/extensions/`, and the packages you installed with pi. It also covers skills, prompt templates, and the project's `AGENTS.md`.
|
|
149
|
+
|
|
150
|
+
vigent gives extensions a UI of their own. When an extension asks for confirmation, vigent shows a y/n question in the command line. Choices and text input open pickers. Notifications go to the transcript and the message line, and statuses show in the winbar. Each one names the agent it came from, and a question from an agent you aren't looking at rings the bell. So pi's permission gate works the same as in pi: it asks before an `rm -rf`, and **No** blocks the command.
|
|
151
|
+
|
|
152
|
+
Type an extension's command (`/deploy`), a skill (`/skill:changelog`) or a prompt template (`/tidy src/cart.js`) as a prompt. **`:pi`** lists everything the focused agent loaded, including extensions that failed and why. Press Enter on a command, skill or prompt template to start a prompt with it.
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
|
|
103
156
|
## Worktrees
|
|
104
157
|
|
|
105
158
|
Every agent gets its own git worktree and branch, so agents never touch your checkout or each other's files:
|
|
@@ -124,20 +177,25 @@ A worktree is normally a full copy of your checkout, so ten agents on a big repo
|
|
|
124
177
|
- On restart, vigent inspects riftri's worktrees before reopening their agents. If an OverlayFS view lost its mount (after a reboot), vigent repairs it first.
|
|
125
178
|
- vigent falls back to git only when riftri declines with a receipt saying nothing was changed (unsupported volume, checkout or environment). Any other riftri failure is shown, never papered over. `[worktree] backend = "riftri"` requires riftri, and `"git"` turns it off.
|
|
126
179
|
|
|
127
|
-

|
|
128
181
|
|
|
129
|
-

|
|
130
183
|
|
|
131
|
-

|
|
132
185
|
|
|
133
186
|
## Reviewing and landing work
|
|
134
187
|
|
|
188
|
+
**`:review`** (`Space r`) goes through the agent's changes one hunk at a time. That covers its commits, its uncommitted edits and its new files. Press `x` to drop the hunk under the cursor, `X` to drop the whole file, and `u` to undo. Dropping takes the change out of the agent's worktree, so `:merge` and `:pr` land only what you kept.
|
|
189
|
+
|
|
190
|
+

|
|
191
|
+
|
|
135
192
|
```vim
|
|
136
193
|
:diff " the agent's changes; ]c / [c jump between hunks
|
|
137
194
|
:merge " squash-merge its branch into yours: one commit, e.g. "fix: flaky checkout test"
|
|
138
195
|
:merge --no-squash " a regular merge commit instead
|
|
139
196
|
:pr " push the branch and open a pull request (gh), or print the compare URL
|
|
140
197
|
:dash " every agent at a glance; j/k and Enter to jump to one
|
|
198
|
+
:cost " tokens and money each agent has used, and the total
|
|
141
199
|
:queue <prompt> " send a follow-up after the current run (:queue alone lists them)
|
|
142
200
|
:pause / :resume " hold an agent and its queue, then continue
|
|
143
201
|
:w [file] " save the transcript as Markdown
|
|
@@ -152,13 +210,13 @@ Agents survive a restart: quit vigent, start it again in the same repo, and the
|
|
|
152
210
|
|
|
153
211
|
`:merge` and `:pr` first commit anything the agent left uncommitted. `:merge` only touches your checkout when it's on the agent's base branch with no uncommitted changes, and a conflict is rolled back so nothing changes. After a merge, `:kill!` removes the worktree and the merged branch. `:q` won't quit while agents are running; `:q!` or `ZQ` does. Use `:new <task> --model <id>` to give one agent a different model.
|
|
154
212
|
|
|
155
|
-

|
|
156
214
|
|
|
157
|
-

|
|
158
216
|
|
|
159
|
-

|
|
160
218
|
|
|
161
|
-

|
|
162
220
|
|
|
163
221
|
## Configuration
|
|
164
222
|
|
|
@@ -189,7 +247,7 @@ Normal = { bg = "NONE" }
|
|
|
189
247
|
|
|
190
248
|
You can also change keys while vigent runs, with `:nmap`, `:imap`, `:cmap`, `:unmap` and `:let mapleader`. **[docs/config.md](https://github.com/farming-labs/vigent/blob/main/docs/config.md)** has every option, action and built-in key.
|
|
191
249
|
|
|
192
|
-

|
|
193
251
|
|
|
194
252
|
## Themes
|
|
195
253
|
|
|
@@ -206,7 +264,7 @@ vigent --theme nvim # follow your Neovim: the colorscheme your c
|
|
|
206
264
|
|
|
207
265
|
**Follow your editor:** with `theme = "nvim"` (or `"vim"`) in config.toml, vigent uses whatever colorscheme your Neovim config and plugins set, whether that's AstroNvim's `astrodark`, LazyVim's `tokyonight` or anything else. Change it in Neovim, and vigent picks it up the next time it starts. vigent keeps a copy (`themes/nvim.json`) so it opens instantly, and checks Neovim in the background.
|
|
208
266
|
|
|
209
|
-
Inside vigent, `:colorscheme` opens a picker with live preview. `:hi Group guifg=… guibg=…` changes any color on the spot, `:set transparent` lets your terminal's background (its blur, opacity or wallpaper) show through any theme, and `:theme save mine` keeps what's on screen as your own theme file. To keep settings, put them in `~/.config/vigent/config.toml` (`vigent config init` writes a starter file):
|
|
267
|
+
Inside vigent, `:colorscheme` (`<Space>t`) opens a picker with live preview: `j`/`k` move and preview, Enter keeps it, `q` or Esc puts the old one back, and `/` searches. `:hi Group guifg=… guibg=…` changes any color on the spot, `:set transparent` lets your terminal's background (its blur, opacity or wallpaper) show through any theme, and `:theme save mine` keeps what's on screen as your own theme file. To keep settings, put them in `~/.config/vigent/config.toml` (`vigent config init` writes a starter file):
|
|
210
268
|
|
|
211
269
|
```toml
|
|
212
270
|
theme = "tokyonight"
|
|
@@ -225,19 +283,19 @@ CursorLine = "guibg=#2a2f3a"
|
|
|
225
283
|
|
|
226
284
|
25 built in, including `lazyvim` (LazyVim's look, transparent), the tokyonight, catppuccin and rose-pine families, `dracula`, `onedark`, `everforest`, `nightfox`, `gruvbox`, `kanagawa`, `nord`, `monokai-pro`, `ayu-mirage`, and GitHub and solarized in dark and light. The picker shows each one's colors:
|
|
227
285
|
|
|
228
|
-

|
|
229
287
|
|
|
230
288
|
**`:settings`** (`<Space>s`) changes the theme, transparency, layout, engine, worktrees and any key in one place. Press `w` and it's saved to config.toml:
|
|
231
289
|
|
|
232
|
-

|
|
233
291
|
|
|
234
|
-

|
|
235
293
|
|
|
236
|
-

|
|
237
295
|
|
|
238
|
-

|
|
239
297
|
|
|
240
|
-

|
|
241
299
|
|
|
242
300
|
The full guide covers importing, theme files, palettes, every option and every highlight group: **[docs/themes.md](https://github.com/farming-labs/vigent/blob/main/docs/themes.md)**.
|
|
243
301
|
|
package/dist/agents.js
CHANGED
|
@@ -63,3 +63,32 @@ export function restorableAgents(root, config) {
|
|
|
63
63
|
}
|
|
64
64
|
return out.sort((a, b) => a.meta.createdAt.localeCompare(b.meta.createdAt));
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Agents to reopen at startup, with riftri's views made ready first.
|
|
68
|
+
*
|
|
69
|
+
* An OverlayFS view loses its mount when the machine restarts: its folder is
|
|
70
|
+
* then empty, so the agent's record (kept through the worktree's .git) can't
|
|
71
|
+
* be read until riftri has repaired it. So every vigent worktree is inspected
|
|
72
|
+
* (and repaired) before any record is read.
|
|
73
|
+
*/
|
|
74
|
+
export function reopenableAgents(root, config, prepare) {
|
|
75
|
+
const listed = listWorktrees(root, config).filter((w) => w.branch);
|
|
76
|
+
const views = prepare(root, listed.map((w) => w.path));
|
|
77
|
+
const blocked = [];
|
|
78
|
+
const agents = [];
|
|
79
|
+
for (const w of listed) {
|
|
80
|
+
const view = views.get(w.path);
|
|
81
|
+
if (view && !view.ready) {
|
|
82
|
+
blocked.push({ path: w.path, reason: view.reason ?? "not ready" });
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!fs.existsSync(w.path))
|
|
86
|
+
continue;
|
|
87
|
+
const meta = loadAgentMeta(w.path);
|
|
88
|
+
if (!meta || meta.detached)
|
|
89
|
+
continue;
|
|
90
|
+
agents.push({ meta, worktree: { branch: w.branch, path: w.path, base: meta.base }, backend: view?.backend });
|
|
91
|
+
}
|
|
92
|
+
agents.sort((a, b) => a.meta.createdAt.localeCompare(b.meta.createdAt));
|
|
93
|
+
return { agents, blocked };
|
|
94
|
+
}
|