@solaqua/gji 0.11.0 → 0.12.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.
Files changed (67) hide show
  1. package/README.md +82 -496
  2. package/dist/clean.js +2 -0
  3. package/dist/cli.d.ts +4 -0
  4. package/dist/cli.js +40 -4
  5. package/dist/context-card.d.ts +1 -0
  6. package/dist/context-card.js +25 -0
  7. package/dist/doctor.js +21 -0
  8. package/dist/done.js +2 -0
  9. package/dist/gji-bundle.mjs +988 -350
  10. package/dist/go.d.ts +1 -0
  11. package/dist/go.js +8 -0
  12. package/dist/hooks.d.ts +1 -0
  13. package/dist/hooks.js +7 -1
  14. package/dist/hub.d.ts +31 -0
  15. package/dist/hub.js +287 -0
  16. package/dist/ls.js +9 -1
  17. package/dist/new.d.ts +1 -0
  18. package/dist/new.js +9 -0
  19. package/dist/pr-open.js +2 -10
  20. package/dist/pull-requests.d.ts +1 -0
  21. package/dist/pull-requests.js +32 -3
  22. package/dist/remove.js +2 -0
  23. package/dist/repo.d.ts +1 -0
  24. package/dist/repo.js +4 -0
  25. package/dist/run-hook.js +2 -0
  26. package/dist/shell-completion.js +11 -3
  27. package/dist/slots.d.ts +8 -0
  28. package/dist/slots.js +61 -0
  29. package/dist/status.d.ts +2 -0
  30. package/dist/status.js +9 -1
  31. package/dist/task-command.d.ts +9 -0
  32. package/dist/task-command.js +29 -0
  33. package/dist/task.d.ts +9 -0
  34. package/dist/task.js +37 -0
  35. package/dist/terminal-text.d.ts +4 -0
  36. package/dist/terminal-text.js +72 -0
  37. package/dist/worktree-bootstrap.js +3 -0
  38. package/dist/worktree-info.d.ts +6 -1
  39. package/dist/worktree-info.js +14 -4
  40. package/dist/worktree-picker.d.ts +3 -3
  41. package/dist/worktree-picker.js +71 -82
  42. package/dist/worktree-sources.d.ts +1 -0
  43. package/dist/worktree-sources.js +57 -11
  44. package/man/man1/gji-back.1 +1 -1
  45. package/man/man1/gji-clean.1 +1 -1
  46. package/man/man1/gji-completion.1 +1 -1
  47. package/man/man1/gji-config.1 +1 -1
  48. package/man/man1/gji-doctor.1 +1 -1
  49. package/man/man1/gji-done.1 +1 -1
  50. package/man/man1/gji-go.1 +4 -1
  51. package/man/man1/gji-history.1 +1 -1
  52. package/man/man1/gji-init.1 +1 -1
  53. package/man/man1/gji-ls.1 +1 -1
  54. package/man/man1/gji-new.1 +4 -1
  55. package/man/man1/gji-open.1 +1 -1
  56. package/man/man1/gji-pr.1 +1 -1
  57. package/man/man1/gji-remove.1 +1 -1
  58. package/man/man1/gji-root.1 +1 -1
  59. package/man/man1/gji-run-hook.1 +1 -1
  60. package/man/man1/gji-status.1 +1 -1
  61. package/man/man1/gji-sync-files.1 +1 -1
  62. package/man/man1/gji-sync.1 +1 -1
  63. package/man/man1/gji-task.1 +16 -0
  64. package/man/man1/gji-undo.1 +1 -1
  65. package/man/man1/gji-warp.1 +1 -1
  66. package/man/man1/gji.1 +5 -1
  67. package/package.json +1 -1
package/README.md CHANGED
@@ -1,558 +1,144 @@
1
- # gji — Git worktrees without the hassle
1
+ # gji — Switch Git contexts without stashing
2
2
 
3
- > Jump between tasks instantly. No stash. No branch juggling. No mess.
3
+ > Start, review, and switch between Git tasks without disturbing the work already open.
4
4
 
5
- `gji` wraps Git worktrees into a fast, ergonomic CLI. Each branch gets its own directory, its own `node_modules`, and its own terminal — so switching context is a single command instead of a ritual.
5
+ `gji` makes Git worktrees feel like normal shell navigation. Each task gets its
6
+ own directory, dependencies, editor context, and terminal — so moving to a
7
+ pull request or experiment does not require stashing, checking out, or
8
+ reinstalling.
6
9
 
7
- That matters even more in AI-assisted workflows, where one repository often has several active tasks in parallel: your main feature, a PR review, a scratch experiment, or an agent-driven refactor. `gji` keeps each one isolated and easy to enter.
10
+ ## Start your next task
8
11
 
