yggtree 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,9 @@
3
3
  [![npm version](https://img.shields.io/npm/v/yggtree.svg)](https://www.npmjs.com/package/yggtree)
4
4
  [![license](https://img.shields.io/npm/l/yggtree.svg)](https://www.npmjs.com/package/yggtree)
5
5
 
6
- **Yggdrasil Worktree** (invoked as `yggtree`) is a powerful, interactive CLI designed to streamline your Git worktree workflow. Like the mythical world tree connecting the realms, Yggdrasil connects your branches into isolated, manageable worktrees.
6
+ **Yggdrasil Worktree** (invoked as `yggtree`) is an interactive CLI designed to turn Git worktrees into a first‑class workflow.
7
+
8
+ Like the mythical world tree connecting realms, Yggdrasil lets you grow isolated, parallel environments where ideas can evolve independently without colliding.
7
9
 
8
10
  ---
9
11
 
@@ -11,84 +13,106 @@
11
13
 
12
14
  ### Installation
13
15
 
14
- You can run it directly without installing:
16
+ Run without installing:
15
17
 
16
18
  ```bash
17
19
  npx yggtree
18
20
  ```
19
21
 
20
- Or install it globally for convenience:
22
+ Or install globally:
21
23
 
22
24
  ```bash
23
25
  npm install -g yggtree
24
26
  ```
25
27
 
26
- ### Usage
28
+ ### Basic Usage
27
29
 
28
- Simply run `yggtree` to open the interactive menu:
30
+ Run with no arguments to open the interactive menu:
29
31
 
30
32
  ```bash
31
33
  yggtree
32
34
  ```
33
35
 
34
- Or use specific commands:
36
+ Or use commands directly:
35
37
 
36
38
  ```bash
37
- yggtree wt create # Smart branch-based creation
38
- yggtree wt list # View all managed worktrees
39
- yggtree wt prune # Clean up stale worktree data
39
+ yggtree wt create
40
+ yggtree wt list
41
+ yggtree wt enter my-feature
40
42
  ```
41
43
 
42
44
  ---
43
45
 
44
- ## Key Features
46
+ ## 🧠 Mental Model
47
+
48
+ Yggdrasil is built around a few core ideas:
49
+
50
+ * **Branches are ideas**
51
+ * **Worktrees are realities**
52
+ * **Each task deserves its own realm**
53
+
54
+ Instead of constantly switching branches in one working directory, Yggdrasil creates **isolated worktrees**, each mapped to a branch, living outside your main repo.
45
55
 
46
- ### 🌿 Smart Branch Creation (`wt create`)
47
- The primary way to start working. Instead of worrying about folder names, just tell Yggdrasil which branch you want to work on.
48
- - **Auto-Slug**: Converts `feat/eng-123-ui` to a clean folder name like `feat-eng-123-ui`.
49
- - **Auto-Branching**: If the branch doesn't exist, Yggdrasil creates it for you from a base branch.
50
- - **Remote Awareness**: Seamlessly base your work on `origin/main` or local refs.
56
+ All managed worktrees live under:
51
57
 
52
- ### 🌳 Batch Creation (`wt create-multi`)
53
- Need to spin up multiple features? Provide branch names separated by spaces, and Yggdrasil will provision all of them in one go.
58
+ ```
59
+ ~/.yggtree/<repo-name>/<worktree-slug>
60
+ ```
54
61
 
55
- ### 🚀 Custom Bootstrapping
56
- Configure your environment automatically using an `anvil-worktree.json` (also compatible with `.cursor/worktrees.json`) file in your project root.
62
+ This keeps your main repository clean while enabling true parallelism.
57
63
 
58
64
  ---
59
65
 
60
66
  ## 🤔 Why Yggdrasil Worktree?
61
67
 
62
- Git worktrees are incredibly powerful, but they are also **painfully manual** once you go beyond a single task.
68
+ Git worktrees are powerful, but once you start doing **parallel work**, they become tedious to manage manually.
63
69
 
64
- Modern development isn’t sequential anymore. You’re constantly switching contexts, juggling experiments, fixes, reviews, and now **AI agents running in parallel**.
70
+ Modern development looks like this:
65
71
 
66
- Yggdrasil exists to solve three modern problems at once:
72
+ * Fixing a bug
73
+ * Reviewing a PR
74
+ * Prototyping a feature
75
+ * Letting AI agents explore refactors
76
+ * Running tests in isolation
67
77
 
68
- 1. **Parallel work without context collision**
69
- 2. **Fast environment setup per task**
70
- 3. **Agent-friendly isolation for AI workflows**
78
+ All at the same time.
71
79
 
72
- Instead of juggling branches, folders, and bootstrap scripts by hand, Yggdrasil gives you a repeatable, intentional workflow.
73
- Each worktree becomes its own **small realm** — isolated, focused, and safe to explore.
80
+ Yggdrasil exists to solve three problems together:
81
+
82
+ 1. Parallel work without context collision
83
+ 2. Fast, repeatable environment setup
84
+ 3. Agent‑friendly isolation for AI workflows
85
+
86
+ Each worktree becomes its own **small realm**, safe to explore and easy to discard.
74
87
 
75
88
  ---
76
89
 
77
- ## 🧠 Parallel Development, Done Right
90
+ ## Key Features
78
91
 
79
- Traditional branching assumes *sequential* work.
92
+ 🌳 **First-class worktree workflow**
93
+ Create, manage, and navigate Git worktrees as a primary workflow, not an afterthought.
80
94
 
81
- Reality looks more like this:
95
+ 🧠 **Parallel development by default**
96
+ Work on multiple branches at the same time, each in its own isolated environment.
82
97
 
83
- * You’re fixing a bug
84
- * Reviewing a PR
85
- * Prototyping a feature
86
- * Letting an AI agent explore refactors
87
- * Letting another agent generate tests
98
+ 🤖 **AI-friendly isolation**
99
+ One worktree per agent, per experiment, per idea. No shared state, no collisions.
88
100
 
89
- All at the same time.
101
+ **Automatic bootstrapping**
102
+ Run installs, submodules, and setup scripts automatically for each worktree.
103
+
104
+ 🚪 **Enter, exec, and exit with ease**
105
+ Enter worktrees, execute commands, or run tasks without changing directories.
106
+
107
+ 📍 **Predictable structure**
108
+ All managed worktrees live under `~/.yggtree`, keeping your repository clean.
90
109
 
91
- Yggdrasil lets each task live in its **own isolated worktree** — a separate realm where ideas can evolve without colliding.
110
+ 🧭 **Interactive or scriptable**
111
+ Use the interactive UI or drive everything through commands and flags.
112
+
113
+ ---
114
+
115
+ ## 🧠 Parallel Development, Done Right
92
116
 
93
117
  ```bash
94
118
  yggtree wt create feat/eng-2581-state-selection
@@ -96,74 +120,184 @@ yggtree wt create fix/eng-2610-validation
96
120
  yggtree wt create chore/cleanup-api
97
121
  ```
98
122
 
99
- Each command spins up:
123
+ Each command creates:
100
124
 
101
125
  * A clean folder
102
126
  * A dedicated branch
103
- * A fully bootstrapped environment
127
+ * A bootstrapped environment
104
128
 
105
- No context bleeding.
106
129
  No stash juggling.
107
- No “what branch am I on?” moments.
130
+ No branch confusion.
131
+ No shared state accidents.
108
132
 
109
133
  ---
110
134
 
111
- ## 🤖 Built for AI-Assisted Workflows
112
-
113
- Yggdrasil shines when combined with AI agents.
135
+ ## 🤖 Built for AIAssisted Workflows
114
136
 
115
- Instead of running agents against the same working directory, you can:
137
+ Yggdrasil shines when paired with AI agents.
116
138
 
117
- * Assign one worktree per agent
118
- * Let each agent explore independently
119
- * Compare results safely
120
- * Merge only what makes sense
121
-
122
- Example workflow:
139
+ Instead of running agents against the same directory, you can assign **one worktree per agent**.
123
140
 
124
141
  ```bash
125
- # Prepare isolated worktrees
126
- yggtree wt create feat/ai-refactor-a
127
- yggtree wt create feat/ai-refactor-b
142
+ yggtree wt create feat/ai-refactor-a --exec "cursor ."
143
+ yggtree wt create feat/ai-refactor-b --exec "codex"
128
144
  ```
129
145
 
130
- Each agent operates in its own realm, free to experiment without side effects.
131
-
132
- This enables patterns like:
146
+ Each agent operates in its own realm:
133
147
 
134
148
  * Model A refactors architecture
135
149
  * Model B focuses on tests
136
- * Model C explores performance improvements
150
+ * Model C explores performance
137
151
 
138
- All in parallel.
139
- All reviewable.
140
- All under your control.
152
+ All in parallel. All reviewable. All isolated.
141
153
 
142
154
  ---
143
155
 
144
- ## ⚡ Zero-Friction Bootstrapping
156
+ ## ⚡ Bootstrapping & Configuration
157
+
158
+ Yggdrasil automatically prepares each worktree.
145
159
 
146
- Every worktree can auto-configure itself.
160
+ Resolution order:
147
161
 
148
- Yggdrasil reads your project’s setup file and prepares the realm immediately:
162
+ 1. `yggtree-worktree.json` inside the worktree
163
+ 2. `yggtree-worktree.json` in the repo root
164
+ 3. `.cursor/worktrees.json`
165
+ 4. Fallback: `npm install` + submodules
166
+
167
+ ### Example configuration
149
168
 
150
169
  ```json
151
170
  {
152
171
  "setup-worktree": [
153
172
  "npm install",
154
173
  "git submodule sync --recursive",
155
- "git submodule update --init --recursive"
174
+ "git submodule update --init --recursive",
175
+ "echo \"🌳 Realm ready\""
156
176
  ]
157
177
  }
158
178
  ```
159
179
 
160
- That means:
180
+ ---
181
+
182
+ ## 🛠️ Command Reference
183
+
184
+ ### `yggtree`
185
+
186
+ Open the interactive menu.
187
+
188
+ ---
189
+
190
+ ### `yggtree wt create [branch]`
191
+
192
+ Create a worktree from a branch.
193
+
194
+ Options:
195
+
196
+ * `--base <ref>`
197
+ * `--source local|remote`
198
+ * `--no-bootstrap`
199
+ * `--enter / --no-enter`
200
+ * `--exec "<command>"`
201
+
202
+ <details>
203
+ <summary>Example</summary>
204
+
205
+ ```bash
206
+ yggtree wt create feat/new-ui --base main --exec "cursor ."
207
+ ```
208
+
209
+ </details>
210
+
211
+ ---
212
+
213
+ ### `yggtree wt create-multi`
214
+
215
+ Create multiple worktrees at once.
216
+
217
+ <details>
218
+ <summary>Example</summary>
219
+
220
+ ```bash
221
+ yggtree wt create-multi --base main
222
+ ```
223
+
224
+ </details>
225
+
226
+ ---
227
+
228
+ ### `yggtree wt list`
229
+
230
+ List all worktrees with state.
161
231
 
162
- * No manual installs
163
- * No forgotten submodules
164
- * No “works on main but not here” surprises
232
+ Columns:
165
233
 
166
- You enter a worktree and it’s ready to work.
234
+ * TYPE (MAIN / MANAGED)
235
+ * STATE (clean / dirty)
236
+ * BRANCH
237
+ * PATH
238
+
239
+ ---
240
+
241
+ ### `yggtree wt enter [worktree]`
242
+
243
+ Enter a worktree using a sub‑shell.
244
+
245
+ * Uses your default shell
246
+ * Type `exit` to return
247
+
248
+ Optional:
249
+
250
+ * `--exec "<command>"`
251
+
252
+ <details>
253
+ <summary>Example</summary>
254
+
255
+ ```bash
256
+ yggtree wt enter feat/new-ui --exec "npm test"
257
+ ```
258
+
259
+ </details>
260
+
261
+ ---
262
+
263
+ ### `yggtree wt exec [worktree] -- <command>`
264
+
265
+ Run a command inside a worktree **without entering**.
266
+
267
+ <details>
268
+ <summary>Example</summary>
269
+
270
+ ```bash
271
+ yggtree wt exec feat/new-ui -- npm test
272
+ ```
273
+
274
+ </details>
275
+
276
+ ---
277
+
278
+ ### `yggtree wt path [worktree]`
279
+
280
+ Print a `cd` command for a worktree.
281
+
282
+ Useful for scripting and shell aliases.
283
+
284
+ ---
285
+
286
+ ### `yggtree wt bootstrap`
287
+
288
+ Re‑run bootstrap commands for a worktree.
289
+
290
+ ---
291
+
292
+ ### `yggtree wt delete`
293
+
294
+ Interactively delete managed worktrees.
295
+
296
+ ---
297
+
298
+ ### `yggtree wt prune`
299
+
300
+ Clean up stale git worktree metadata.
167
301
 
168
302
  ---
169
303
 
@@ -172,74 +306,136 @@ You enter a worktree and it’s ready to work.
172
306
  Yggdrasil is ideal when:
173
307
 
174
308
  * You work on multiple tasks in parallel
175
- * You use AI agents for exploration or execution
309
+ * You use AI agents for exploration
176
310
  * You want isolation without duplication
177
- * You value repeatable, scripted setup
178
- * You’re tired of fighting your own repo
311
+ * You value scripted, repeatable setups
312
+ * `git checkout` no longer scales
179
313
 
180
- If your workflow has outgrown `git checkout`, Yggdrasil is the missing layer.
314
+ ---
315
+
316
+ ## 📝 Practical Examples
317
+
318
+ <details>
319
+ <summary>Create a worktree and enter it immediately</summary>
320
+
321
+ **Command:**
322
+
323
+ ```
324
+ yggtree wt create feat/login-flow
325
+ ```
326
+
327
+ **What happens:**
181
328
 
329
+ * Creates a new branch if it doesn’t exist
330
+ * Creates a dedicated worktree
331
+ * Runs bootstrap if enabled
332
+ * Drops you into a sub-shell inside the worktree
333
+
334
+ </details>
182
335
  ---
183
336
 
184
- ## 🌍 Philosophy
337
+ <details>
338
+ <summary>Create a worktree without bootstrap and without entering</summary>
185
339
 
186
- Branches are ideas.
187
- Worktrees are realities.
340
+ **Command:**
341
+
342
+ ```
343
+ yggtree wt create feat/cleanup-api --no-bootstrap --no-enter
344
+ ```
188
345
 
189
- Yggdrasil helps you keep each idea grounded in its own world — until you decide which ones deserve to merge.
346
+ **When to use:**
190
347
 
348
+ * You just want the folder ready
349
+ * You’ll enter it later
350
+ * You don’t want installs running automatically
191
351
 
352
+ </details>
192
353
  ---
193
354
 
194
- ## ⚙️ Configuration
355
+ <details>
356
+ <summary>Create a worktree and open it in your IDE</summary>
195
357
 
196
- Yggdrasil looks for setup instructions in your project root:
358
+ **Command:**
197
359
 
198
- ```json
199
- {
200
- "setup-worktree": [
201
- "npm install",
202
- "git submodule sync --recursive",
203
- "git submodule update --init --recursive",
204
- "npm run build",
205
- "echo '🌳 The realm is ready!'"
206
- ]
207
- }
360
+ ```
361
+ yggtree wt create feat/ui-refactor --exec "cursor ."
208
362
  ```
209
363
 
364
+ Works with:
365
+
366
+ * `cursor .`
367
+ * `code .`
368
+ * `codex`
369
+ * Any custom command available in your shell
370
+
371
+ </details>
210
372
  ---
211
373
 
212
- ## 🛠️ Commands Reference
374
+ <details>
375
+ <summary>Execute a command inside an existing worktree (no shell)</summary>
376
+
377
+ **Command:**
213
378
 
214
- | Command | Description |
215
- | :--- | :--- |
216
- | `yggtree` | Open the interactive main menu. |
217
- | `yggtree wt create` | Create a worktree by branch name (Recommended). |
218
- | `yggtree wt create-multi` | Create multiple worktrees in a single command. |
219
- | `yggtree wt create-slug` | Manually specify both folder name and branch ref. |
220
- | `yggtree wt list` | List all managed worktrees and their status. |
221
- | `yggtree wt delete` | Interactively select and remove a worktree. |
222
- | `yggtree wt bootstrap` | Re-run the setup commands for an existing worktree. |
223
- | `yggtree wt prune` | Clean up Git's internal data for worktrees. |
379
+ ```
380
+ yggtree wt exec test -- npm test
381
+ ```
224
382
 
383
+ **What this does:**
384
+
385
+ * Runs the command inside the selected worktree
386
+ * Does not enter a sub-shell
387
+ * Ideal for CI-like checks, scripts, or quick validations
388
+
389
+ </details>
225
390
  ---
226
391
 
227
- ## 🛠️ Development
392
+ <details>
393
+ <summary>Enter a worktree and run a command before entering</summary>
228
394
 
229
- If you'd like to contribute or run the latest development version:
395
+ **Command:**
230
396
 
231
- ```bash
232
- # Clone the repository
233
- git clone https://github.com/leoreisdias/yggdrasil-cli.git
234
- cd yggdrasil-cli
397
+ ```
398
+ yggtree wt enter test --exec "codex"
399
+ ```
400
+
401
+ **What happens:**
402
+
403
+ * Executes the command inside the worktree
404
+ * Then drops you into a sub-shell
405
+ * Type `exit` to return to your original directory
406
+
407
+ </details>
408
+ ---
235
409
 
236
- # Install dependencies and build
237
- npm install
238
- npm run build
410
+ <details>
411
+ <summary>Get the path to a worktree</summary>
412
+
413
+ **Command:**
414
+
415
+ ```
416
+ yggtree wt path test
417
+ ```
418
+
419
+ **Output:**
239
420
 
240
- # Link the CLI locally
241
- npm link
242
421
  ```
422
+ cd ~/.yggtree/your-repo-name/test
423
+ ```
424
+
425
+ Useful when you want to manually navigate or copy the path into scripts.
426
+
427
+ </details>
428
+
429
+ ---
430
+
431
+ ## 🌍 Philosophy
432
+
433
+ Branches are ideas.
434
+ Worktrees are realities.
435
+
436
+ Yggdrasil helps you grow many worlds and decide later which ones deserve to merge.
437
+
438
+ ---
243
439
 
244
440
  ## 📄 License
245
441
 
@@ -38,7 +38,7 @@ export async function bootstrapCommand() {
38
38
  log.success('Bootstrap completed!');
39
39
  }
40
40
  catch (error) {
41
- log.error(error.message);
41
+ log.actionableError(error.message, 'yggtree wt bootstrap');
42
42
  process.exit(1);
43
43
  }
44
44
  }
@@ -41,33 +41,40 @@ export async function createCommandNew(options) {
41
41
  { name: 'Local', value: 'local' },
42
42
  ],
43
43
  default: 'remote',
44
- when: !options.base,
44
+ when: !options.base && !options.source,
45
45
  },
46
46
  {
47
47
  type: 'confirm',
48
48
  name: 'bootstrap',
49
49
  message: 'Run bootstrap? (npm install + submodules)',
50
50
  default: true,
51
- when: options.bootstrap !== false,
51
+ when: options.bootstrap !== false && options.bootstrap !== true,
52
+ },
53
+ {
54
+ type: 'confirm',
55
+ name: 'shouldEnter',
56
+ message: 'Do you want to enter the new worktree now?',
57
+ default: true,
58
+ when: options.enter === undefined,
52
59
  },
60
+ {
61
+ type: 'input',
62
+ name: 'exec',
63
+ message: 'Command to run after creation (optional):',
64
+ default: options.exec,
65
+ when: options.exec === undefined,
66
+ }
53
67
  ]);
