@getsolaris/copse 1.0.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/LICENSE +21 -0
- package/README.ko.md +985 -0
- package/README.md +1003 -0
- package/dist/cop.js +223 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,1003 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./banner.png" alt="copse" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# 🌲 copse
|
|
6
|
+
|
|
7
|
+
**English** | [Korean](./README.ko.md)
|
|
8
|
+
|
|
9
|
+
> Git worktree manager with a beautiful TUI
|
|
10
|
+
|
|
11
|
+
Manage git worktrees with ease. Create, switch, and clean up worktrees with config-driven automation, monorepo support, and built-in health checks.
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **TUI mode** — interactive terminal UI (`cop`)
|
|
16
|
+
- **CLI mode** — scriptable commands (`cop add`, `cop list`, etc.)
|
|
17
|
+
- **Config-driven** — per-repo hooks, file copying, symlinks
|
|
18
|
+
- **Monorepo support** — auto-detect packages, per-package hooks, focus tracking
|
|
19
|
+
- **Health checks** — `cop doctor` diagnoses worktree issues
|
|
20
|
+
- **Centralized worktrees** — all worktrees under `~/.copse/worktrees/` by default
|
|
21
|
+
- **Smart cleanup** — auto-detect and remove merged worktrees
|
|
22
|
+
- **Themes** — 9 built-in color themes (OpenCode, Tokyo Night, Dracula, Nord, Catppuccin, GitHub Dark, One Dark, Monokai, GitHub Light)
|
|
23
|
+
- **Templates** — reusable worktree presets (`cop add --template review`)
|
|
24
|
+
- **Cross-worktree exec** — run commands across all worktrees (`cop exec "bun test"`)
|
|
25
|
+
- **GitHub PR integration** — create worktrees from PRs (`cop add --pr 123`)
|
|
26
|
+
- **Fuzzy branch picker** — interactive branch selection in TUI with type-ahead filtering
|
|
27
|
+
- **Lifecycle management** — auto-detect stale/merged worktrees, configurable limits
|
|
28
|
+
- **Shared dependencies** — save disk with hardlink/symlink strategies for `node_modules`
|
|
29
|
+
- **Worktree diff** — compare changes between worktrees (`cop diff feature/a feature/b`)
|
|
30
|
+
- **Pin protection** — protect worktrees from auto-cleanup (`cop pin`)
|
|
31
|
+
- **Activity log** — track create/delete/switch/rename/archive/import events (`cop log`)
|
|
32
|
+
- **Archive** — preserve worktree changes as patches before removal (`cop archive`)
|
|
33
|
+
- **Branch rename** — rename worktree branches with metadata migration (`cop rename`)
|
|
34
|
+
- **Clone & init** — clone repos with cop config initialization (`cop clone`)
|
|
35
|
+
- **Import worktrees** — adopt manually-created worktrees (`cop import`)
|
|
36
|
+
- **Detail view** — expanded worktree info with commits, diff stats, upstream status (TUI)
|
|
37
|
+
- **Bulk actions** — multi-select and batch operations on worktrees (TUI)
|
|
38
|
+
- **Toast notifications** — non-blocking operation feedback (TUI)
|
|
39
|
+
- **Shell completions** — tab completion for bash/zsh/fish (`cop shell-init --completions`)
|
|
40
|
+
- **Config profiles** — switch between configuration sets (`cop config --profiles`)
|
|
41
|
+
- **Tmux sessions** — auto-create/kill tmux sessions per worktree with layout templates (`cop session`)
|
|
42
|
+
- **Workspaces** — auto-discover git repos under parent directories with per-workspace defaults (`workspaces` config)
|
|
43
|
+
- **AI agent init** — create config by default or install cop skill for Claude Code, Codex, OpenCode (`cop init`, `cop init --skill`)
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- [Bun](https://bun.sh) runtime
|
|
48
|
+
- git 2.17+
|
|
49
|
+
- macOS or Linux
|
|
50
|
+
- [gh CLI](https://cli.github.com) (optional, for `--pr` flag)
|
|
51
|
+
- [tmux](https://github.com/tmux/tmux) (optional, for `cop session`)
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
### Homebrew (macOS/Linux)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
brew install getsolaris/tap/copse
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### curl (one-liner)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
curl -fsSL https://raw.githubusercontent.com/getsolaris/copse/main/install.sh | bash
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### npm / bun
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
bun install -g @getsolaris/copse
|
|
71
|
+
# or
|
|
72
|
+
npm install -g @getsolaris/copse
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Local Development
|
|
76
|
+
|
|
77
|
+
For local contributor testing, run the repo directly with Bun:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
bun install
|
|
81
|
+
bun run src/index.ts
|
|
82
|
+
bun run src/index.ts <cmd>
|
|
83
|
+
bun run typecheck
|
|
84
|
+
bun test
|
|
85
|
+
bun run build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Prefer targeted tests first when you change covered code, then run the full checks before opening a PR. If you change CLI or TUI behavior, manually run the affected flows locally as well.
|
|
89
|
+
|
|
90
|
+
## Quick Start
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Launch TUI
|
|
94
|
+
cop
|
|
95
|
+
|
|
96
|
+
# List worktrees
|
|
97
|
+
cop list
|
|
98
|
+
|
|
99
|
+
# Create a new worktree
|
|
100
|
+
cop add feature/my-feature
|
|
101
|
+
|
|
102
|
+
# Create with monorepo focus
|
|
103
|
+
cop add feature/my-feature --focus apps/web,apps/api
|
|
104
|
+
|
|
105
|
+
# Create from a GitHub PR
|
|
106
|
+
cop add --pr 123
|
|
107
|
+
|
|
108
|
+
# Use a template
|
|
109
|
+
cop add feature/login --template review
|
|
110
|
+
|
|
111
|
+
# Pin a worktree to protect from cleanup
|
|
112
|
+
cop pin feature/important --reason "active sprint"
|
|
113
|
+
|
|
114
|
+
# View activity log
|
|
115
|
+
cop log
|
|
116
|
+
|
|
117
|
+
# Archive worktree changes before removing
|
|
118
|
+
cop archive feature/done --yes
|
|
119
|
+
|
|
120
|
+
# Rename a worktree branch
|
|
121
|
+
cop rename old-name new-name
|
|
122
|
+
|
|
123
|
+
# Clone and initialize cop
|
|
124
|
+
cop clone https://github.com/user/repo.git
|
|
125
|
+
|
|
126
|
+
# Import an existing worktree
|
|
127
|
+
cop import /path/to/worktree
|
|
128
|
+
|
|
129
|
+
# Open/attach tmux session for a worktree
|
|
130
|
+
cop session feature/my-feature
|
|
131
|
+
|
|
132
|
+
# Create worktree with tmux session
|
|
133
|
+
cop add feature/new --session
|
|
134
|
+
|
|
135
|
+
# Run command across all worktrees
|
|
136
|
+
cop exec "bun test"
|
|
137
|
+
|
|
138
|
+
# Compare two worktrees
|
|
139
|
+
cop diff feature/a feature/b --stat
|
|
140
|
+
|
|
141
|
+
# Check worktree health
|
|
142
|
+
cop doctor
|
|
143
|
+
|
|
144
|
+
# Switch to a worktree (requires shell integration)
|
|
145
|
+
cop switch feature/my-feature
|
|
146
|
+
|
|
147
|
+
# Remove a worktree
|
|
148
|
+
cop remove feature/my-feature --yes
|
|
149
|
+
|
|
150
|
+
# Clean up merged worktrees
|
|
151
|
+
cop clean --dry-run
|
|
152
|
+
|
|
153
|
+
# Initialize config file
|
|
154
|
+
cop init
|
|
155
|
+
|
|
156
|
+
# Generate AI agent skill file
|
|
157
|
+
cop init --skill claude-code
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## TUI Usage
|
|
161
|
+
|
|
162
|
+
Launch with `cop` (no arguments).
|
|
163
|
+
|
|
164
|
+
### Keyboard Shortcuts
|
|
165
|
+
|
|
166
|
+
| Key | Action |
|
|
167
|
+
| --------- | ---------------------- |
|
|
168
|
+
| `j` / `k` | Navigate worktree list |
|
|
169
|
+
| `a` | Add worktree |
|
|
170
|
+
| `d` | Delete worktree |
|
|
171
|
+
| `o` | Open in editor (focus-aware) |
|
|
172
|
+
| `h` | Doctor (health check) |
|
|
173
|
+
| `Enter` | Open detail view |
|
|
174
|
+
| `Escape` | Close detail view / picker |
|
|
175
|
+
| `Space` | Toggle worktree selection |
|
|
176
|
+
| `Ctrl+A` | Select all worktrees |
|
|
177
|
+
| `x` | Bulk actions menu |
|
|
178
|
+
| `r` | Refresh list |
|
|
179
|
+
| `Ctrl+P` | Command palette |
|
|
180
|
+
| `?` | Help |
|
|
181
|
+
| `q` | Quit |
|
|
182
|
+
|
|
183
|
+
#### `o` — Focus-aware editor open
|
|
184
|
+
|
|
185
|
+
Pressing `o` opens the selected worktree in `$VISUAL` / `$EDITOR`:
|
|
186
|
+
|
|
187
|
+
- **No focus paths set** → opens the worktree root.
|
|
188
|
+
- **Exactly 1 focus path** → opens `<worktree>/<focus>` directly.
|
|
189
|
+
- **2+ focus paths** → shows a picker so you can choose which focus path (or the worktree root) to open.
|
|
190
|
+
|
|
191
|
+
The picker supports `j`/`k` or `↑`/`↓` to navigate, `Enter` to open, and `Esc` to cancel.
|
|
192
|
+
|
|
193
|
+
### Command Palette (`Ctrl+P`)
|
|
194
|
+
|
|
195
|
+
Searchable command menu with:
|
|
196
|
+
|
|
197
|
+
- Add / Delete / Refresh worktrees
|
|
198
|
+
- Run Doctor
|
|
199
|
+
- Open Config
|
|
200
|
+
- Switch theme
|
|
201
|
+
- Quit
|
|
202
|
+
|
|
203
|
+
Type to filter, `↑↓` to navigate, `Enter` to execute, `Esc` to close.
|
|
204
|
+
|
|
205
|
+
### Worktree Creation Flow
|
|
206
|
+
|
|
207
|
+
1. Press `a` to open the Create view
|
|
208
|
+
2. Start typing a branch name — matching branches appear as you type
|
|
209
|
+
3. Use `↑↓` to select from suggestions, or keep typing for a new branch
|
|
210
|
+
4. Press `Tab` to switch to the Focus field (optional)
|
|
211
|
+
5. Type focus paths (e.g. `apps/web,apps/api`)
|
|
212
|
+
6. Press `Enter` to preview
|
|
213
|
+
7. Press `Enter` to confirm
|
|
214
|
+
|
|
215
|
+
The fuzzy branch picker shows local and remote branches sorted by last commit date, filtered in real-time as you type.
|
|
216
|
+
|
|
217
|
+
After creation, the configured `copyFiles`, `linkFiles`, `postCreate` hooks, and monorepo hooks run automatically.
|
|
218
|
+
|
|
219
|
+
### Doctor View
|
|
220
|
+
|
|
221
|
+
Press `h` to open the Doctor tab. Shows health check results:
|
|
222
|
+
|
|
223
|
+
- ✓ Git version check
|
|
224
|
+
- ✓ Config validation
|
|
225
|
+
- ✓ Stale worktree detection
|
|
226
|
+
- ✓ Orphaned directory detection
|
|
227
|
+
- ✓ Lock status check
|
|
228
|
+
- ✓ Dirty worktree detection
|
|
229
|
+
|
|
230
|
+
Press `r` to recheck, `Esc` to go back.
|
|
231
|
+
|
|
232
|
+
### Config View
|
|
233
|
+
|
|
234
|
+
Open with `Ctrl+P` → `Open Config`. The Config tab renders the full contents of `~/.config/copse/config.json`, including:
|
|
235
|
+
|
|
236
|
+
- Top-level: `version`, `theme`, `activeProfile`
|
|
237
|
+
- `defaults` (including `postRemove`, `autoUpstream`, `sharedDeps`)
|
|
238
|
+
- All per-repo overrides
|
|
239
|
+
- The full `monorepo` tree — `autoDetect`, `extraPatterns`, and every `hooks[]` entry with its `glob` / `copyFiles` / `linkFiles` / `postCreate` / `postRemove`
|
|
240
|
+
- `templates`, `lifecycle`, `sessions`, `profiles`
|
|
241
|
+
|
|
242
|
+
Most scalar and string-array fields are editable inline. The counter in the header shows the current position (`1/20`).
|
|
243
|
+
|
|
244
|
+
| Key | Action |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `j` / `k` | Navigate editable fields |
|
|
247
|
+
| `g` / `G` | Jump to first / last field |
|
|
248
|
+
| `Enter` | Edit the selected field |
|
|
249
|
+
| `Tab` | Cycle through preset values (in edit mode) |
|
|
250
|
+
| `Space` / `←→` | Toggle a boolean / cycle a theme (in edit mode) |
|
|
251
|
+
| `Enter` | Commit the edit (saves to disk + reloads) |
|
|
252
|
+
| `Esc` | Cancel the edit |
|
|
253
|
+
| `e` | Open the config file in `$EDITOR` |
|
|
254
|
+
| `r` | Reload the file from disk |
|
|
255
|
+
| `i` | Initialize the config file if missing |
|
|
256
|
+
|
|
257
|
+
Inline editing supports five kinds of fields:
|
|
258
|
+
|
|
259
|
+
- **Strings** — plain text input (e.g. `worktreeDir`, hook `glob`, `sessions.prefix`). Press `Tab` to cycle through common presets.
|
|
260
|
+
- **String arrays** — JSON input like `[".env", ".env.local"]`. Empty input is treated as `[]`. Press `Tab` to cycle through presets including `[]` as the first option.
|
|
261
|
+
- **Booleans** — toggle with `Space`, `Tab`, or `←→`, commit with `Enter`.
|
|
262
|
+
- **Themes** — cycle with `Tab` or `←→`, commit with `Enter`. The new theme is applied live.
|
|
263
|
+
- **Enums** — fields with a fixed set of valid values (e.g. `sharedDeps.strategy` = `hardlink` / `symlink` / `copy`). Cycle with `Tab` or `←→`, commit with `Enter`.
|
|
264
|
+
|
|
265
|
+
The footer shows the current preset position when applicable, e.g. `Tab:preset (2/4)`. The cycle starts at the position matching the current value, so the first `Tab` always advances to a new value.
|
|
266
|
+
|
|
267
|
+
Every commit runs `validateConfig` before writing. Invalid input surfaces as an inline error and the edit stays open so you can fix it. For more complex fields (`sessions.layouts`, `templates`, `profiles`), press `e` to open `$EDITOR`.
|
|
268
|
+
|
|
269
|
+
## CLI Commands
|
|
270
|
+
|
|
271
|
+
| Command | Description |
|
|
272
|
+
| ------------------------ | ------------------------------------ |
|
|
273
|
+
| `cop` | Launch TUI |
|
|
274
|
+
| `cop list` | List all worktrees (with focus info) |
|
|
275
|
+
| `cop add <branch>` | Create worktree |
|
|
276
|
+
| `cop remove <branch>` | Remove worktree |
|
|
277
|
+
| `cop switch <branch>` | Switch to worktree |
|
|
278
|
+
| `cop clean` | Remove merged worktrees |
|
|
279
|
+
| `cop doctor` | Check worktree health |
|
|
280
|
+
| `cop config` | Manage configuration |
|
|
281
|
+
| `cop exec <command>` | Run command in each worktree |
|
|
282
|
+
| `cop diff <ref1> [ref2]` | Diff between worktrees/branches |
|
|
283
|
+
| `cop pin <branch>` | Pin/unpin worktree (protect from cleanup) |
|
|
284
|
+
| `cop log` | Show worktree activity log |
|
|
285
|
+
| `cop archive <branch>` | Archive changes and optionally remove |
|
|
286
|
+
| `cop rename <old> <new>` | Rename worktree branch |
|
|
287
|
+
| `cop clone <url>` | Clone repo and initialize cop |
|
|
288
|
+
| `cop import <path>` | Adopt worktree with cop metadata |
|
|
289
|
+
| `cop session [branch]` | Manage tmux sessions for worktrees |
|
|
290
|
+
| `cop open [branch]` | Open a worktree in your editor (focus-aware) |
|
|
291
|
+
| `cop init` | Initialize config or install AI agent skills |
|
|
292
|
+
|
|
293
|
+
### `cop add`
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
cop add feature/login # Create branch if needed + worktree
|
|
297
|
+
cop add feature/login --base main # New branches start from main
|
|
298
|
+
cop add existing-branch # Worktree for existing branch
|
|
299
|
+
|
|
300
|
+
# Monorepo: create with focus packages
|
|
301
|
+
cop add feature/login --focus apps/web,apps/api
|
|
302
|
+
cop add feature/login --focus apps/web --focus apps/api
|
|
303
|
+
|
|
304
|
+
# Use a template
|
|
305
|
+
cop add feature/login --template review
|
|
306
|
+
|
|
307
|
+
# Create from a GitHub PR (requires gh CLI)
|
|
308
|
+
cop add --pr 123
|
|
309
|
+
cop add --pr 456 --template review
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### `cop doctor`
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
cop doctor # Human-readable output
|
|
316
|
+
cop doctor --json # JSON output for scripting
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Exit code: `0` if healthy, `1` if any warnings or errors.
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
copse doctor
|
|
323
|
+
|
|
324
|
+
✓ Git version: 2.39.0 (>= 2.17 required)
|
|
325
|
+
✓ Configuration: valid
|
|
326
|
+
✓ Stale worktrees: none
|
|
327
|
+
✓ Orphaned directories: none
|
|
328
|
+
✓ Worktree locks: all clear
|
|
329
|
+
✓ Dirty worktrees: none
|
|
330
|
+
|
|
331
|
+
All checks passed.
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### `cop list`
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
cop list # Table with Focus column
|
|
338
|
+
cop list --json # JSON with focus array
|
|
339
|
+
cop list --porcelain # Machine-readable
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Output includes a `Focus` column showing monorepo focus paths per worktree.
|
|
343
|
+
|
|
344
|
+
### `cop remove`
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
cop remove feature/login # Remove by branch name
|
|
348
|
+
cop remove feature/login --force # Force remove (dirty worktree)
|
|
349
|
+
cop remove feature/login --yes # Skip confirmation
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### `cop clean`
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
cop clean --dry-run # Preview what would be removed
|
|
356
|
+
cop clean # Remove all merged worktrees
|
|
357
|
+
cop clean --stale # Also show stale worktrees (uses lifecycle config)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### `cop exec`
|
|
361
|
+
|
|
362
|
+
Run a shell command in every non-main worktree.
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
cop exec "bun test" # Run in all worktrees (sequential)
|
|
366
|
+
cop exec "bun test" --parallel # Run in parallel
|
|
367
|
+
cop exec "git pull" --all # Across all configured repos
|
|
368
|
+
cop exec "bun install" --dirty # Only dirty worktrees
|
|
369
|
+
cop exec "git rebase main" --behind # Only worktrees behind upstream
|
|
370
|
+
cop exec "bun test" --json # JSON output
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
| Flag | Description |
|
|
374
|
+
| ------------------- | ------------------------------------- |
|
|
375
|
+
| `--parallel` / `-p` | Run commands in parallel |
|
|
376
|
+
| `--all` / `-a` | Include all configured repos |
|
|
377
|
+
| `--dirty` | Only run in dirty worktrees |
|
|
378
|
+
| `--clean` | Only run in clean worktrees |
|
|
379
|
+
| `--behind` | Only run in worktrees behind upstream |
|
|
380
|
+
| `--json` / `-j` | Output results as JSON |
|
|
381
|
+
|
|
382
|
+
Environment variables available in commands: `COP_BRANCH`, `COP_WORKTREE_PATH`, `COP_REPO_PATH`.
|
|
383
|
+
|
|
384
|
+
### `cop diff`
|
|
385
|
+
|
|
386
|
+
Show diff between two worktree branches.
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
cop diff feature/a feature/b # Full diff
|
|
390
|
+
cop diff feature/a feature/b --stat # Diffstat summary
|
|
391
|
+
cop diff feature/a --name-only # Changed file names only
|
|
392
|
+
cop diff feature/a # Compare against current HEAD
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### `cop pin`
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
cop pin feature/auth --reason "active sprint" # Pin with reason
|
|
399
|
+
cop pin --list # List pinned worktrees
|
|
400
|
+
cop pin --list --json # JSON output
|
|
401
|
+
cop unpin feature/auth # Unpin
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Pinned worktrees are excluded from `cop clean` and lifecycle auto-cleanup.
|
|
405
|
+
|
|
406
|
+
### `cop log`
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
cop log # Show last 20 events
|
|
410
|
+
cop log --limit 50 # Show last 50 events
|
|
411
|
+
cop log --json # JSON output
|
|
412
|
+
cop log --clear # Clear activity log
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Events are color-coded: create (green), delete (red), switch (blue), rename (yellow), archive (magenta), import (cyan).
|
|
416
|
+
|
|
417
|
+
### `cop archive`
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
cop archive feature/done --yes # Archive and remove
|
|
421
|
+
cop archive feature/wip --keep # Archive without removing
|
|
422
|
+
cop archive --list # List all archives
|
|
423
|
+
cop archive --list --json # JSON output
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Archives are stored as patch files in `~/.copse/archives/`.
|
|
427
|
+
|
|
428
|
+
### `cop rename`
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
cop rename old-branch new-branch # Rename branch
|
|
432
|
+
cop rename old-branch new-branch --move-path # Also move worktree directory
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### `cop clone`
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
cop clone https://github.com/user/repo.git # Clone and init
|
|
439
|
+
cop clone https://github.com/user/repo.git ./my-dir # Custom target path
|
|
440
|
+
cop clone https://github.com/user/repo.git --template review # Apply template
|
|
441
|
+
cop clone https://github.com/user/repo.git --no-init-config # Skip config init
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### `cop import`
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
cop import /path/to/worktree # Adopt worktree
|
|
448
|
+
cop import /path/to/worktree --focus apps/web,apps/api # With focus
|
|
449
|
+
cop import /path/to/worktree --pin # Pin immediately
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### `cop session`
|
|
453
|
+
|
|
454
|
+
Manage tmux sessions for worktrees. Requires tmux.
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
cop session feature/auth # Open/attach session (create if needed)
|
|
458
|
+
cop session feature/auth --layout api # Use named layout from config
|
|
459
|
+
cop session --list # List active cop sessions
|
|
460
|
+
cop session --list --json # JSON output
|
|
461
|
+
cop session feature/auth --kill # Kill session for worktree
|
|
462
|
+
cop session --kill-all # Kill all cop sessions
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Sessions are auto-created/killed when `sessions.autoCreate` / `sessions.autoKill` are enabled in config.
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
# Create worktree with tmux session
|
|
469
|
+
cop add feature/login --session
|
|
470
|
+
cop add feature/login --session --layout api
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
When `sessions.enabled` is `true` and you're inside tmux, `cop switch` automatically switches to the target worktree's tmux session.
|
|
474
|
+
|
|
475
|
+
### `cop open`
|
|
476
|
+
|
|
477
|
+
Open a worktree in your editor or IDE. Auto-detects `$VISUAL` / `$EDITOR` and falls back to a known list (`code`, `cursor`, `vim`, `nvim`, `emacs`, `nano`, `subl`, `zed`, `idea`, `webstorm`).
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
cop open # Open the current worktree
|
|
481
|
+
cop open feature/auth # Open a specific worktree
|
|
482
|
+
cop open feature/auth -e nvim # Override editor
|
|
483
|
+
|
|
484
|
+
# Focus-aware behavior (when the worktree was created with --focus)
|
|
485
|
+
cop open feature/auth # 1 focus path → opens that focus
|
|
486
|
+
# 2+ focus paths → errors with hint
|
|
487
|
+
cop open feature/auth --focus apps/web # Pick a specific focus path
|
|
488
|
+
cop open feature/auth -f apps/api # Same with the short alias
|
|
489
|
+
cop open feature/auth --root # Force the worktree root, ignore focus
|
|
490
|
+
|
|
491
|
+
cop open --list-editors # List detected editors
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
| Flag | Alias | Description |
|
|
495
|
+
| ---- | ----- | ----------- |
|
|
496
|
+
| `--editor` | `-e` | Editor command to use (overrides `$VISUAL`/`$EDITOR`) |
|
|
497
|
+
| `--focus` | `-f` | Open a specific focus path (must match a focus entry on the worktree) |
|
|
498
|
+
| `--root` | | Force the worktree root, ignoring any focus paths |
|
|
499
|
+
| `--list-editors` | | List detected editors |
|
|
500
|
+
|
|
501
|
+
**Focus resolution rules:**
|
|
502
|
+
|
|
503
|
+
- 0 focus paths set → opens the worktree root.
|
|
504
|
+
- 1 focus path set → opens `<worktree>/<focus>` automatically.
|
|
505
|
+
- 2+ focus paths set → errors out and asks for `--focus <path>` or `--root` (the TUI shows an interactive picker instead).
|
|
506
|
+
|
|
507
|
+
### `cop init`
|
|
508
|
+
|
|
509
|
+
Initialize cop config by default, or install cop skill for AI coding agents so they can use cop commands.
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
cop init # → ~/.config/copse/config.json
|
|
513
|
+
cop init --skill claude-code # → ~/.claude/skills/cop/
|
|
514
|
+
cop init --skill codex # → ~/.agents/skills/cop/
|
|
515
|
+
cop init --skill opencode # → ~/.config/opencode/skill/cop/
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
| Platform | Skill Path |
|
|
519
|
+
|----------|-----------|
|
|
520
|
+
| `claude-code` | `~/.claude/skills/cop/` |
|
|
521
|
+
| `codex` | `~/.agents/skills/cop/` |
|
|
522
|
+
| `opencode` | `~/.config/opencode/skill/cop/` |
|
|
523
|
+
|
|
524
|
+
Each skill directory contains:
|
|
525
|
+
- `SKILL.md` — overview and common workflows
|
|
526
|
+
- `references/` — detailed per-command documentation (21 files)
|
|
527
|
+
|
|
528
|
+
Without `--skill`, the command reuses the normal config initializer and creates only `config.json`.
|
|
529
|
+
The command is idempotent — running it again updates the skill directory.
|
|
530
|
+
|
|
531
|
+
#### Auto-init on first run
|
|
532
|
+
|
|
533
|
+
You don't have to run `cop init` manually. The first time you run any `cop` command (including launching the TUI), if `~/.config/copse/config.json` does not exist, cop creates it with the default template and prints a one-line notice to stderr:
|
|
534
|
+
|
|
535
|
+
```
|
|
536
|
+
cop: created default config at /Users/you/.config/copse/config.json
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
The notice is suppressed when stdout is not a TTY (so pipes, scripts, and CI stay quiet) and when you run `cop init` explicitly (to avoid duplicate messages with init's own success line). Auto-init is fully idempotent — subsequent runs do nothing.
|
|
540
|
+
|
|
541
|
+
## Configuration
|
|
542
|
+
|
|
543
|
+
Config file: `~/.config/copse/config.json`
|
|
544
|
+
|
|
545
|
+
Initialize with: `cop config --init` (or just run any `cop` command — see [Auto-init on first run](#auto-init-on-first-run))
|
|
546
|
+
|
|
547
|
+
### Full Example
|
|
548
|
+
|
|
549
|
+
```json
|
|
550
|
+
{
|
|
551
|
+
"$schema": "https://raw.githubusercontent.com/getsolaris/copse/main/schema.json",
|
|
552
|
+
"version": 1,
|
|
553
|
+
"theme": "dracula",
|
|
554
|
+
"defaults": {
|
|
555
|
+
"worktreeDir": "~/.copse/worktrees/{repo}-{branch}",
|
|
556
|
+
"copyFiles": [".env"],
|
|
557
|
+
"linkFiles": ["node_modules"],
|
|
558
|
+
"postCreate": ["bun install"],
|
|
559
|
+
"postRemove": [],
|
|
560
|
+
"sharedDeps": {
|
|
561
|
+
"strategy": "hardlink",
|
|
562
|
+
"paths": ["node_modules"],
|
|
563
|
+
"invalidateOn": ["package.json", "bun.lockb"]
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
"templates": {
|
|
567
|
+
"review": {
|
|
568
|
+
"copyFiles": [".env.local"],
|
|
569
|
+
"postCreate": ["bun install", "bun run build"],
|
|
570
|
+
"autoUpstream": true
|
|
571
|
+
},
|
|
572
|
+
"hotfix": {
|
|
573
|
+
"base": "main",
|
|
574
|
+
"copyFiles": [".env.production"],
|
|
575
|
+
"postCreate": ["bun install"]
|
|
576
|
+
},
|
|
577
|
+
"experiment": {
|
|
578
|
+
"worktreeDir": "~/tmp/experiments/{branch}",
|
|
579
|
+
"postRemove": []
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"lifecycle": {
|
|
583
|
+
"autoCleanMerged": true,
|
|
584
|
+
"staleAfterDays": 14,
|
|
585
|
+
"maxWorktrees": 10
|
|
586
|
+
},
|
|
587
|
+
"sessions": {
|
|
588
|
+
"enabled": true,
|
|
589
|
+
"autoCreate": false,
|
|
590
|
+
"autoKill": true,
|
|
591
|
+
"prefix": "cop",
|
|
592
|
+
"defaultLayout": "dev",
|
|
593
|
+
"layouts": {
|
|
594
|
+
"dev": {
|
|
595
|
+
"windows": [
|
|
596
|
+
{ "name": "editor", "command": "$EDITOR ." },
|
|
597
|
+
{ "name": "dev", "command": "bun dev" },
|
|
598
|
+
{ "name": "test", "command": "bun test --watch" }
|
|
599
|
+
]
|
|
600
|
+
},
|
|
601
|
+
"minimal": {
|
|
602
|
+
"windows": [
|
|
603
|
+
{ "name": "shell" }
|
|
604
|
+
]
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
"workspaces": [
|
|
609
|
+
{
|
|
610
|
+
"path": "~/Desktop/work",
|
|
611
|
+
"depth": 1,
|
|
612
|
+
"exclude": ["node_modules", ".cache", "archived"],
|
|
613
|
+
"defaults": {
|
|
614
|
+
"copyFiles": [".env", ".env.local"],
|
|
615
|
+
"linkFiles": ["node_modules"],
|
|
616
|
+
"postCreate": ["bun install"],
|
|
617
|
+
"autoUpstream": true
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
],
|
|
621
|
+
"repos": [
|
|
622
|
+
{
|
|
623
|
+
"path": "/Users/me/dev/frontend",
|
|
624
|
+
"copyFiles": [".env", ".env.local"],
|
|
625
|
+
"linkFiles": ["node_modules", ".next"],
|
|
626
|
+
"postCreate": ["bun install", "bun run build"]
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"path": "/Users/me/dev/backend",
|
|
630
|
+
"copyFiles": [".env"],
|
|
631
|
+
"postCreate": ["pip install -r requirements.txt"]
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
"path": "/Users/me/dev/monorepo",
|
|
635
|
+
"copyFiles": [".env"],
|
|
636
|
+
"postCreate": ["pnpm install"],
|
|
637
|
+
"monorepo": {
|
|
638
|
+
"autoDetect": true,
|
|
639
|
+
"extraPatterns": ["apps/*/*"],
|
|
640
|
+
"hooks": [
|
|
641
|
+
{
|
|
642
|
+
"glob": "apps/web",
|
|
643
|
+
"copyFiles": [".env"],
|
|
644
|
+
"postCreate": ["cd {packagePath} && pnpm install"]
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
"glob": "apps/api",
|
|
648
|
+
"copyFiles": [".env"],
|
|
649
|
+
"linkFiles": ["node_modules"],
|
|
650
|
+
"postCreate": ["cd {packagePath} && pnpm install && pnpm build"]
|
|
651
|
+
}
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
]
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Config Fields
|
|
660
|
+
|
|
661
|
+
#### `defaults`
|
|
662
|
+
|
|
663
|
+
All repos inherit these unless overridden.
|
|
664
|
+
|
|
665
|
+
| Field | Type | Default | Description |
|
|
666
|
+
| ------------- | ---------- | ---------------------------------- | --------------------------------------- |
|
|
667
|
+
| `worktreeDir` | `string` | `~/.copse/worktrees/{repo}-{branch}` | Worktree directory pattern |
|
|
668
|
+
| `copyFiles` | `string[]` | `[]` | Files to copy from main repo |
|
|
669
|
+
| `linkFiles` | `string[]` | `[]` | Files/dirs to symlink (saves disk) |
|
|
670
|
+
| `postCreate` | `string[]` | `[]` | Commands to run after worktree creation |
|
|
671
|
+
| `postRemove` | `string[]` | `[]` | Commands to run before worktree removal |
|
|
672
|
+
|
|
673
|
+
#### `repos[]`
|
|
674
|
+
|
|
675
|
+
Per-repo overrides. Each entry requires `path`.
|
|
676
|
+
|
|
677
|
+
| Field | Type | Required | Description |
|
|
678
|
+
| ------------- | ---------- | -------- | ----------------------------------- |
|
|
679
|
+
| `path` | `string` | Yes | Absolute path to the repository |
|
|
680
|
+
| `worktreeDir` | `string` | No | Override default worktree directory |
|
|
681
|
+
| `copyFiles` | `string[]` | No | Override default copy files |
|
|
682
|
+
| `linkFiles` | `string[]` | No | Override default link files |
|
|
683
|
+
| `postCreate` | `string[]` | No | Override default post-create hooks |
|
|
684
|
+
| `postRemove` | `string[]` | No | Override default post-remove hooks |
|
|
685
|
+
| `monorepo` | `object` | No | Monorepo support config |
|
|
686
|
+
|
|
687
|
+
#### `workspaces[]`
|
|
688
|
+
|
|
689
|
+
Auto-discover git repositories under parent directories. Each discovered repo is merged into `repos[]` at load time with the workspace's `defaults` as its override layer.
|
|
690
|
+
|
|
691
|
+
```json
|
|
692
|
+
{
|
|
693
|
+
"workspaces": [
|
|
694
|
+
{
|
|
695
|
+
"path": "~/Desktop/work",
|
|
696
|
+
"depth": 1,
|
|
697
|
+
"exclude": ["node_modules", ".cache", "archived"],
|
|
698
|
+
"defaults": {
|
|
699
|
+
"copyFiles": [".env", ".env.local"],
|
|
700
|
+
"linkFiles": ["node_modules"],
|
|
701
|
+
"postCreate": ["bun install"],
|
|
702
|
+
"autoUpstream": true
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
]
|
|
706
|
+
}
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
| Field | Type | Required | Default | Description |
|
|
710
|
+
| ---------- | ---------- | -------- | ------- | ------------------------------------------------------------------------------ |
|
|
711
|
+
| `path` | `string` | Yes | — | Parent directory to scan. Supports `~` expansion. |
|
|
712
|
+
| `depth` | `integer` | No | `1` | Scan depth (1–3). `1` means immediate children only. |
|
|
713
|
+
| `exclude` | `string[]` | No | `[]` | Glob patterns matched against directory names to skip (e.g. `node_modules`). |
|
|
714
|
+
| `defaults` | `object` | No | — | Per-repo defaults applied to every discovered repo. Same fields as `defaults`. |
|
|
715
|
+
|
|
716
|
+
**Discovery rules:**
|
|
717
|
+
|
|
718
|
+
- A directory is a repo only if it contains a `.git` **directory** (not a file). Linked worktrees (`.git` as file) and submodules are skipped.
|
|
719
|
+
- Discovered repos do NOT have their children scanned (no recursion into repos).
|
|
720
|
+
- Symbolic links are not followed.
|
|
721
|
+
- Discovery runs on every `loadConfig()` call. There is no caching.
|
|
722
|
+
|
|
723
|
+
**Precedence (highest → lowest):**
|
|
724
|
+
|
|
725
|
+
1. Explicit `repos[]` entry with the same resolved path — wins entirely.
|
|
726
|
+
2. `workspaces[].defaults` — repo-level override layer.
|
|
727
|
+
3. Top-level `defaults`.
|
|
728
|
+
4. Built-in defaults.
|
|
729
|
+
|
|
730
|
+
**`workspaces[].defaults` does NOT support `monorepo`.** If you need monorepo hooks for a discovered repo, add an explicit `repos[]` entry for it.
|
|
731
|
+
|
|
732
|
+
**TUI display:** The Config view (Ctrl+P → Open Config) shows the file *as authored*. Workspace-discovered repos appear under their own `Workspaces (N)` section, not under `Repos (N)`. The `Repos` count therefore reflects only your explicit `repos[]` entries, even when workspace discovery is adding more repos at runtime. Editing any field via the Config view writes back the raw, user-authored shape — auto-discovered repos are never serialized into `repos[]` on disk.
|
|
733
|
+
|
|
734
|
+
#### `monorepo`
|
|
735
|
+
|
|
736
|
+
Universal monorepo support. Auto-detects packages from workspace config files and supports per-package hooks.
|
|
737
|
+
|
|
738
|
+
```json
|
|
739
|
+
{
|
|
740
|
+
"monorepo": {
|
|
741
|
+
"autoDetect": true,
|
|
742
|
+
"extraPatterns": ["apps/*/*"],
|
|
743
|
+
"hooks": [
|
|
744
|
+
{
|
|
745
|
+
"glob": "apps/mobile/*",
|
|
746
|
+
"copyFiles": [".env"],
|
|
747
|
+
"linkFiles": ["node_modules"],
|
|
748
|
+
"postCreate": ["cd {packagePath} && pnpm install"]
|
|
749
|
+
}
|
|
750
|
+
]
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
| Field | Type | Default | Description |
|
|
756
|
+
| --------------- | ---------- | ------- | ----------------------------------------- |
|
|
757
|
+
| `autoDetect` | `boolean` | `true` | Auto-detect monorepo tools |
|
|
758
|
+
| `extraPatterns` | `string[]` | `[]` | Extra glob patterns for package discovery |
|
|
759
|
+
| `hooks` | `array` | `[]` | Per-package hook definitions |
|
|
760
|
+
|
|
761
|
+
**Auto-detection** supports: pnpm workspaces, Turborepo, Nx, Lerna, npm/yarn workspaces.
|
|
762
|
+
|
|
763
|
+
**`extraPatterns`** catches packages not covered by auto-detection. For example, if your `pnpm-workspace.yaml` only covers `packages/*` but you also have apps at `apps/frontend/dashboard`, use `extraPatterns: ["apps/*/*"]`.
|
|
764
|
+
|
|
765
|
+
#### `monorepo.hooks[]`
|
|
766
|
+
|
|
767
|
+
Per-package hooks matched by glob pattern against focus paths.
|
|
768
|
+
|
|
769
|
+
| Field | Type | Required | Description |
|
|
770
|
+
| ------------ | ---------- | -------- | ------------------------------------------------------------------------------ |
|
|
771
|
+
| `glob` | `string` | Yes | Glob to match focus paths (e.g. `apps/*`, `apps/mobile/*`) |
|
|
772
|
+
| `copyFiles` | `string[]` | No | Files to copy within the matched package directory |
|
|
773
|
+
| `linkFiles` | `string[]` | No | Files/dirs to symlink within the matched package directory |
|
|
774
|
+
| `postCreate` | `string[]` | No | Commands to run after creation. Supports `{packagePath}`, `{repo}`, `{branch}` |
|
|
775
|
+
| `postRemove` | `string[]` | No | Commands to run before removal |
|
|
776
|
+
|
|
777
|
+
Hooks execute in declaration order, after the repo-level `postCreate`/`postRemove`.
|
|
778
|
+
|
|
779
|
+
**`copyFiles`/`linkFiles` in hooks** operate on the **package subdirectory**, not the repo root. For example, with `glob: "apps/mobile/*"` and `copyFiles: [".env"]`, the `.env` file is copied from `<main-repo>/apps/mobile/ios/.env` to `<worktree>/apps/mobile/ios/.env`.
|
|
780
|
+
|
|
781
|
+
#### `templates`
|
|
782
|
+
|
|
783
|
+
Named presets for worktree creation. Each template can override any default field.
|
|
784
|
+
|
|
785
|
+
```json
|
|
786
|
+
{
|
|
787
|
+
"templates": {
|
|
788
|
+
"review": {
|
|
789
|
+
"copyFiles": [".env.local"],
|
|
790
|
+
"postCreate": ["bun install", "bun run build"],
|
|
791
|
+
"autoUpstream": true
|
|
792
|
+
},
|
|
793
|
+
"hotfix": {
|
|
794
|
+
"base": "main",
|
|
795
|
+
"copyFiles": [".env.production"],
|
|
796
|
+
"postCreate": ["bun install"]
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
| Field | Type | Description |
|
|
803
|
+
| -------------- | ---------- | ---------------------------------- |
|
|
804
|
+
| `worktreeDir` | `string` | Override worktree directory |
|
|
805
|
+
| `copyFiles` | `string[]` | Override files to copy |
|
|
806
|
+
| `linkFiles` | `string[]` | Override files to symlink |
|
|
807
|
+
| `postCreate` | `string[]` | Override post-create hooks |
|
|
808
|
+
| `postRemove` | `string[]` | Override post-remove hooks |
|
|
809
|
+
| `autoUpstream` | `boolean` | Override upstream tracking |
|
|
810
|
+
| `base` | `string` | Default base branch for newly created branches |
|
|
811
|
+
|
|
812
|
+
Usage: `cop add feature/login --template review`
|
|
813
|
+
|
|
814
|
+
Template values override the resolved repo config. The `base` field sets a default for `--base` if not explicitly provided.
|
|
815
|
+
|
|
816
|
+
#### `lifecycle`
|
|
817
|
+
|
|
818
|
+
Automatic worktree lifecycle management. Used by `cop clean --stale`.
|
|
819
|
+
|
|
820
|
+
```json
|
|
821
|
+
{
|
|
822
|
+
"lifecycle": {
|
|
823
|
+
"autoCleanMerged": true,
|
|
824
|
+
"staleAfterDays": 14,
|
|
825
|
+
"maxWorktrees": 10
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
| Field | Type | Default | Description |
|
|
831
|
+
| ----------------- | --------- | ------- | ------------------------------------------- |
|
|
832
|
+
| `autoCleanMerged` | `boolean` | `false` | Flag merged worktrees for cleanup |
|
|
833
|
+
| `staleAfterDays` | `number` | — | Days of inactivity before flagging as stale |
|
|
834
|
+
| `maxWorktrees` | `number` | — | Warn when exceeding this count |
|
|
835
|
+
|
|
836
|
+
#### Config Profiles
|
|
837
|
+
|
|
838
|
+
Switch between different configuration sets.
|
|
839
|
+
|
|
840
|
+
```bash
|
|
841
|
+
cop config --profiles # List profiles
|
|
842
|
+
cop config --profile work --activate # Activate profile
|
|
843
|
+
cop config --profile personal --delete # Delete profile
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
#### `sessions`
|
|
847
|
+
|
|
848
|
+
Tmux session management for worktrees.
|
|
849
|
+
|
|
850
|
+
```json
|
|
851
|
+
{
|
|
852
|
+
"sessions": {
|
|
853
|
+
"enabled": true,
|
|
854
|
+
"autoCreate": true,
|
|
855
|
+
"autoKill": true,
|
|
856
|
+
"prefix": "cop",
|
|
857
|
+
"defaultLayout": "dev",
|
|
858
|
+
"layouts": {
|
|
859
|
+
"dev": {
|
|
860
|
+
"windows": [
|
|
861
|
+
{ "name": "editor", "command": "$EDITOR ." },
|
|
862
|
+
{ "name": "dev", "command": "bun dev" },
|
|
863
|
+
{ "name": "test", "command": "bun test --watch" }
|
|
864
|
+
]
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
| Field | Type | Default | Description |
|
|
872
|
+
| --------------- | --------- | ------- | -------------------------------------------------- |
|
|
873
|
+
| `enabled` | `boolean` | `false` | Enable session integration (auto-switch in tmux) |
|
|
874
|
+
| `autoCreate` | `boolean` | `false` | Auto-create tmux session on `cop add` |
|
|
875
|
+
| `autoKill` | `boolean` | `false` | Auto-kill tmux session on `cop remove` |
|
|
876
|
+
| `prefix` | `string` | `"cop"` | Prefix for tmux session names |
|
|
877
|
+
| `defaultLayout` | `string` | — | Default layout name for new sessions |
|
|
878
|
+
| `layouts` | `object` | `{}` | Named layouts with window definitions |
|
|
879
|
+
|
|
880
|
+
**Layout windows:**
|
|
881
|
+
|
|
882
|
+
| Field | Type | Required | Description |
|
|
883
|
+
| --------- | -------- | -------- | ------------------------------ |
|
|
884
|
+
| `name` | `string` | Yes | Window name |
|
|
885
|
+
| `command` | `string` | No | Command to run in the window |
|
|
886
|
+
|
|
887
|
+
Session naming: branch `feat/auth-token` → tmux session `cop_feat-auth-token`.
|
|
888
|
+
|
|
889
|
+
#### `sharedDeps`
|
|
890
|
+
|
|
891
|
+
Share dependencies between main repo and worktrees to save disk space. Can be set in `defaults` or per-repo.
|
|
892
|
+
|
|
893
|
+
```json
|
|
894
|
+
{
|
|
895
|
+
"defaults": {
|
|
896
|
+
"sharedDeps": {
|
|
897
|
+
"strategy": "hardlink",
|
|
898
|
+
"paths": ["node_modules"],
|
|
899
|
+
"invalidateOn": ["package.json", "bun.lockb"]
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
| Field | Type | Default | Description |
|
|
906
|
+
| -------------- | ---------- | ----------- | ------------------------------------------ |
|
|
907
|
+
| `strategy` | `string` | `"symlink"` | `"hardlink"`, `"symlink"`, or `"copy"` |
|
|
908
|
+
| `paths` | `string[]` | `[]` | Directories/files to share |
|
|
909
|
+
| `invalidateOn` | `string[]` | `[]` | Files that trigger re-sharing when changed |
|
|
910
|
+
|
|
911
|
+
**Strategies:**
|
|
912
|
+
|
|
913
|
+
- `hardlink` — Create hard links for each file (saves disk, each worktree can modify independently for files that get rewritten)
|
|
914
|
+
- `symlink` — Create a symlink to the source directory (most disk savings, shared state)
|
|
915
|
+
- `copy` — Fall back to regular copy
|
|
916
|
+
|
|
917
|
+
### `--focus` Flag
|
|
918
|
+
|
|
919
|
+
Track which monorepo packages a worktree is working on.
|
|
920
|
+
|
|
921
|
+
```bash
|
|
922
|
+
cop add feature/login --focus apps/web,apps/api
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
- Supports comma-separated, space-separated, or multiple `--focus` flags
|
|
926
|
+
- Focus metadata is stored in git internals (not in the worktree root)
|
|
927
|
+
- `cop list` shows focus paths per worktree
|
|
928
|
+
- Monorepo hooks only fire for matching focus paths
|
|
929
|
+
- Focus is optional — omitting it creates a normal worktree
|
|
930
|
+
|
|
931
|
+
### Template Variables
|
|
932
|
+
|
|
933
|
+
Available in `worktreeDir` and monorepo hook commands:
|
|
934
|
+
|
|
935
|
+
| Variable | Description | Example |
|
|
936
|
+
| --------------- | ------------------------------------------ | -------------- |
|
|
937
|
+
| `{repo}` | Repository directory name | `my-app` |
|
|
938
|
+
| `{branch}` | Branch name (`/` replaced with `-`) | `feature-auth` |
|
|
939
|
+
| `{packagePath}` | Matched package path (monorepo hooks only) | `apps/web` |
|
|
940
|
+
| `~` | Home directory (only at path start) | `/Users/me` |
|
|
941
|
+
|
|
942
|
+
### Priority
|
|
943
|
+
|
|
944
|
+
Per-repo settings completely replace defaults (no merging):
|
|
945
|
+
|
|
946
|
+
```
|
|
947
|
+
repos[].copyFiles exists? → use repos[].copyFiles
|
|
948
|
+
repos[].copyFiles missing? → use defaults.copyFiles
|
|
949
|
+
defaults.copyFiles missing? → use [] (empty)
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
### Themes
|
|
953
|
+
|
|
954
|
+
Set via config or command palette (`Ctrl+P`):
|
|
955
|
+
|
|
956
|
+
```json
|
|
957
|
+
{ "theme": "tokyo-night" }
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
Available: `opencode`, `tokyo-night`, `dracula`, `nord`, `catppuccin`, `github-dark`, `one-dark`, `monokai`, `github-light`
|
|
961
|
+
|
|
962
|
+
## Shell Integration
|
|
963
|
+
|
|
964
|
+
Use `cop shell-init` to install shell integration for `cop switch`.
|
|
965
|
+
|
|
966
|
+
### Completions
|
|
967
|
+
|
|
968
|
+
```bash
|
|
969
|
+
# Add completions (bash)
|
|
970
|
+
eval "$(cop shell-init --completions bash)"
|
|
971
|
+
|
|
972
|
+
# Add completions (zsh)
|
|
973
|
+
eval "$(cop shell-init --completions zsh)"
|
|
974
|
+
|
|
975
|
+
# Add completions (fish)
|
|
976
|
+
cop shell-init --completions fish | source
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
### Examples
|
|
980
|
+
|
|
981
|
+
```bash
|
|
982
|
+
# zsh
|
|
983
|
+
echo 'eval "$(cop shell-init zsh)"' >> ~/.zshrc
|
|
984
|
+
source ~/.zshrc
|
|
985
|
+
|
|
986
|
+
# bash
|
|
987
|
+
echo 'eval "$(cop shell-init bash)"' >> ~/.bashrc
|
|
988
|
+
source ~/.bashrc
|
|
989
|
+
|
|
990
|
+
# fish
|
|
991
|
+
cop shell-init fish >> ~/.config/fish/config.fish
|
|
992
|
+
source ~/.config/fish/config.fish
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
You can also preview the generated wrapper before saving it:
|
|
996
|
+
|
|
997
|
+
```bash
|
|
998
|
+
cop shell-init zsh
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
## License
|
|
1002
|
+
|
|
1003
|
+
MIT © getsolaris
|