9
- ```sh
10
- gji new feature/payment-refactor # new branch + worktree, cd in
11
- gji pr 1234 # review PR in isolation, cd in
12
- gji pr open # open the PR for the current worktree
13
- gji go main # jump back, shell changes directory
14
- gji done feature/payment-refactor
15
- ```
16
-
17
- ## Before / After
18
-
19
- <table>
20
- <tr>
21
- <td width="50%" valign="top">
22
- <strong>Before</strong><br />
23
- <img src=".github/assets/readme-before.gif" alt="Traditional branch review flow with git stash, branch switching, reinstalling dependencies, and a merge conflict on stash pop." />
24
- </td>
25
- <td width="50%" valign="top">
26
- <strong>After</strong><br />
27
- <img src=".github/assets/readme-after.gif" alt="gji creating an isolated pull request worktree from the terminal in a few commands." />
28
- </td>
29
- </tr>
30
- </table>
31
-
32
- Maintainer note: `pnpm generate:readme-demos` currently expects macOS, `zsh`, Google Chrome, `asciinema`, and `ffmpeg`.
33
-
34
- ---
35
-
36
- **If `gji` has saved you from a `git stash` spiral, a ⭐ on [GitHub](https://github.com/sjquant/gji) means a lot — it helps other developers find this tool.**
37
-
38
- ---
39
-
40
- ## The problem
41
-
42
- You are deep in a feature branch. A colleague asks for a quick review. You:
43
-
44
- 1. stash your changes
45
- 2. checkout their branch
46
- 3. wait for `npm install` to finish
47
- 4. review
48
- 5. checkout back
49
- 6. pop your stash
50
- 7. realize something is broken
51
-
52
- **Or you use `gji`, run `gji pr 1234`, and let the fresh worktree boot itself.**
53
-
54
- ## Why it matters more now
55
-
56
- AI increases the amount of parallel work around a codebase.
57
-
58
- It is increasingly normal to have:
59
-
60
- 1. your own branch open
61
- 2. another branch for review
62
- 3. a scratch space for testing an AI-generated change
63
- 4. a separate worktree for validating a risky migration or refactor
64
-
65
- That makes Git worktrees more important, because a single shared checkout becomes the bottleneck. `gji` turns worktrees into a daily workflow instead of a Git power-user feature.
66
-
67
- ## Install
12
+ Run `gji new` and let the interactive flow guide you into a fresh worktree:
68
13
 
69
14
  ```sh
70
- npm install -g @solaqua/gji
15
+ gji new
71
16
  ```
72
17
 
73
- Then run the guided setup in an interactive terminal:
18
+ Choose a task name and setup options, then continue working in the new
19
+ directory. For repeatable workflows, you can still provide a branch directly:
74
20
 
75
21
  ```sh
76
- gji init
77
- # restart your shell, or source the rc file shown by the wizard
78
- gji doctor
22
+ gji new feature/payment-refactor
79
23
  ```
80
24
 
81
- The wizard installs shell integration, completions, and an available editor. In a non-interactive environment, use the existing explicit shell command instead:
25
+ ## The problem
26
+
27
+ You are halfway through a feature when someone asks you to review a pull
28
+ request. Without worktrees, a quick review often becomes:
82
29
 
83
- ```sh
84
- gji init zsh --write
30
+ ```text
31
+ stash checkout → reinstall → review → checkout back → stash pop
85
32
  ```
86
33
 
87
- ## Quick start
34
+ With `gji`, the review gets its own workspace and your current task stays
35
+ untouched:
88
36
 
89
37
  ```sh
90
- # start a new task
91
- gji new feature/dark-mode
92
-
93
- # start a task and open it straight in your editor
94
- gji new feature/dark-mode --open --editor cursor
95
-
96
- # review a pull request
97
38
  gji pr 1234
98
- gji pr open # open the PR for the current worktree
99
- gji pr open --select # choose a PR from any linked worktree
100
- gji pr open feature/auth-refactor # open the PR for a branch
101
- gji pr open '#1234' # open an open PR directly
102
-
103
- # see what's open
104
- gji status
105
-
106
- # jump between worktrees
107
- gji go feature/dark-mode
108
- gji go main
109
-
110
- # open the current worktree in an editor
111
- gji open
112
- gji open --select # choose another worktree interactively
113
- gji open feature/dark-mode --editor code
114
-
115
- # finish a worktree when done
116
- gji done feature/dark-mode
117
39
  ```
118
40
 
119
- Worktrees land at a deterministic path so your editor bookmarks and scripts always know where to look:
120
-
121
- ```
122
- ../worktrees/<repo>/<branch>
123
- ```
124
-
125
- Set `worktreePath` in your config to use a different base (e.g. `"~/worktrees"` → `~/worktrees/<branch>`).
41
+ <table>
42
+ <tr>
43
+ <td width="50%" valign="top">
44
+ <strong>Before</strong><br />
45
+ <img src=".github/assets/readme-before.gif" alt="Traditional branch switching with stash and reinstall steps" />
46
+ </td>
47
+ <td width="50%" valign="top">
48
+ <strong>After</strong><br />
49
+ <img src=".github/assets/readme-after.gif" alt="Creating an isolated pull request worktree with gji" />
50
+ </td>
51
+ </tr>
52
+ </table>
126
53
 
127
- ## Daily workflow
54
+ ## Remember four commands
128
55
 
129
56
  ```sh
130
- gji new feature/auth-refactor # new branch + worktree
131
- gji new feature/auth-tests --from-current # branch from the current worktree
132
- gji new --detached # scratch space, auto-named
133
-
134
- gji pr 1234 # checkout PR locally
135
- gji pr https://github.com/org/repo/pull/1234 # or paste the URL
136
-
137
- gji go feature/auth-refactor # jump to a worktree
138
- gji go teammate-branch # open an existing local or remote branch
139
- gji go - # return to the previous worktree
140
- gji go --root # return to the main repository checkout
141
- gji root # jump to repo root
142
- gji warp repo-a/main # compatibility spelling for cross-repo navigation
143
- gji back # return through navigation history
144
- gji history # inspect recent navigation
145
-
146
- # with no branch, the chooser starts in the current repo; press Tab for all repos
147
-
148
- gji status # health overview + ahead/behind counts
149
- gji ls # list with status/upstream/last commit
150
- gji ls --compact # branch/path only
151
-
152
- gji sync # rebase current worktree onto default branch
153
- gji sync --all # rebase every worktree
154
-
155
- gji clean # interactive bulk cleanup
156
- gji clean --stale # only target safe stale cleanup candidates
157
- gji done feature/auth-refactor # finish one worktree and its branch
158
-
159
- gji trigger-hook afterCreate # re-run setup in the current worktree
57
+ gji new # interactively start a task
58
+ gji pr 1234 # open a pull request in isolation
59
+ gji go main # jump to another worktree
60
+ gji done feature/payment-refactor # finish and clean up a task
160
61
  ```
161
62
 
162
- ## Comparison
163
-
164
- `gji` sits between raw Git primitives and larger Git or repository tools:
165
-
166
- - **vs raw `git worktree`**: same underlying capability, but with branch-first commands, shell handoff, PR checkout, hooks, sync, and cleanup built into the workflow
167
- - **vs `lazygit`**: `lazygit` is a broad Git UI; `gji` is narrower and faster for opening, jumping between, and removing isolated branch directories
168
- - **vs `ghq`**: `ghq` organizes where repositories live; `gji` organizes which branch, PR, or worktree you should be in once you are inside one
169
-
170
- Use `gji` when your bottleneck is repeated context switching between features, reviews, and maintenance work without disturbing what is already open.
171
-
172
- It is especially useful when those contexts are happening in parallel across both human and AI-assisted work.
173
-
174
- See the full comparison in [website/docs/comparison.mdx](./website/docs/comparison.mdx).
175
-
176
- ## Shell setup
63
+ With shell integration enabled, each command moves your shell into the
64
+ selected worktree automatically.
177
65
 
178
- Without shell integration `gji` prints paths and exits — which is fine for scripts but means it cannot `cd` you into a new worktree. Install the integration, completions, and an editor once with:
66
+ ## Install
179
67
 
180
68
  ```sh
69
+ npm install -g @solaqua/gji
181
70
  gji init
182
- gji doctor
183
- ```
184
-
185
- `gji init` is interactive. For dotfiles or CI, the explicit shell commands remain available and preserve their existing output:
186
-
187
- ```sh
188
- # zsh
189
- echo 'eval "$(gji init zsh)"' >> ~/.zshrc
190
-
191
- # bash
192
- echo 'eval "$(gji init bash)"' >> ~/.bashrc
193
-
194
- # fish
195
- gji init fish --write
196
71
  ```
197
72
 
198
- Install completions separately so your shell rc stays small:
73
+ `gji init` interactively installs shell integration, completions, and an
74
+ available editor. Restart your shell, or source the rc file shown by the
75
+ wizard, then run:
199
76
 
200
77
  ```sh
201
- # zsh
202
- mkdir -p ~/.zsh/completions
203
- gji completion zsh > ~/.zsh/completions/_gji
204
- # add this before running compinit in ~/.zshrc
205
- fpath=(~/.zsh/completions $fpath)
206
-
207
- # bash
208
- mkdir -p ~/.local/share/bash-completion/completions
209
- gji completion bash > ~/.local/share/bash-completion/completions/gji
210
-
211
- # fish
212
- mkdir -p ~/.config/fish/completions
213
- gji completion fish > ~/.config/fish/completions/gji.fish
214
- ```
215
-
216
- After a reinstall or upgrade, refresh both the wrapper and the completion file:
217
-
218
- ```sh
219
- # zsh
220
- eval "$(gji init zsh)"
221
- gji completion zsh > ~/.zsh/completions/_gji
222
- # if zsh is already running, refresh completion discovery too
223
- autoload -Uz compinit && compinit
224
-
225
- # fish
226
- gji init fish --write
227
- gji completion fish > ~/.config/fish/completions/gji.fish
228
- source ~/.config/fish/config.fish
229
- ```
230
-
231
- For scripts that need the raw path, use `--print`:
232
-
233
- ```sh
234
- path=$(gji go --print feature/dark-mode)
235
- path=$(gji root --print)
236
- ```
237
-
238
- ## Commands
239
-
240
- | Command | Description |
241
- |---|---|
242
- | `gji new [branch] [--from-current] [--detached] [--no-fetch] [--take] [--copy] [--force] [--open] [--editor <cli>] [--dry-run] [--json]` | create branch + worktree from a refreshed remote base by default; `--no-fetch` opts out |
243
- | `gji done [branch] [--force] [--keep-branch] [--json]` | safely finish a linked worktree and return |
244
- | `gji undo [id] [--list] [--json]` | restore a journaled cleanup without overwriting work |
245
- | `gji pr <ref> [--json]` | fetch PR ref, create worktree, cd in |
246
- | `gji pr open [branch|#N] [--select]` | open the current worktree PR, or choose a linked worktree with `--select` |
247
- | `gji back [n] [--print]` | return to a previous worktree from navigation history |
248
- | `gji history [--json]` | show navigation history |
249
- | `gji warp [branch] [--print] [--json]` | compatibility spelling for cross-repository navigation |
250
- | `gji open [branch] [--select] [--editor <cli>] [--save] [--workspace]` | open the current or selected worktree in an editor |
251
- | `gji go [branch] [--root] [--print] [--json]` | resolve and jump to a worktree, branch, remote, or PR |
252
- | `gji root [--print]` | jump to the main repo root |
253
- | `gji status [--json]` | repo overview, worktree health, ahead/behind |
254
- | `gji ls [--compact] [--json]` | list active worktrees |
255
- | `gji sync [--all]` | fetch and rebase worktrees onto default branch |
256
- | `gji sync-files [list\|add\|remove] [paths...]` | manage local files copied into new worktrees |
257
- | `gji clean [--stale] [--force] [--dry-run] [--json]` | interactively prune linked worktrees |
258
- | `gji remove [branch] [--force] [--dry-run] [--json]` (`rm`) | **deprecated**; use `gji done` for one worktree or `gji clean` for bulk cleanup |
259
- | `gji trigger-hook <hook>` | run a hook in the current worktree |
260
- | `gji config [get\|set\|unset] [key] [value]` | manage global defaults |
261
- | `gji init [shell]` | interactively set up onboarding, or print/install a shell wrapper |
262
- | `gji doctor [--json] [--fix] [--yes]` | check installation and configuration health; optionally remove stale repository entries |
263
- | `gji completion [shell]` | print shell completion definitions |
264
-
265
- The repository registry records projects that gji has visited so `go`, `warp`,
266
- and the chooser can resolve worktrees across repositories. It is advisory
267
- metadata: missing paths are skipped and `gji doctor --fix` can remove stale
268
- entries.
269
-
270
- `gji remove` and its `rm` alias remain available during the deprecation window,
271
- but print a migration warning in human-readable mode. Use `gji done <branch>`
272
- to finish one linked worktree or `gji clean` to prune several worktrees.
273
-
274
- ## Configuration
275
-
276
- No setup required. Optional config lives in:
277
-
278
- - `~/.config/gji/config.json` — global defaults
279
- - `.gji.json` — repo-local overrides (takes precedence)
280
-
281
- ### Available keys
282
-
283
- | Key | Description |
284
- |---|---|
285
- | `branchPrefix` | prefix added to new branch names (e.g. `"feature/"`) |
286
- | `editor` | default editor CLI for `gji open` and `gji new --open` (e.g. `"cursor"`, `"code"`, `"zed"`); set automatically with `gji open --save` |
287
- | `worktreePath` | base directory for new worktrees (absolute or `~/…`); overrides the default `../worktrees/<repo>/` layout |
288
- | `syncRemote` | remote for `gji sync` (default: `origin`) |
289
- | `syncDefaultBranch` | branch to rebase onto (default: remote `HEAD`) |
290
- | `syncFiles` | files to copy from main worktree into each new worktree; use global per-repo config for private files |
291
- | `syncDirs` | arbitrary directories to clone with filesystem copy-on-write before sync files |
292
- | `dependencyBootstrap` | dependency/build-state policy: `off`, `cow-then-repair`, or `install-only` |
293
- | `dependencyBuildCommand` | optional Cargo repair command used by `dependencyBootstrap` (default: `cargo check`) |
294
- | `skipInstallPrompt` | `true` to disable the auto-install prompt permanently |
295
- | `installSaveTarget` | `"local"` or `"global"` — where dependency policy and legacy **Always**/**Never** choices are persisted (default: `"local"`); set during `gji init <shell> --write` |
296
- | `hooks` | lifecycle scripts (see [Hooks](#hooks)) |
297
- | `repos` | per-repo overrides inside the global config (see below) |
298
-
299
- ```json
300
- {
301
- "branchPrefix": "feature/",
302
- "syncRemote": "upstream",
303
- "syncDefaultBranch": "main",
304
- "syncFiles": [".env.example", ".nvmrc"],
305
- "syncDirs": [".next"],
306
- "dependencyBootstrap": "cow-then-repair"
307
- }
78
+ gji doctor
308
79
  ```
309
80
 
310
- ### Syncing local files
311
-
312
- Use `syncFiles` for private, gitignored, or machine-local files that every new worktree needs, such as `.env.local` or `.npmrc`. `gji new` copies these files from the main worktree before install hooks run, skips missing source files, and does not overwrite files that already exist in the target worktree.
81
+ Without shell integration, commands still print paths for scripts and other
82
+ non-interactive use. See the [installation guide](https://gji.solaqua.dev/docs/installation)
83
+ for explicit shell setup.
313
84
 
314
- For private files, prefer the `sync-files` command. It writes to your global per-repo config so secret filenames do not need to be committed to `.gji.json`:
85
+ ## A typical day
315
86
 
316
87
  ```sh
317
- gji sync-files add .env.local .npmrc
318
- gji sync-files list
319
- gji sync-files remove .npmrc
320
- ```
321
-
322
- This stores:
88
+ # Start feature work
89
+ gji new
323
90
 
324
- ```json
325
- {
326
- "repos": {
327
- "/home/me/code/my-repo": {
328
- "syncFiles": [".env.local"]
329
- }
330
- }
331
- }
332
- ```
91
+ # Check what is active
92
+ gji
333
93
 
334
- ### Instant directory bootstrap
94
+ # Review a PR without changing the current task
95
+ gji pr 1234
335
96
 
336
- Use `syncDirs` for advanced, arbitrary directories that should be available immediately in each new worktree. Dependency adapters discover their own project-local targets, so you do not need to list `node_modules`, `.venv`, or `target` here:
97
+ # Move between tasks
98
+ gji go feature/payment-refactor
99
+ gji back
337
100
 
338
- ```json
339
- {
340
- "syncDirs": [".next", ".cache"]
341
- }
101
+ # Keep worktrees current and remove finished work
102
+ gji sync
103
+ gji done feature/payment-refactor
342
104
  ```
343
105
 
344
- `gji new` clones these directories with APFS copy-on-write on macOS or mandatory reflinks on Linux, before `syncFiles`. It never falls back to a slow ordinary copy. Unsupported filesystems, external symlink targets, missing sources, and existing destinations are skipped safely; failed CoW attempts are cached in `~/.config/gji/state.json` so repeated worktree creation does not keep waiting on the same unsupported filesystem. `syncDirs` is generic: it does not know or special-case package managers.
345
-
346
- Paths are relative to the repository root. Absolute paths, `..` segments, and `.git` paths are rejected in all three config layers.
347
-
348
- The human output includes clone timing; dry-run can provide source-size estimates:
106
+ Worktrees use a predictable location by default:
349
107
 
350
108
  ```text
351
- ⚡ cloned .next (size unavailable → 1.2s)
352
- ```
353
-
354
- Use `dependencyBootstrap` when a package manager or build cache needs a reusable seed followed by authoritative repair:
355
-
356
- ```json
357
- {
358
- "dependencyBootstrap": "cow-then-repair"
359
- }
360
- ```
361
-
362
- `cow-then-repair` supports pnpm (`node_modules` + `pnpm install --frozen-lockfile`), Yarn (`node_modules` + `yarn install --immutable`), uv (`.venv` + `uv sync --locked`), Cargo (`target` + the configured `dependencyBuildCommand`, or `cargo check`), and Bundler (`vendor/bundle` + `BUNDLE_PATH=vendor/bundle bundle install`). npm is install-only (`npm ci`) because it can delete an existing dependency tree; it never seeds `node_modules`. Only project-local targets are eligible, so global Ruby gems and package-manager caches are never cloned. CoW failure never triggers ordinary copying: repair runs from an empty target instead. The lifecycle is `CoW seed → syncFiles → repair/install → after-create`; a sync-file failure stops repair, install prompts, and hooks. A successful dependency seed is reported as `reused and repaired`, not as an install skip.
363
-
364
- When a supported lockfile is detected and no `dependencyBootstrap` policy is configured, interactive `gji new` and `gji pr` ask which policy to persist: **Reuse and repair (recommended)**, **Install fresh each time**, or **Skip dependency setup**. The prompt explains the detected tool—for example, pnpm reuses local `node_modules` through CoW and then runs `pnpm install --frozen-lockfile`. The choice is saved locally or in the per-repo global config according to `installSaveTarget`. Headless, JSON, and dry-run commands never prompt and retain the safe `off` default.
365
-
366
- Ecosystems dominated by global caches, such as Gradle, Maven, and Go, are not seeded until a safe project-local target and deterministic repair rule are available. Future adapters can add Composer, Poetry/PDM, Mix, Dart/Flutter, or .NET without changing `syncDirs`.
367
-
368
- Use `gji new --dry-run` to see the directories and estimated sizes without creating anything. `gji new --json` adds a `cloned` array and structured `dependencyBootstrap` events, including machine-readable reasons for skips and failures. If bootstrap fails, the JSON error includes the created worktree path; text mode prints the same path and a cleanup hint. The benchmark target for a 2 GB dependency tree on supported APFS/Btrfs or XFS filesystems is under 5 seconds; benchmark your repository locally because filesystem and storage behavior determine the result.
369
-
370
- ### Per-repo overrides in global config
371
-
372
- If you work across many repositories, you can scope config to a specific repo inside `~/.config/gji/config.json` without adding a `.gji.json` to that repo:
373
-
374
- ```json
375
- {
376
- "branchPrefix": "feature/",
377
- "repos": {
378
- "/home/me/code/my-repo": {
379
- "branchPrefix": "fix/",
380
- "hooks": {
381
- "afterCreate": "npm install"
382
- }
383
- }
384
- }
385
- }
386
- ```
387
-
388
- Precedence (lowest → highest): **global defaults → per-repo global → local `.gji.json`**. Hooks from all three layers are merged per key — different keys all apply, same key the higher-precedence layer wins.
389
-
390
- ### Config commands
391
-
392
- ```sh
393
- gji config get
394
- gji config get branchPrefix
395
- gji config set branchPrefix feature/
396
- gji config unset branchPrefix
397
- ```
398
-
399
- ## Hooks
400
-
401
- Run scripts automatically at key lifecycle moments:
402
-
403
- ```json
404
- {
405
- "hooks": {
406
- "afterCreate": ["pnpm", "install"],
407
- "afterEnter": ["printf", "switched to %s\n", "{{branch}}"],
408
- "beforeRemove": "pnpm run cleanup"
409
- }
410
- }
411
- ```
412
-
413
- | Hook | When it runs |
414
- |---|---|
415
- | `afterCreate` | after `gji new` or `gji pr` creates a worktree |
416
- | `afterEnter` | after `gji go` switches to a worktree |
417
- | `beforeRemove` | before `gji done` or `gji clean` deletes a worktree |
418
-
419
- Hooks receive `{{branch}}`, `{{path}}`, `{{repo}}` as template variables and `GJI_BRANCH`, `GJI_PATH`, `GJI_REPO` as environment variables. A failing hook emits a warning but never aborts the command.
420
-
421
- Prefer argv-array hooks for simple commands:
422
-
423
- ```json
424
- {
425
- "hooks": {
426
- "afterCreate": ["pnpm", "install"],
427
- "afterEnter": ["printf", "switched to %s at %s\n", "{{branch}}", "{{path}}"]
428
- }
429
- }
430
- ```
431
-
432
- Array hooks run without a shell and pass each array item as exactly one argument. Use string hooks only when you need shell features like `&&`, pipes, redirects, shell functions, or `nvm use`.
433
-
434
- Template values are interpolated before the shell parses string hooks, so avoid putting `{{branch}}`, `{{path}}`, or `{{repo}}` directly into shell strings. For shell-string hooks, the safer pattern is to use the environment variables and double-quote each expansion:
435
-
436
- ```json
437
- {
438
- "hooks": {
439
- "afterCreate": "pnpm install && printf 'ready: %s\n' \"$GJI_PATH\""
440
- }
441
- }
109
+ ../worktrees/<repo>/<branch>
442
110
  ```
443
111
 
444
- Avoid unquoted template values in shell strings, such as `echo {{branch}}` or `cd {{path}}`.
112
+ That keeps editor bookmarks, scripts, and terminal navigation stable.
445
113
 
446
- Hooks from all three config layers merge per key — different keys from different layers both apply, same key the higher-precedence layer wins:
114
+ ## More capabilities
447
115
 
448
- ```jsonc
449
- // ~/.config/gji/config.json
450
- { "hooks": { "afterCreate": "nvm use", "afterEnter": "echo hi" } }
116
+ Use the documentation when you need to go beyond the core workflow:
451
117
 
452
- // per-repo entry in ~/.config/gji/config.json
453
- { "repos": { "/my/repo": { "hooks": { "afterCreate": "npm install" } } } }
118
+ - [Daily workflow](https://gji.solaqua.dev/docs/daily-workflow) navigation, PRs, sync, and cleanup
119
+ - [Commands](https://gji.solaqua.dev/docs/commands) complete command reference
120
+ - [Shell integration](https://gji.solaqua.dev/docs/shell-integration) — zsh, bash, and fish setup
121
+ - [Configuration](https://gji.solaqua.dev/docs/configuration) — paths, defaults, and local files
122
+ - [Hooks](https://gji.solaqua.dev/docs/hooks) — automate setup and cleanup
123
+ - [Sync and cleanup](https://gji.solaqua.dev/docs/sync-and-cleanup) — maintain active worktrees
124
+ - [Comparison](https://gji.solaqua.dev/docs/comparison) — `gji` vs `git worktree`, `lazygit`, and `ghq`
125
+ - [FAQ and troubleshooting](https://gji.solaqua.dev/docs/faq) — common questions and fixes
454
126
 
455
- // .gji.json
456
- { "hooks": { "beforeRemove": "echo bye" } }
457
-
458
- // effective
459
- { "hooks": { "afterCreate": "npm install", "afterEnter": "echo hi", "beforeRemove": "echo bye" } }
460
- ```
461
-
462
- ### Triggering hooks manually
463
-
464
- Run any hook in the current worktree on demand:
127
+ `gji` also supports JSON output for scripts and AI-assisted workflows:
465
128
 
466
129
  ```sh
467
- gji trigger-hook afterCreate # re-run the setup script
468
- gji trigger-hook afterEnter # re-run the enter script
469
- gji trigger-hook beforeRemove # dry-run the cleanup script
470
- ```
471
-
472
- This is useful after cloning on a new machine, recovering a broken worktree, or letting an AI agent bootstrap an already-existing worktree without needing interactive prompts.
473
-
474
- ## Install prompt
475
-
476
- For supported lockfiles, the dependency policy prompt above is the primary setup choice. Keep `after-create` hooks for project-specific work such as `pnpm run generate`, code generation, local-service setup, or environment-specific commands; hooks are not a second dependency-bootstrap configuration.
477
-
478
- Projects without a supported dependency adapter can still use the legacy one-shot install prompt:
479
-
480
- ```
481
- Run `pnpm install` in the new worktree?
482
- › Yes run once
483
- No skip this time
484
- Always save as afterCreate hook
485
- Never disable this prompt for this repo
486
- ```
487
-
488
- **Always** saves `hooks.afterCreate`; **Never** writes `skipInstallPrompt: true`. Where they are saved depends on `installSaveTarget` (see [Available keys](#available-keys)) — defaults to `.gji.json`.
489
-
490
- `syncDirs` remains generic and never suppresses installation or repair. To automate supported dependency/build setup, use `dependencyBootstrap`; the adapter always runs its lockfile/build repair after `syncFiles`. Explicit policies in global defaults, per-repo global config, or `.gji.json` always win over prompting.
491
-
492
- ## JSON output
493
-
494
- Every mutating command supports `--json` for scripting and AI agent use. Success goes to stdout, errors go to stderr with exit code 1.
495
-
496
- ```sh
497
- # create
130
+ gji --json
498
131
  gji new --json feature/dark-mode
499
- # { "branch": "feature/dark-mode", "path": "/…/worktrees/repo/feature/dark-mode", "repository": { "name": "repo", "root": "/…/repo" } }
500
-
501
- # fetch PR
502
- gji pr --json 1234
503
- # → { "branch": "pr/1234", "path": "/…/worktrees/repo/pr/1234", "repository": { "name": "repo", "root": "/…/repo" } }
504
-
505
- # resolve an existing destination without changing directories
506
- gji go --json feature/auth-refactor
507
- # → { "branch": "feature/auth-refactor", "path": "/…/worktrees/repo/feature/auth-refactor", "repository": { "name": "repo", "root": "/…/repo" } }
508
-
509
- # detailed list
510
- gji ls --json
511
- # → [{ "branch": "...", "status": "clean", "upstream": { "kind": "tracked", ... }, ... }]
512
-
513
- # finish one worktree
514
- gji done --json --force feature/dark-mode
515
- # → { "branch": "feature/dark-mode", "path": "/…", "deleted": true }
516
-
517
- # bulk clean
518
- gji clean --json --force
519
- # → { "removed": [{ "branch": "...", "path": "..." }, …] }
520
-
521
- # stale-only clean
522
- gji clean --stale --json --force
523
- # → { "removed": [{ "branch": "...", "path": "..." }, …] }
524
-
525
- # error shape (any command)
526
- # stderr → { "error": "branch argument is required" }
132
+ gji go --json feature/dark-mode
527
133
  ```
528
134
 
529
- `gji clean --stale` limits cleanup to clean branch worktrees whose upstream is gone and whose branch is already merged into the configured or remote default branch.
135
+ Read the [full documentation](https://gji.solaqua.dev) for configuration,
136
+ dependency bootstrap, hooks, automation, and the complete CLI reference.
530
137
 
531
- `--json` suppresses all interactive prompts. Navigation results include a `repository` object with the stable repository `root` and display `name`. `--force` is required for `done` and `clean` in JSON mode. `branch` is `null` for detached worktrees.
532
-
533
- `gji ls --json` and `gji status --json` also produce structured output — see `gji status --json | jq` for the full schema.
534
-
535
- ## Non-interactive / CI mode
536
-
537
- ```sh
538
- GJI_NO_TUI=1 gji new feature/ci-branch
539
- GJI_NO_TUI=1 gji done --force feature/ci-branch
540
- GJI_NO_TUI=1 gji clean --force
541
- ```
542
-
543
- `GJI_NO_TUI=1` disables all prompts. Commands that need confirmation require their non-interactive approval flag (`--force` for cleanup commands, `--yes` for `doctor --fix`). `--json` implies the same behaviour.
544
-
545
- `gji pr open --select` requires an interactive terminal; plain `gji pr open` opens the PR for the current worktree without prompting.
546
- If the current worktree has no open PR or has multiple open PRs in headless mode, pass `gji pr open <branch|#N>` explicitly.
547
-
548
- Update notifications are also suppressed automatically in non-interactive and `--json` runs. Users can opt out explicitly with `NO_UPDATE_NOTIFIER=1` or `--no-update-notifier`.
549
-
550
- ## Notes
138
+ ---
551
139
 
552
- - Works from either the main repo root or inside any linked worktree
553
- - The current worktree is never offered as a `gji clean` candidate
554
- - `gji pr` fetches from `origin` using the first matching forge ref namespace: GitHub `refs/pull/<number>/head`, GitLab `refs/merge-requests/<number>/head`, then Bitbucket `refs/pull-requests/<number>/from`
555
- - `gji pr open` reads open PRs from the `origin` forge (GitHub, GitLab, or Bitbucket), preferring an installed authenticated provider CLI and falling back to its public API
140
+ If `gji` has saved you from a `git stash` spiral, a on
141
+ [GitHub](https://github.com/sjquant/gji) helps other developers find it.
556
142
 
557
143
  ## License
558
144
 
package/dist/clean.js CHANGED
@@ -2,6 +2,7 @@ import { confirm, isCancel } from "@clack/prompts";
2
2
  import { loadEffectiveConfig } from "./config.js";
3
3
  import { isBranchMergedInto, readWorktreeHealth, resolveRemoteDefaultBranch, runGit, } from "./git.js";
4
4
  import { isHeadless } from "./headless.js";
5
+ import { releaseWorktreeSlot } from "./slots.js";
5
6
  import { finalizeUndoOperation, recordUndoOperation } from "./undo.js";
6
7
  import { formatLastCommit, formatUpstreamState, readWorktreeInfos, serializeWorktreeInfo, } from "./worktree-info.js";
7
8
  import { deleteBranch, forceDeleteBranch, forceRemoveWorktree, isBranchUnmergedError, isSubmoduleWorktreeRemovalError, isWorktreeDeletionError, isWorktreeForceRemovalError, loadLinkedWorktrees, removeWorktree, } from "./worktree-management.js";
@@ -167,6 +168,7 @@ export function createCleanCommand(dependencies = {}) {
167
168
  }
168
169
  }
169
170
  await finalizeUndoOperation(journal, removedWorktrees);
171
+ await Promise.all(removedWorktrees.map((worktree) => releaseWorktreeSlot(worktree.path)));
170
172
  if (options.json) {
171
173
  const removed = removedWorktrees.map((worktree) => {
172
174
  const info = selectedInfoByPath.get(worktree.path);