yggtree 1.4.1 → 1.4.3
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 +131 -87
- package/dist/commands/wt/create-branch.js +21 -35
- package/dist/commands/wt/create-multi.js +11 -2
- package/dist/commands/wt/create-sandbox.js +21 -35
- package/dist/commands/wt/create.js +109 -58
- package/dist/commands/wt/enter.js +3 -2
- package/dist/commands/wt/list.js +23 -6
- package/dist/commands/wt/open.js +207 -53
- package/dist/index.js +133 -111
- package/dist/lib/env-files.js +72 -0
- package/dist/lib/git.js +89 -6
- package/dist/lib/registry.js +81 -0
- package/dist/lib/repo-context.js +46 -0
- package/dist/lib/update-check.js +55 -0
- package/dist/lib/worktree.js +12 -0
- package/package.json +12 -3
package/README.md
CHANGED
|
@@ -7,22 +7,69 @@
|
|
|
7
7
|
|
|
8
8
|
Like the mythical world tree connecting realms, Yggdrasil lets you grow isolated, parallel environments where ideas can evolve independently without colliding.
|
|
9
9
|
|
|
10
|
+
For guided workflows, command examples, and safety notes, read the full docs:
|
|
11
|
+
**[yggtree.logbookfordevs.com/docs](https://yggtree.logbookfordevs.com/docs)**.
|
|
12
|
+
|
|
10
13
|
---
|
|
11
14
|
|
|
12
15
|
## 🚀 Quick Start
|
|
13
16
|
|
|
14
17
|
### Installation
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
Install globally:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g yggtree
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or try it without installing:
|
|
17
26
|
|
|
18
27
|
```bash
|
|
19
28
|
npx yggtree
|
|
20
29
|
```
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
### Agent Skills
|
|
32
|
+
|
|
33
|
+
An agent skill is now available for your favorite agents.
|
|
34
|
+
|
|
35
|
+
`yggtree` ships one consolidated skill that helps agents choose the right
|
|
36
|
+
worktree workflow first, then load the smallest reference they need:
|
|
37
|
+
|
|
38
|
+
* **Create a task worktree**: start a brand-new branch-backed task in parallel.
|
|
39
|
+
* **Branch off without stashing**: jump into another branch without disturbing
|
|
40
|
+
the work already in progress.
|
|
41
|
+
* **Bootstrap and use a realm**: prepare a worktree, open it in your IDE, or
|
|
42
|
+
run commands inside it.
|
|
43
|
+
* **Run sandbox experiments**: try alternative approaches locally and
|
|
44
|
+
apply/unapply the winner safely.
|
|
45
|
+
|
|
46
|
+
This skill is especially useful with agents like **Claude Code**,
|
|
47
|
+
**Codex**, **Cursor**, **Gemini CLI**, and other tools that support the open
|
|
48
|
+
Skills ecosystem.
|
|
49
|
+
|
|
50
|
+
Install it with the Skills CLI:
|
|
23
51
|
|
|
24
52
|
```bash
|
|
25
|
-
|
|
53
|
+
npx skills add logbookfordevs/yggdrasil-worktree
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Install it globally for your user:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx skills add logbookfordevs/yggdrasil-worktree --global
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Install only the consolidated `yggtree` skill:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx skills add logbookfordevs/yggdrasil-worktree --skill yggtree
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If your agent supports targeted installs, you can also point the install to a
|
|
69
|
+
specific agent runtime, for example:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx skills add logbookfordevs/yggdrasil-worktree --agent codex
|
|
26
73
|
```
|
|
27
74
|
|
|
28
75
|
### Basic Usage
|
|
@@ -36,11 +83,14 @@ yggtree
|
|
|
36
83
|
Or use commands directly:
|
|
37
84
|
|
|
38
85
|
```bash
|
|
39
|
-
yggtree
|
|
40
|
-
yggtree
|
|
41
|
-
yggtree
|
|
86
|
+
yggtree create
|
|
87
|
+
yggtree list
|
|
88
|
+
yggtree wc --ref my-feature
|
|
89
|
+
yggtree -v
|
|
42
90
|
```
|
|
43
91
|
|
|
92
|
+
The older `yggtree wt ...` form still works for compatibility, but direct commands are the preferred shape.
|
|
93
|
+
|
|
44
94
|
---
|
|
45
95
|
|
|
46
96
|
## 🧠 Mental Model
|
|
@@ -118,9 +168,9 @@ Use the interactive UI or drive everything through commands and flags.
|
|
|
118
168
|
## 🧠 Parallel Development, Done Right
|
|
119
169
|
|
|
120
170
|
```bash
|
|
121
|
-
yggtree
|
|
122
|
-
yggtree
|
|
123
|
-
yggtree
|
|
171
|
+
yggtree create feat/city-selection
|
|
172
|
+
yggtree create fix/validation
|
|
173
|
+
yggtree create chore/cleanup-api
|
|
124
174
|
```
|
|
125
175
|
|
|
126
176
|
Each command creates:
|
|
@@ -142,8 +192,8 @@ Yggdrasil shines when paired with AI agents.
|
|
|
142
192
|
Instead of running agents against the same directory, you can assign **one worktree per agent**.
|
|
143
193
|
|
|
144
194
|
```bash
|
|
145
|
-
yggtree
|
|
146
|
-
yggtree
|
|
195
|
+
yggtree create feat/ai-refactor-a --exec "cursor ."
|
|
196
|
+
yggtree create feat/ai-refactor-b --exec "codex"
|
|
147
197
|
```
|
|
148
198
|
|
|
149
199
|
Each agent operates in its own realm:
|
|
@@ -162,10 +212,10 @@ Sometimes you don't want to "commit to a branch" yet. You just want to try somet
|
|
|
162
212
|
|
|
163
213
|
**Sandboxes** are temporary, local-only worktrees designed for this:
|
|
164
214
|
|
|
165
|
-
1. **Create**: `yggtree
|
|
215
|
+
1. **Create**: `yggtree create-sandbox` (creates something like `sandbox-a3f2_feature-branch`).
|
|
166
216
|
2. **Experiment**: Change files, run tests, try that risky refactor.
|
|
167
|
-
3. **Apply**: `yggtree
|
|
168
|
-
4. **Unapply**: Don't like it? `yggtree
|
|
217
|
+
3. **Apply**: `yggtree apply` to "push" those file changes back to your origin directory.
|
|
218
|
+
4. **Unapply**: Don't like it? `yggtree unapply` restores your origin to exactly how it was before.
|
|
169
219
|
|
|
170
220
|
Sandboxes are **not pushed to remote** and their names are randomly generated because they are meant to be temporary playgrounds.
|
|
171
221
|
|
|
@@ -208,7 +258,7 @@ Open the interactive menu.
|
|
|
208
258
|
|
|
209
259
|
---
|
|
210
260
|
|
|
211
|
-
### `yggtree
|
|
261
|
+
### `yggtree create [branch]`
|
|
212
262
|
|
|
213
263
|
Create a worktree from a branch.
|
|
214
264
|
|
|
@@ -218,26 +268,26 @@ Options:
|
|
|
218
268
|
* `--base <ref>`
|
|
219
269
|
* `--source local|remote`
|
|
220
270
|
* `--no-bootstrap`
|
|
221
|
-
* `--
|
|
271
|
+
* `--open / --no-open`
|
|
222
272
|
* `--exec "<command>"`
|
|
223
273
|
|
|
224
274
|
Interactive flow:
|
|
225
275
|
|
|
226
|
-
* Instead of asking for a free-form `exec` command, yggtree now asks if you want to open
|
|
276
|
+
* Instead of asking for a free-form `exec` command, yggtree now asks if you want to open an editor after creation.
|
|
227
277
|
* `--exec` remains available as an advanced explicit override.
|
|
228
278
|
|
|
229
279
|
<details>
|
|
230
280
|
<summary>Example</summary>
|
|
231
281
|
|
|
232
282
|
```bash
|
|
233
|
-
yggtree
|
|
283
|
+
yggtree create feat/new-ui --base main --exec "cursor ."
|
|
234
284
|
```
|
|
235
285
|
|
|
236
286
|
</details>
|
|
237
287
|
|
|
238
288
|
---
|
|
239
289
|
|
|
240
|
-
### `yggtree
|
|
290
|
+
### `yggtree worktree-checkout [name] [ref]`
|
|
241
291
|
|
|
242
292
|
Create a checkout-style worktree from an existing branch.
|
|
243
293
|
|
|
@@ -245,34 +295,46 @@ Behavior:
|
|
|
245
295
|
|
|
246
296
|
* Prompts a searchable branch picker (type to filter in real time).
|
|
247
297
|
* Attaches the new worktree directly to the selected branch (checkout-style).
|
|
298
|
+
* If a branch exists both locally and on `origin`, the picker shows both `branch` (local) and `origin/branch` (remote tip, detached) as explicit choices.
|
|
248
299
|
* If you select a remote-only branch (`origin/*`), yggtree creates the local branch in the new worktree automatically.
|
|
249
|
-
* If that branch already has an active
|
|
300
|
+
* If that branch already has an active worktree, yggtree falls back to using that worktree instead of creating a duplicate.
|
|
301
|
+
* By default, yggtree ends the flow inside the worktree shell.
|
|
302
|
+
* `yggtree wc` is a short alias for the same flow.
|
|
250
303
|
|
|
251
304
|
Options:
|
|
252
305
|
|
|
253
306
|
* `-n, --name <slug>`
|
|
254
307
|
* `-r, --ref <ref>`: skip picker and use a specific branch (`feature/x` or `origin/feature/x`)
|
|
255
308
|
* `--no-bootstrap`
|
|
256
|
-
* `--
|
|
309
|
+
* `--open / --no-open`: choose whether to open editors or run a startup command before the worktree shell starts
|
|
310
|
+
* `--tool <command>`: open a specific editor/app and skip the open prompt (`cursor`, `code`, `codex-app`)
|
|
311
|
+
* `--no-enter`: finish after create/open and return to the caller
|
|
257
312
|
* `--exec "<command>"`
|
|
258
313
|
|
|
259
314
|
Interactive flow:
|
|
260
315
|
|
|
261
|
-
*
|
|
316
|
+
* Yggtree asks what to open before starting the worktree shell.
|
|
317
|
+
* Editor choices can be selected together.
|
|
318
|
+
* Use `--tool` to skip the open prompt and launch one editor/app directly.
|
|
319
|
+
* `Other command...` runs a command in the Yggtree shell first, then leaves you there.
|
|
320
|
+
* Use `--no-enter` when you only want the worktree created/opened and the command to return.
|
|
262
321
|
* `--exec` remains available as an advanced explicit override.
|
|
263
322
|
|
|
264
323
|
<details>
|
|
265
324
|
<summary>Example</summary>
|
|
266
325
|
|
|
267
326
|
```bash
|
|
268
|
-
yggtree
|
|
327
|
+
yggtree worktree-checkout -n hotfix-auth -r main --no-open
|
|
328
|
+
yggtree wc hotfix-auth main --open
|
|
329
|
+
yggtree wc hotfix-auth main --tool codex-app
|
|
330
|
+
yggtree wc hotfix-auth main --open --no-enter
|
|
269
331
|
```
|
|
270
332
|
|
|
271
333
|
</details>
|
|
272
334
|
|
|
273
335
|
---
|
|
274
336
|
|
|
275
|
-
### `yggtree
|
|
337
|
+
### `yggtree create-sandbox`
|
|
276
338
|
|
|
277
339
|
Create a temporary sandbox from your current local branch.
|
|
278
340
|
|
|
@@ -281,18 +343,18 @@ Options:
|
|
|
281
343
|
* `-n, --name <name>`: Optional sandbox name (auto-generated if omitted).
|
|
282
344
|
* `--carry / --no-carry`: Bring uncommitted changes (staged/unstaged/untracked) with you.
|
|
283
345
|
* `--no-bootstrap`
|
|
284
|
-
* `--
|
|
346
|
+
* `--open / --no-open`
|
|
285
347
|
* `--exec "<command>"`
|
|
286
348
|
|
|
287
349
|
Interactive flow:
|
|
288
350
|
|
|
289
351
|
* Prompts for an optional sandbox name (leave empty to auto-generate one from current branch).
|
|
290
|
-
* Instead of asking for a free-form `exec` command, yggtree now asks if you want to open
|
|
352
|
+
* Instead of asking for a free-form `exec` command, yggtree now asks if you want to open an editor after creation.
|
|
291
353
|
* `--exec` remains available as an advanced explicit override.
|
|
292
354
|
|
|
293
355
|
---
|
|
294
356
|
|
|
295
|
-
### `yggtree
|
|
357
|
+
### `yggtree apply`
|
|
296
358
|
|
|
297
359
|
Apply changes from the current sandbox back to the origin repository.
|
|
298
360
|
* **Backs up** origin files before overwriting.
|
|
@@ -300,7 +362,7 @@ Apply changes from the current sandbox back to the origin repository.
|
|
|
300
362
|
|
|
301
363
|
---
|
|
302
364
|
|
|
303
|
-
### `yggtree
|
|
365
|
+
### `yggtree unapply`
|
|
304
366
|
|
|
305
367
|
Undo a previous `apply` operation.
|
|
306
368
|
* Restores origin files from the sandbox's backup.
|
|
@@ -308,7 +370,7 @@ Undo a previous `apply` operation.
|
|
|
308
370
|
|
|
309
371
|
---
|
|
310
372
|
|
|
311
|
-
### `yggtree
|
|
373
|
+
### `yggtree create-multi`
|
|
312
374
|
|
|
313
375
|
Create multiple worktrees at once.
|
|
314
376
|
|
|
@@ -322,14 +384,14 @@ Options:
|
|
|
322
384
|
<summary>Example</summary>
|
|
323
385
|
|
|
324
386
|
```bash
|
|
325
|
-
yggtree
|
|
387
|
+
yggtree create-multi --base main
|
|
326
388
|
```
|
|
327
389
|
|
|
328
390
|
</details>
|
|
329
391
|
|
|
330
392
|
---
|
|
331
393
|
|
|
332
|
-
### `yggtree
|
|
394
|
+
### `yggtree list`
|
|
333
395
|
|
|
334
396
|
List all repo-linked worktrees with state.
|
|
335
397
|
|
|
@@ -338,6 +400,7 @@ Columns:
|
|
|
338
400
|
* TYPE (`MAIN`, `MANAGED`, `LINKED`, `SANDBOX`)
|
|
339
401
|
* STATE (clean / dirty)
|
|
340
402
|
* LAST ACTIVE
|
|
403
|
+
* PR (optional — requires [GitHub CLI](https://cli.github.com/))
|
|
341
404
|
* BRANCH
|
|
342
405
|
|
|
343
406
|
Notes:
|
|
@@ -346,76 +409,57 @@ Notes:
|
|
|
346
409
|
* `SANDBOX` and `MANAGED` are worktrees inside `~/.yggtree`.
|
|
347
410
|
* External worktrees are labeled `LINKED`.
|
|
348
411
|
* Use `--open` to switch this flow into "pick and open in tool" mode.
|
|
412
|
+
* The **PR** column shows the pull request status for each branch (e.g. `OPEN`, `IN REVIEW`, `APPROVED`, `MERGED`, `DRAFT`, `CHANGES`). It only appears when `gh` CLI is installed and authenticated — otherwise it's silently omitted.
|
|
349
413
|
|
|
350
414
|
---
|
|
351
415
|
|
|
352
|
-
### `yggtree
|
|
353
|
-
|
|
354
|
-
Enter a worktree using a sub‑shell.
|
|
355
|
-
|
|
356
|
-
* Uses your default shell
|
|
357
|
-
* Type `exit` to return
|
|
358
|
-
|
|
359
|
-
Optional:
|
|
360
|
-
|
|
361
|
-
* `--exec "<command>"`
|
|
362
|
-
|
|
363
|
-
<details>
|
|
364
|
-
<summary>Example</summary>
|
|
365
|
-
|
|
366
|
-
```bash
|
|
367
|
-
yggtree wt enter feat/new-ui --exec "npm test"
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
</details>
|
|
371
|
-
|
|
372
|
-
---
|
|
373
|
-
|
|
374
|
-
### `yggtree wt open [worktree]`
|
|
416
|
+
### `yggtree open [worktree]`
|
|
375
417
|
|
|
376
|
-
Open a worktree in an
|
|
418
|
+
Open a worktree in an editor or supported desktop app.
|
|
377
419
|
|
|
378
420
|
Behavior:
|
|
379
421
|
|
|
380
422
|
* If `[worktree]` is omitted, you can pick from the worktree list with type-to-filter search.
|
|
381
|
-
* Detects available
|
|
382
|
-
*
|
|
383
|
-
*
|
|
423
|
+
* Detects available editor commands in your `PATH` (for example: `cursor`, `code`, `zed`, `webstorm`).
|
|
424
|
+
* Detects Codex App on macOS and launches it with `open -b com.openai.codex`.
|
|
425
|
+
* Lets you choose one or more editors/apps interactively, or pass `--tool`.
|
|
426
|
+
* By default, `open` launches editors/apps and returns.
|
|
427
|
+
* Use `wc --open` when you want to open a worktree and continue in its shell.
|
|
384
428
|
|
|
385
429
|
Options:
|
|
386
430
|
|
|
387
|
-
* `--tool <command>`
|
|
431
|
+
* `--tool <command>` (for example: `cursor`, `code`, `codex`, or `codex-app`)
|
|
388
432
|
|
|
389
433
|
<details>
|
|
390
434
|
<summary>Examples</summary>
|
|
391
435
|
|
|
392
436
|
```bash
|
|
393
|
-
yggtree
|
|
394
|
-
yggtree
|
|
395
|
-
yggtree
|
|
396
|
-
yggtree
|
|
437
|
+
yggtree open
|
|
438
|
+
yggtree open feat/new-ui --tool cursor
|
|
439
|
+
yggtree open feat/new-ui --tool codex-app
|
|
440
|
+
yggtree list --open
|
|
397
441
|
```
|
|
398
442
|
|
|
399
443
|
</details>
|
|
400
444
|
|
|
401
445
|
---
|
|
402
446
|
|
|
403
|
-
### `yggtree
|
|
447
|
+
### `yggtree exec [worktree] -- <command>`
|
|
404
448
|
|
|
405
|
-
Run a command inside a worktree
|
|
449
|
+
Run a command inside a worktree without changing your current terminal.
|
|
406
450
|
|
|
407
451
|
<details>
|
|
408
452
|
<summary>Example</summary>
|
|
409
453
|
|
|
410
454
|
```bash
|
|
411
|
-
yggtree
|
|
455
|
+
yggtree exec feat/new-ui -- npm test
|
|
412
456
|
```
|
|
413
457
|
|
|
414
458
|
</details>
|
|
415
459
|
|
|
416
460
|
---
|
|
417
461
|
|
|
418
|
-
### `yggtree
|
|
462
|
+
### `yggtree path [worktree]`
|
|
419
463
|
|
|
420
464
|
Print a `cd` command for a worktree.
|
|
421
465
|
|
|
@@ -423,13 +467,13 @@ Useful for scripting and shell aliases.
|
|
|
423
467
|
|
|
424
468
|
---
|
|
425
469
|
|
|
426
|
-
### `yggtree
|
|
470
|
+
### `yggtree bootstrap`
|
|
427
471
|
|
|
428
472
|
Re‑run bootstrap commands for a worktree.
|
|
429
473
|
|
|
430
474
|
---
|
|
431
475
|
|
|
432
|
-
### `yggtree
|
|
476
|
+
### `yggtree delete`
|
|
433
477
|
|
|
434
478
|
Interactively delete worktrees.
|
|
435
479
|
|
|
@@ -446,7 +490,7 @@ Optional:
|
|
|
446
490
|
|
|
447
491
|
---
|
|
448
492
|
|
|
449
|
-
### `yggtree
|
|
493
|
+
### `yggtree prune`
|
|
450
494
|
|
|
451
495
|
Clean up stale git worktree metadata.
|
|
452
496
|
|
|
@@ -467,12 +511,12 @@ Yggdrasil is ideal when:
|
|
|
467
511
|
## 📝 Practical Examples
|
|
468
512
|
|
|
469
513
|
<details>
|
|
470
|
-
<summary>Create a worktree
|
|
514
|
+
<summary>Create a worktree with the guided post-create flow</summary>
|
|
471
515
|
|
|
472
516
|
**Command:**
|
|
473
517
|
|
|
474
518
|
```
|
|
475
|
-
yggtree
|
|
519
|
+
yggtree create feat/login-flow
|
|
476
520
|
```
|
|
477
521
|
|
|
478
522
|
**What happens:**
|
|
@@ -480,25 +524,25 @@ yggtree wt create feat/login-flow
|
|
|
480
524
|
* Creates a new branch if it doesn’t exist (without inheriting base tracking), then publishes it to `origin` when possible
|
|
481
525
|
* Creates a dedicated worktree
|
|
482
526
|
* Runs bootstrap if enabled
|
|
483
|
-
*
|
|
527
|
+
* Lets you choose whether to open an editor after creation
|
|
484
528
|
|
|
485
529
|
|
|
486
530
|
</details>
|
|
487
531
|
---
|
|
488
532
|
|
|
489
533
|
<details>
|
|
490
|
-
<summary>Create a worktree without bootstrap and without
|
|
534
|
+
<summary>Create a worktree without bootstrap and without opening a tool</summary>
|
|
491
535
|
|
|
492
536
|
**Command:**
|
|
493
537
|
|
|
494
538
|
```
|
|
495
|
-
yggtree
|
|
539
|
+
yggtree create feat/cleanup-api --no-bootstrap --no-open
|
|
496
540
|
```
|
|
497
541
|
|
|
498
542
|
**When to use:**
|
|
499
543
|
|
|
500
544
|
* You just want the folder ready
|
|
501
|
-
* You’ll
|
|
545
|
+
* You’ll open it or move into its shell later if needed
|
|
502
546
|
* You don’t want installs running automatically
|
|
503
547
|
|
|
504
548
|
</details>
|
|
@@ -510,14 +554,13 @@ yggtree wt create feat/cleanup-api --no-bootstrap --no-enter
|
|
|
510
554
|
**Command:**
|
|
511
555
|
|
|
512
556
|
```
|
|
513
|
-
yggtree
|
|
557
|
+
yggtree create feat/ui-refactor --exec "cursor ."
|
|
514
558
|
```
|
|
515
559
|
|
|
516
560
|
Works with:
|
|
517
561
|
|
|
518
562
|
* `cursor .`
|
|
519
563
|
* `code .`
|
|
520
|
-
* `codex`
|
|
521
564
|
* Any custom command available in your shell
|
|
522
565
|
|
|
523
566
|
</details>
|
|
@@ -529,31 +572,32 @@ Works with:
|
|
|
529
572
|
**Command:**
|
|
530
573
|
|
|
531
574
|
```
|
|
532
|
-
yggtree
|
|
575
|
+
yggtree exec test -- npm test
|
|
533
576
|
```
|
|
534
577
|
|
|
535
578
|
**What this does:**
|
|
536
579
|
|
|
537
580
|
* Runs the command inside the selected worktree
|
|
538
|
-
*
|
|
581
|
+
* Keeps your current terminal where it is
|
|
539
582
|
* Ideal for CI-like checks, scripts, or quick validations
|
|
540
583
|
|
|
541
584
|
</details>
|
|
542
585
|
---
|
|
543
586
|
|
|
544
587
|
<details>
|
|
545
|
-
<summary>
|
|
588
|
+
<summary>Checkout a branch and run a startup command</summary>
|
|
546
589
|
|
|
547
590
|
**Command:**
|
|
548
591
|
|
|
549
592
|
```
|
|
550
|
-
yggtree
|
|
593
|
+
yggtree wc --ref test --open
|
|
551
594
|
```
|
|
552
595
|
|
|
553
596
|
**What happens:**
|
|
554
597
|
|
|
555
|
-
*
|
|
556
|
-
*
|
|
598
|
+
* Checks out or reuses the branch worktree
|
|
599
|
+
* Lets you choose an editor, supported app, or `Other command...`
|
|
600
|
+
* Starts a worktree shell unless you pass `--no-enter`
|
|
557
601
|
* Type `exit` to return to your original directory
|
|
558
602
|
|
|
559
603
|
</details>
|
|
@@ -565,7 +609,7 @@ yggtree wt enter test --exec "codex"
|
|
|
565
609
|
**Command:**
|
|
566
610
|
|
|
567
611
|
```
|
|
568
|
-
yggtree
|
|
612
|
+
yggtree path test
|
|
569
613
|
```
|
|
570
614
|
|
|
571
615
|
**Output:**
|
|
@@ -586,7 +630,7 @@ Useful when you want to manually navigate or copy the path into scripts.
|
|
|
586
630
|
**Command:**
|
|
587
631
|
|
|
588
632
|
```bash
|
|
589
|
-
yggtree
|
|
633
|
+
yggtree create-sandbox --carry
|
|
590
634
|
```
|
|
591
635
|
|
|
592
636
|
**Scenario:**
|
|
@@ -594,7 +638,7 @@ yggtree wt create-sandbox --carry
|
|
|
594
638
|
1. You have 5 files changed in your main repo but aren't sure about the direction.
|
|
595
639
|
2. Run `create-sandbox --carry` to move those changes into an isolated `sandbox-a3f2_feature-branch` folder.
|
|
596
640
|
3. Experiment freely.
|
|
597
|
-
4. If it works: `yggtree
|
|
641
|
+
4. If it works: `yggtree apply`.
|
|
598
642
|
5. If it fails: Just delete the sandbox or `unapply`.
|
|
599
643
|
|
|
600
644
|
</details>
|
|
@@ -5,14 +5,17 @@ import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch, ensure
|
|
|
5
5
|
import { runBootstrap } from '../../lib/config.js';
|
|
6
6
|
import { WORKTREES_ROOT } from '../../lib/paths.js';
|
|
7
7
|
import { log, ui, createSpinner } from '../../lib/ui.js';
|
|
8
|
-
import {
|
|
8
|
+
import { promptAndCopyEnvFiles } from '../../lib/env-files.js';
|
|
9
|
+
import { detectInstalledOpenTools, launchOpenTool, promptOpenToolSelection, } from './open.js';
|
|
9
10
|
import { execa } from 'execa';
|
|
10
|
-
import { spawn } from 'child_process';
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
12
|
export async function createCommandNew(options) {
|
|
13
13
|
try {
|
|
14
14
|
const repoRoot = await getRepoRoot();
|
|
15
15
|
log.info(`Repo: ${chalk.dim(repoRoot)}`);
|
|
16
|
+
if (options.enter !== undefined) {
|
|
17
|
+
log.warning('`--enter` / `--no-enter` is deprecated. Use `--open` / `--no-open` instead.');
|
|
18
|
+
}
|
|
16
19
|
// 1. Gather inputs
|
|
17
20
|
const currentBranch = await getCurrentBranch();
|
|
18
21
|
const answers = await inquirer.prompt([
|
|
@@ -51,28 +54,25 @@ export async function createCommandNew(options) {
|
|
|
51
54
|
default: true,
|
|
52
55
|
when: options.bootstrap !== false && options.bootstrap !== true,
|
|
53
56
|
},
|
|
54
|
-
{
|
|
55
|
-
type: 'confirm',
|
|
56
|
-
name: 'shouldEnter',
|
|
57
|
-
message: 'Do you want to enter the new worktree now?',
|
|
58
|
-
default: true,
|
|
59
|
-
when: options.enter === undefined,
|
|
60
|
-
},
|
|
61
57
|
{
|
|
62
58
|
type: 'confirm',
|
|
63
59
|
name: 'shouldOpenTool',
|
|
64
|
-
message: 'Open
|
|
60
|
+
message: 'Open an editor after creation?',
|
|
65
61
|
default: false,
|
|
66
|
-
when: options.exec === undefined,
|
|
62
|
+
when: options.exec === undefined && options.open === undefined && options.enter === undefined,
|
|
67
63
|
},
|
|
68
64
|
]);
|
|
69
65
|
const branchName = options.branch || answers.branch;
|
|
70
66
|
let baseRef = options.base || answers.base;
|
|
71
67
|
const source = options.source || answers.source;
|
|
72
|
-
const shouldEnter = options.enter !== undefined ? options.enter : answers.shouldEnter;
|
|
73
68
|
const shouldBootstrap = options.bootstrap !== undefined ? options.bootstrap : answers.bootstrap;
|
|
69
|
+
const shouldOpenTool = options.open !== undefined
|
|
70
|
+
? options.open
|
|
71
|
+
: options.enter !== undefined
|
|
72
|
+
? options.enter
|
|
73
|
+
: Boolean(answers.shouldOpenTool);
|
|
74
74
|
let selectedTool;
|
|
75
|
-
if (options.exec === undefined &&
|
|
75
|
+
if (options.exec === undefined && shouldOpenTool) {
|
|
76
76
|
const installedTools = await detectInstalledOpenTools();
|
|
77
77
|
if (installedTools.length === 0) {
|
|
78
78
|
log.warning('No IDE/agent tool detected in PATH. Skipping open step.');
|
|
@@ -81,7 +81,6 @@ export async function createCommandNew(options) {
|
|
|
81
81
|
selectedTool = await promptOpenToolSelection(installedTools, 'Select tool to open:');
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
const execCommandStr = options.exec || (selectedTool && isAgentTool(selectedTool) ? buildAgentExecCommand(selectedTool) : undefined);
|
|
85
84
|
// Append origin/ if remote is selected and not already present
|
|
86
85
|
if (!options.base && source === 'remote' && !baseRef.startsWith('origin/')) {
|
|
87
86
|
baseRef = `origin/${baseRef}`;
|
|
@@ -150,27 +149,28 @@ export async function createCommandNew(options) {
|
|
|
150
149
|
'Attempt to push manually: git push -u origin HEAD',
|
|
151
150
|
]);
|
|
152
151
|
}
|
|
152
|
+
await promptAndCopyEnvFiles(repoRoot, wtPath);
|
|
153
153
|
if (shouldBootstrap) {
|
|
154
154
|
await runBootstrap(wtPath, repoRoot);
|
|
155
155
|
}
|
|
156
156
|
// 5. Exec Command
|
|
157
|
-
if (
|
|
158
|
-
log.info(`Executing: ${
|
|
157
|
+
if (options.exec && options.exec.trim()) {
|
|
158
|
+
log.info(`Executing: ${options.exec} in ${ui.path(wtPath)}`);
|
|
159
159
|
try {
|
|
160
|
-
await execa(
|
|
160
|
+
await execa(options.exec, {
|
|
161
161
|
cwd: wtPath,
|
|
162
162
|
stdio: 'inherit',
|
|
163
163
|
shell: true
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
166
|
catch (error) {
|
|
167
|
-
log.actionableError(error.message,
|
|
168
|
-
`cd ${wtPath} && ${
|
|
167
|
+
log.actionableError(error.message, options.exec, wtPath, [
|
|
168
|
+
`cd ${wtPath} && ${options.exec}`,
|
|
169
169
|
'Check your command syntax and environment variables'
|
|
170
170
|
]);
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
if (selectedTool
|
|
173
|
+
else if (selectedTool) {
|
|
174
174
|
try {
|
|
175
175
|
log.info(`Opening ${ui.path(wtPath)} in ${chalk.cyan(selectedTool.name)}...`);
|
|
176
176
|
await launchOpenTool(selectedTool, wtPath);
|
|
@@ -181,21 +181,7 @@ export async function createCommandNew(options) {
|
|
|
181
181
|
}
|
|
182
182
|
// 6. Final Output
|
|
183
183
|
log.success('Worktree ready!');
|
|
184
|
-
|
|
185
|
-
log.info(`Spawning sub-shell in ${ui.path(wtPath)}...`);
|
|
186
|
-
log.dim('Type "exit" to return to the main terminal.');
|
|
187
|
-
const shell = process.env.SHELL || 'zsh';
|
|
188
|
-
const child = spawn(shell, [], {
|
|
189
|
-
cwd: wtPath,
|
|
190
|
-
stdio: 'inherit',
|
|
191
|
-
});
|
|
192
|
-
child.on('close', () => {
|
|
193
|
-
log.info('Exited sub-shell.');
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
log.header(`cd "${wtPath}"`);
|
|
198
|
-
}
|
|
184
|
+
log.header(`cd "${wtPath}"`);
|
|
199
185
|
}
|
|
200
186
|
catch (error) {
|
|
201
187
|
log.actionableError(error.message, 'yggtree wt create');
|
|
@@ -5,6 +5,7 @@ import { getRepoRoot, getRepoName, verifyRef, fetchAll, getCurrentBranch, ensure
|
|
|
5
5
|
import { runBootstrap } from '../../lib/config.js';
|
|
6
6
|
import { WORKTREES_ROOT } from '../../lib/paths.js';
|
|
7
7
|
import { log, ui, createSpinner } from '../../lib/ui.js';
|
|
8
|
+
import { findLocalEnvFiles, promptAndCopyEnvFilesToWorktrees } from '../../lib/env-files.js';
|
|
8
9
|
import { execa } from 'execa';
|
|
9
10
|
import fs from 'fs-extra';
|
|
10
11
|
export async function createCommandMulti(options) {
|
|
@@ -117,8 +118,16 @@ export async function createCommandMulti(options) {
|
|
|
117
118
|
]);
|
|
118
119
|
}
|
|
119
120
|
createdWorktrees.push(wtPath);
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
}
|
|
122
|
+
const envFiles = await findLocalEnvFiles(repoRoot);
|
|
123
|
+
if (envFiles.length > 0 && createdWorktrees.length > 0) {
|
|
124
|
+
await promptAndCopyEnvFilesToWorktrees(repoRoot, createdWorktrees, envFiles, {
|
|
125
|
+
promptMessage: `Copy local env file${envFiles.length === 1 ? '' : 's'} to all created worktrees? (${envFiles.join(', ')})`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// 4. Bootstrap
|
|
129
|
+
if (shouldBootstrap) {
|
|
130
|
+
for (const wtPath of createdWorktrees) {
|
|
122
131
|
await runBootstrap(wtPath, repoRoot);
|
|
123
132
|
}
|
|
124
133
|
}
|