54
- let shouldEnter = false;
55
- if (!options.branch) {
56
- const finalAnswer = await inquirer.prompt([{
57
- type: 'confirm',
58
- name: 'shouldEnter',
59
- message: 'Do you want to enter the new worktree now?',
60
- default: true
61
- }]);
62
- shouldEnter = finalAnswer.shouldEnter;
63
- }
64
68
  const branchName = options.branch || answers.branch;
65
69
  let baseRef = options.base || answers.base;
70
+ const source = options.source || answers.source;
71
+ const shouldEnter = options.enter !== undefined ? options.enter : answers.shouldEnter;
72
+ const shouldBootstrap = options.bootstrap !== undefined ? options.bootstrap : answers.bootstrap;
73
+ const execCommandStr = options.exec || answers.exec;
66
74
  // Append origin/ if remote is selected and not already present
67
- if (!options.base && answers.source === 'remote' && !baseRef.startsWith('origin/')) {
75
+ if (!options.base && source === 'remote' && !baseRef.startsWith('origin/')) {
68
76
  baseRef = `origin/${baseRef}`;
69
77
  }
70
- const shouldBootstrap = options.bootstrap === false ? false : answers.bootstrap;
71
78
  // Convert branch name to slug (friendly folder name)
72
79
  // e.g. feat/eng-2222-new-button -> feat-eng-2222-new-button
73
80
  const slug = branchName.replace(/[\/\\]/g, '-').replace(/\s+/g, '-');
@@ -107,14 +114,38 @@ export async function createCommandNew(options) {
107
114
  }
108
115
  catch (e) {
109
116
  spinner.fail('Failed to create worktree.');
110
- log.error(e.message);
117
+ const cmd = targetBranchExists
118
+ ? `git worktree add ${wtPath} ${branchName}`
119
+ : `git worktree add -b ${branchName} ${wtPath} ${baseRef}`;
120
+ log.actionableError(e.message, cmd, wtPath, [
121
+ 'Check if the folder already exists: ls ' + wtPath,
122
+ 'Check if the branch is already used: git worktree list',
123
+ 'Try pruning stale worktrees: yggtree wt prune',
124
+ `Run manually: ${cmd}`
125
+ ]);
111
126
  return;
112
127
  }
113
- // 4. Bootstrap
114
128
  if (shouldBootstrap) {
115
129
  await runBootstrap(wtPath, repoRoot);
116
130
  }
117
- // 5. Final Output
131
+ // 5. Exec Command
132
+ if (execCommandStr && execCommandStr.trim()) {
133
+ log.info(`Executing: ${execCommandStr} in ${ui.path(wtPath)}`);
134
+ try {
135
+ await execa(execCommandStr, {
136
+ cwd: wtPath,
137
+ stdio: 'inherit',
138
+ shell: true
139
+ });
140
+ }
141
+ catch (error) {
142
+ log.actionableError(error.message, execCommandStr, wtPath, [
143
+ `cd ${wtPath} && ${execCommandStr}`,
144
+ 'Check your command syntax and environment variables'
145
+ ]);
146
+ }
147
+ }
148
+ // 6. Final Output
118
149
  log.success('Worktree ready!');
119
150
  if (shouldEnter) {
120
151
  log.info(`Spawning sub-shell in ${ui.path(wtPath)}...`);
@@ -133,7 +164,7 @@ export async function createCommandNew(options) {
133
164
  }
134
165
  }
135
166
  catch (error) {
136
- log.error(error.message);
167
+ log.actionableError(error.message, 'yggtree wt create');
137
168
  process.exit(1);
138
169
  }
139
170
  }