@gw-tools/gw 0.2.0 → 0.8.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
@@ -2,25 +2,99 @@
2
2
 
3
3
  A command-line tool for managing git worktrees, built with Deno.
4
4
 
5
+ ## Table of Contents
6
+
7
+ - [gw - Git Worktree Tools](#gw---git-worktree-tools)
8
+ - [Table of Contents](#table-of-contents)
9
+ - [Quick Start](#quick-start)
10
+ - [Features](#features)
11
+ - [Installation](#installation)
12
+ - [Via npm (Recommended)](#via-npm-recommended)
13
+ - [Build from source](#build-from-source)
14
+ - [Configuration](#configuration)
15
+ - [Auto-Detection](#auto-detection)
16
+ - [Example Configuration](#example-configuration)
17
+ - [Configuration Options](#configuration-options)
18
+ - [Commands](#commands)
19
+ - [add](#add)
20
+ - [Arguments](#arguments)
21
+ - [Options](#options)
22
+ - [Examples](#examples)
23
+ - [Auto-Copy Configuration](#auto-copy-configuration)
24
+ - [cd](#cd)
25
+ - [Arguments](#arguments-1)
26
+ - [Examples](#examples-1)
27
+ - [How It Works](#how-it-works)
28
+ - [install-shell](#install-shell)
29
+ - [Options](#options-1)
30
+ - [Examples](#examples-2)
31
+ - [root](#root)
32
+ - [Examples](#examples-3)
33
+ - [How It Works](#how-it-works-1)
34
+ - [init](#init)
35
+ - [Options](#options-2)
36
+ - [Examples](#examples-4)
37
+ - [When to Use](#when-to-use)
38
+ - [sync](#sync)
39
+ - [Arguments](#arguments-2)
40
+ - [Options](#options-3)
41
+ - [Examples](#examples-5)
42
+ - [Git Worktree Proxy Commands](#git-worktree-proxy-commands)
43
+ - [list (ls)](#list-ls)
44
+ - [remove (rm)](#remove-rm)
45
+ - [move (mv)](#move-mv)
46
+ - [prune](#prune)
47
+ - [lock](#lock)
48
+ - [unlock](#unlock)
49
+ - [repair](#repair)
50
+ - [Use Case](#use-case)
51
+ - [Typical Workflow](#typical-workflow)
52
+ - [Development](#development)
53
+ - [Local Development \& Testing](#local-development--testing)
54
+ - [Method 1: Shell Alias (Recommended for Active Development)](#method-1-shell-alias-recommended-for-active-development)
55
+ - [Method 2: Symlink to Compiled Binary (Faster Execution)](#method-2-symlink-to-compiled-binary-faster-execution)
56
+ - [Method 3: Development Wrapper Script (Best of Both Worlds)](#method-3-development-wrapper-script-best-of-both-worlds)
57
+ - [Method 4: npm link (For Testing Installation)](#method-4-npm-link-for-testing-installation)
58
+ - [Watch Mode for Active Development](#watch-mode-for-active-development)
59
+ - [Available Scripts](#available-scripts)
60
+ - [Publishing](#publishing)
61
+ - [Automated Release (Recommended)](#automated-release-recommended)
62
+ - [Manual Publishing](#manual-publishing)
63
+ - [Publishing to JSR (Optional)](#publishing-to-jsr-optional)
64
+ - [Version Management](#version-management)
65
+ - [Project Structure](#project-structure)
66
+ - [Adding New Commands](#adding-new-commands)
67
+ - [License](#license)
68
+
5
69
  ## Quick Start
6
70
 
7
71
  ```bash
8
72
  # Install
9
73
  npm install -g @gw-tools/gw
10
74
 
11
- # Create a new worktree
12
- git worktree add feat-new-feature
75
+ # Create a new worktree and copy files
76
+ gw add feat-new-feature .env secrets/
77
+
78
+ # Navigate to your new worktree
79
+ gw cd feat-new-feature
80
+ ```
13
81
 
14
- # Copy secrets from main to the new worktree
15
- gw copy feat-new-feature .env
82
+ **Or with auto-copy (one-time setup):**
83
+
84
+ ```bash
85
+ # Configure auto-copy files once per repository
86
+ gw init --root $(gw root) --auto-copy-files .env,secrets/
16
87
 
17
- # Done! Your new worktree has all the secrets it needs
18
- cd feat-new-feature
88
+ # Now just create worktrees - files are copied automatically
89
+ gw add feat-another-feature
90
+ gw cd feat-another-feature
19
91
  ```
20
92
 
21
93
  ## Features
22
94
 
95
+ - **Quick navigation**: Navigate to worktrees instantly with smart partial matching (`gw cd feat` finds `feat-branch`)
23
96
  - **Copy files between worktrees**: Easily copy secrets, environment files, and configurations from one worktree to another
97
+ - **Automatic shell integration**: Shell function installs automatically on npm install for seamless `gw cd` navigation
24
98
  - **Multi-command architecture**: Extensible framework for adding new worktree management commands
25
99
  - **Auto-configured per repository**: Each repository gets its own local config file, automatically created on first use
26
100
  - **Dry-run mode**: Preview what would be copied without making changes
@@ -63,65 +137,551 @@ cp dist/packages/gw-tool/gw /usr/local/bin/gw
63
137
 
64
138
  ## Configuration
65
139
 
66
- On first run, `gw` will automatically create a configuration file at `<git-root>/.gw/config.json` in your repository. The tool finds the git repository root by walking up the directory tree from your current location.
140
+ On first run, `gw` will automatically detect your git repository root and create a configuration file at `.gw/config.json`. The tool finds the config by walking up the directory tree from your current location, so you can run `gw` commands from anywhere within your repository.
141
+
142
+ ### Auto-Detection
143
+
144
+ The tool automatically:
145
+
146
+ 1. **Searches for existing config**: Walks up from your current directory looking for `.gw/config.json`
147
+ 2. **Auto-detects git root**: If no config is found, detects the repository root automatically
148
+ 3. **Creates config**: Saves the detected root and default settings to `.gw/config.json`
149
+
150
+ If auto-detection fails (rare edge cases), you can manually initialize:
151
+
152
+ ```bash
153
+ gw init --root /path/to/your/repo.git
154
+ ```
67
155
 
68
156
  ### Example Configuration
69
157
 
70
158
  ```json
71
159
  {
72
- "defaultSource": "main"
160
+ "root": "/Users/username/Workspace/my-project.git",
161
+ "defaultBranch": "main",
162
+ "autoCopyFiles": [
163
+ ".env",
164
+ "components/agents/.env",
165
+ "components/ui/.vercel/"
166
+ ]
73
167
  }
74
168
  ```
75
169
 
76
170
  ### Configuration Options
77
171
 
78
- - **defaultSource**: Default source worktree name (optional, defaults to "main")
172
+ - **root**: Absolute path to the git repository root (automatically detected or manually set with `gw init`)
173
+ - **defaultBranch**: Default source worktree name (optional, defaults to "main")
174
+ - **autoCopyFiles**: Array of file/directory paths to automatically copy when creating worktrees with `gw add` (optional, only set via `gw init --auto-copy-files`)
79
175
 
80
176
  ## Commands
81
177
 
82
- ### copy
178
+ ### add
179
+
180
+ Create a new git worktree with optional automatic file copying.
181
+
182
+ ```bash
183
+ gw add <worktree-name> [files...]
184
+ ```
185
+
186
+ This command wraps `git worktree add` and optionally copies files to the new worktree. If `autoCopyFiles` is configured, those files are automatically copied. You can override this by specifying files as arguments.
187
+
188
+ #### Arguments
189
+
190
+ - `<worktree-name>`: Name or path for the new worktree
191
+ - `[files...]`: Optional files to copy (overrides `autoCopyFiles` config)
192
+
193
+ #### Options
194
+
195
+ All `git worktree add` options are supported:
196
+ - `-b <branch>`: Create a new branch
197
+ - `-B <branch>`: Create or reset a branch
198
+ - `--detach`: Detach HEAD in new worktree
199
+ - `--force, -f`: Force checkout even if already checked out
200
+ - `--track`: Track branch from remote
201
+ - `-h, --help`: Show help message
202
+
203
+ #### Examples
204
+
205
+ ```bash
206
+ # Create worktree (auto-copies files if autoCopyFiles is configured)
207
+ gw add feat/new-feature
208
+
209
+ # Create worktree with new branch
210
+ gw add feat/new-feature -b my-branch
211
+
212
+ # Create worktree and copy specific files (overrides config)
213
+ gw add feat/new-feature .env secrets/
214
+
215
+ # Force create even if branch exists elsewhere
216
+ gw add feat/bugfix -f
217
+ ```
218
+
219
+ #### Auto-Copy Configuration
220
+
221
+ To enable automatic file copying, configure `autoCopyFiles` using `gw init`:
222
+
223
+ ```bash
224
+ gw init --root /path/to/repo.git --auto-copy-files .env,secrets/,components/ui/.vercel/
225
+ ```
226
+
227
+ This creates:
228
+ ```json
229
+ {
230
+ "root": "/path/to/repo.git",
231
+ "defaultBranch": "main",
232
+ "autoCopyFiles": [".env", "secrets/", "components/ui/.vercel/"]
233
+ }
234
+ ```
235
+
236
+ Now every time you run `gw add`, these files will be automatically copied from your default source worktree (usually `main`) to the new worktree.
237
+
238
+ ### cd
239
+
240
+ Navigate directly to a worktree by name or partial match. The command uses smart matching to find worktrees, searching both branch names and worktree paths.
241
+
242
+ ```bash
243
+ gw cd <worktree>
244
+ ```
245
+
246
+ #### Arguments
247
+
248
+ - `<worktree>`: Name or partial name of the worktree (matches branch name or path)
249
+
250
+ #### Examples
251
+
252
+ ```bash
253
+ # Navigate to a worktree by exact name
254
+ gw cd feat-branch
255
+
256
+ # Navigate using partial match (finds "feat-new-feature")
257
+ gw cd feat
258
+
259
+ # If multiple matches found, shows list with helpful error:
260
+ gw cd api
261
+ # Output: Multiple worktrees match "api":
262
+ # api-refactor -> /path/to/repo/api-refactor
263
+ # graphql-api -> /path/to/repo/graphql-api
264
+ ```
265
+
266
+ #### How It Works
267
+
268
+ The `cd` command integrates with your shell through an automatically installed function (see [install-shell](#install-shell)). When you run `gw cd <worktree>`:
269
+
270
+ 1. The command finds the matching worktree path
271
+ 2. The shell function intercepts the call and navigates you there
272
+ 3. All other `gw` commands pass through normally
273
+
274
+ **Note**: Shell integration is automatically installed when you install via npm. If needed, you can manually install or remove it using `gw install-shell`.
275
+
276
+ ### install-shell
277
+
278
+ Install or remove shell integration for the `gw cd` command. This is automatically run during `npm install`, but can be run manually if needed.
279
+
280
+ ```bash
281
+ gw install-shell [options]
282
+ ```
283
+
284
+ #### Options
285
+
286
+ - `--remove`: Remove shell integration
287
+ - `--quiet, -q`: Suppress output messages
288
+ - `-h, --help`: Show help message
289
+
290
+ #### Examples
291
+
292
+ ```bash
293
+ # Install shell integration (usually not needed - auto-installed)
294
+ gw install-shell
295
+
296
+ # Remove shell integration
297
+ gw install-shell --remove
298
+
299
+ # Install quietly (for automation)
300
+ gw install-shell --quiet
301
+ ```
302
+
303
+ **Supported Shells:**
304
+ - **Zsh** (~/.zshrc)
305
+ - **Bash** (~/.bashrc)
306
+ - **Fish** (~/.config/fish/functions/gw.fish)
307
+
308
+ The command is idempotent - running it multiple times won't create duplicate entries.
309
+
310
+ ### root
311
+
312
+ Get the root directory of the current git repository. For git worktrees, returns the parent directory containing all worktrees.
313
+
314
+ ```bash
315
+ gw root
316
+ ```
317
+
318
+ This command is useful when working with git worktrees to find the main repository directory that contains all worktrees, regardless of how deeply nested you are in the directory structure.
83
319
 
84
- Copy files and directories between worktrees, preserving directory structure.
320
+ #### Examples
85
321
 
86
322
  ```bash
87
- gw copy [options] <target-worktree> <files...>
323
+ # Get repository root path
324
+ gw root
325
+ # Output: /Users/username/Workspace/my-project.git
326
+
327
+ # Navigate to repository root
328
+ cd "$(gw root)"
329
+
330
+ # List all worktrees
331
+ ls "$(gw root)"
332
+
333
+ # Use in scripts
334
+ REPO_ROOT=$(gw root)
335
+ echo "Repository is at: $REPO_ROOT"
336
+
337
+ # Works from any depth
338
+ cd /Users/username/Workspace/my-project.git/feat/deeply/nested/folder
339
+ gw root
340
+ # Output: /Users/username/Workspace/my-project.git
341
+ ```
342
+
343
+ #### How It Works
344
+
345
+ - **In a worktree**: Returns the parent directory containing all worktrees (e.g., `/path/to/repo.git`)
346
+ - **In a regular repo**: Returns the directory containing the `.git` directory
347
+ - **From nested directories**: Walks up the directory tree to find the repository root
348
+
349
+ ### init
350
+
351
+ Initialize gw configuration for a git repository. This command is only needed if auto-detection fails or if you want to manually specify the repository root.
352
+
353
+ ```bash
354
+ gw init --root <path> [options]
355
+ ```
356
+
357
+ #### Options
358
+
359
+ - `--root <path>`: Specify the git repository root path (required)
360
+ - `--default-source <name>`: Set the default source worktree (default: "main")
361
+ - `--auto-copy-files <files>`: Comma-separated list of files to auto-copy when creating worktrees with `gw add`
362
+ - `-h, --help`: Show help message
363
+
364
+ #### Examples
365
+
366
+ ```bash
367
+ # Initialize with repository root
368
+ gw init --root /Users/username/Workspace/my-project.git
369
+
370
+ # Initialize with custom default source
371
+ gw init --root /Users/username/Workspace/my-project.git --default-source master
372
+
373
+ # Initialize with auto-copy files
374
+ gw init --root /Users/username/Workspace/my-project.git --auto-copy-files .env,secrets/,components/ui/.vercel/
375
+
376
+ # Show help
377
+ gw init --help
378
+ ```
379
+
380
+ #### When to Use
381
+
382
+ In most cases, you won't need to run `gw init` manually because the tool auto-detects your repository root on first run. However, you may need it when:
383
+
384
+ - Auto-detection fails (rare edge cases with non-standard repository structures)
385
+ - You want to override the auto-detected root
386
+ - You're setting up configuration before the repository has standard git structures
387
+
388
+ The config file is created at `.gw/config.json` in your current directory, so you can run this command from wherever makes sense for your workflow (typically the repository root).
389
+
390
+ ### sync
391
+
392
+ Sync files and directories between worktrees, preserving directory structure.
393
+
394
+ ```bash
395
+ gw sync [options] <target-worktree> <files...>
88
396
  ```
89
397
 
90
398
  #### Arguments
91
399
 
92
400
  - `<target-worktree>`: Name or full path of the target worktree
93
- - `<files...>`: One or more files or directories to copy (paths relative to worktree root)
401
+ - `<files...>`: One or more files or directories to sync (paths relative to worktree root)
94
402
 
95
403
  #### Options
96
404
 
97
405
  - `--from <source>`: Source worktree name (default: from config or "main")
98
- - `-n, --dry-run`: Show what would be copied without actually copying
406
+ - `-n, --dry-run`: Show what would be synced without actually syncing
99
407
  - `-h, --help`: Show help message
100
408
 
101
409
  #### Examples
102
410
 
103
411
  ```bash
104
- # Copy .env file from main to feat-branch
105
- gw copy feat-branch .env
412
+ # Sync .env file from main to feat-branch
413
+ gw sync feat-branch .env
106
414
 
107
- # Copy multiple files
108
- gw copy feat-branch .env components/agents/.env components/agents/agents.yaml
415
+ # Sync multiple files
416
+ gw sync feat-branch .env components/agents/.env components/agents/agents.yaml
109
417
 
110
- # Copy entire directory
111
- gw copy feat-branch components/ui/.vercel
418
+ # Sync entire directory
419
+ gw sync feat-branch components/ui/.vercel
112
420
 
113
421
  # Use custom source worktree
114
- gw copy --from develop feat-branch .env
422
+ gw sync --from develop feat-branch .env
115
423
 
116
424
  # Dry run to preview changes
117
- gw copy --dry-run feat-branch .env
425
+ gw sync --dry-run feat-branch .env
118
426
 
119
427
  # Use absolute path as target
120
- gw copy /full/path/to/repo/feat-branch .env
428
+ gw sync /full/path/to/repo/feat-branch .env
429
+ ```
430
+
431
+ ### Git Worktree Proxy Commands
432
+
433
+ These commands wrap native `git worktree` operations, providing consistent colored output and help messages. All git flags and options are passed through transparently.
434
+
435
+ #### list (ls)
436
+
437
+ List all worktrees in the repository.
438
+
439
+ ```bash
440
+ gw list
441
+ # or
442
+ gw ls
443
+ ```
444
+
445
+ **Examples:**
446
+ ```bash
447
+ gw list # List all worktrees
448
+ gw list --porcelain # Machine-readable output
449
+ gw list -v # Verbose output
450
+ ```
451
+
452
+ #### remove (rm)
453
+
454
+ Remove a worktree from the repository.
455
+
456
+ ```bash
457
+ gw remove <worktree>
458
+ # or
459
+ gw rm <worktree>
460
+ ```
461
+
462
+ **Examples:**
463
+ ```bash
464
+ gw remove feat-branch # Remove a worktree
465
+ gw remove --force feat-branch # Force remove even if dirty
466
+ gw rm feat-branch # Using alias
467
+ ```
468
+
469
+ #### move (mv)
470
+
471
+ Move a worktree to a new location.
472
+
473
+ ```bash
474
+ gw move <worktree> <new-path>
475
+ # or
476
+ gw mv <worktree> <new-path>
477
+ ```
478
+
479
+ **Examples:**
480
+ ```bash
481
+ gw move feat-branch ../new-location
482
+ gw mv feat-branch ../new-location
483
+ ```
484
+
485
+ #### prune
486
+
487
+ Clean up worktree information for deleted worktrees.
488
+
489
+ ```bash
490
+ gw prune
491
+ ```
492
+
493
+ **Examples:**
494
+ ```bash
495
+ gw prune # Clean up stale worktree information
496
+ gw prune --dry-run # Preview what would be pruned
497
+ gw prune --verbose # Show detailed output
498
+ ```
499
+
500
+ #### lock
501
+
502
+ Lock a worktree to prevent removal.
503
+
504
+ ```bash
505
+ gw lock <worktree>
506
+ ```
507
+
508
+ **Examples:**
509
+ ```bash
510
+ gw lock feat-branch
511
+ gw lock --reason "Work in progress" feat-branch
512
+ ```
513
+
514
+ #### unlock
515
+
516
+ Unlock a worktree to allow removal.
517
+
518
+ ```bash
519
+ gw unlock <worktree>
520
+ ```
521
+
522
+ **Examples:**
523
+ ```bash
524
+ gw unlock feat-branch
525
+ ```
526
+
527
+ #### repair
528
+
529
+ Repair worktree administrative files.
530
+
531
+ ```bash
532
+ gw repair [<path>]
533
+ ```
534
+
535
+ **Examples:**
536
+ ```bash
537
+ gw repair # Repair all worktrees
538
+ gw repair /path/to/worktree # Repair specific worktree
539
+ ```
540
+
541
+ ## Use Case
542
+
543
+ This tool was originally created to simplify the workflow of copying secrets and environment files when creating new git worktrees. When you create a new worktree for a feature branch, you often need to copy `.env` files, credentials, and other configuration files from your main worktree to the new one. This tool automates that process.
544
+
545
+ The tool automatically detects which git repository you're working in and creates a local config file (`.gw/config.json`) on first use. The config stores the repository root and other settings, so subsequent runs are fast and don't need to re-detect the repository structure. Each repository has its own configuration, and you can customize the default source worktree per repository.
546
+
547
+ ### Typical Workflow
548
+
549
+ ```bash
550
+ # One-time setup: Configure auto-copy files
551
+ gw init --root $(gw root) --auto-copy-files .env,components/agents/.env,components/ui/.vercel/
552
+
553
+ # From within any worktree of your repository
554
+ # Create a new worktree with auto-copy
555
+ gw add feat-new-feature
556
+
557
+ # Navigate to your new worktree
558
+ gw cd feat-new-feature
559
+
560
+ # Alternative: Create worktree and copy specific files
561
+ gw add feat-bugfix .env custom-config.json
562
+
563
+ # Alternative: Use the manual sync command
564
+ git worktree add feat-manual
565
+ gw sync feat-manual .env
566
+ gw cd feat-manual
121
567
  ```
122
568
 
123
569
  ## Development
124
570
 
571
+ ### Local Development & Testing
572
+
573
+ When developing the tool, you can test changes locally without publishing by creating a global symlink. This allows you to use the `gw` command with live code updates.
574
+
575
+ #### Method 1: Shell Alias (Recommended for Active Development)
576
+
577
+ Create a shell alias that runs the Deno version directly with watch mode:
578
+
579
+ ```bash
580
+ # Add to your ~/.zshrc or ~/.bashrc
581
+ alias gw-dev='deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts'
582
+
583
+ # Reload your shell
584
+ source ~/.zshrc # or ~/.bashrc
585
+
586
+ # Now you can use it anywhere
587
+ cd ~/some-project
588
+ gw-dev copy feat-branch .env
589
+ ```
590
+
591
+ This gives you instant feedback - just edit the TypeScript files and run the command again.
592
+
593
+ #### Method 2: Symlink to Compiled Binary (Faster Execution)
594
+
595
+ Create a symlink to the compiled binary and recompile when needed:
596
+
597
+ ```bash
598
+ # From the workspace root
599
+ nx run gw-tool:compile
600
+
601
+ # Create global symlink (one-time setup)
602
+ sudo ln -sf ~/path/to/gw-tools/dist/packages/gw-tool/gw /usr/local/bin/gw
603
+
604
+ # Now you can use `gw` globally
605
+ cd ~/some-project
606
+ gw sync feat-branch .env
607
+
608
+ # When you make changes, recompile
609
+ nx run gw-tool:compile
610
+ # The symlink automatically points to the new binary
611
+ ```
612
+
613
+ #### Method 3: Development Wrapper Script (Best of Both Worlds)
614
+
615
+ Create a wrapper script that provides both speed and live updates:
616
+
617
+ ```bash
618
+ # Create ~/bin/gw (make sure ~/bin is in your PATH)
619
+ cat > ~/bin/gw << 'EOF'
620
+ #!/bin/bash
621
+ # Check if we're in development mode (set GW_DEV=1 to use source)
622
+ if [ "$GW_DEV" = "1" ]; then
623
+ exec deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts "$@"
624
+ else
625
+ exec ~/path/to/gw-tools/dist/packages/gw-tool/gw "$@"
626
+ fi
627
+ EOF
628
+
629
+ chmod +x ~/bin/gw
630
+
631
+ # Use compiled version (fast)
632
+ gw sync feat-branch .env
633
+
634
+ # Use development version with live updates
635
+ GW_DEV=1 gw sync feat-branch .env
636
+
637
+ # Or set it for your entire session
638
+ export GW_DEV=1
639
+ gw sync feat-branch .env
640
+ ```
641
+
642
+ #### Method 4: npm link (For Testing Installation)
643
+
644
+ Test the npm package installation flow locally:
645
+
646
+ ```bash
647
+ # Compile binaries
648
+ nx run gw-tool:compile-all
649
+
650
+ # Prepare npm package
651
+ nx run gw-tool:npm-pack
652
+
653
+ # Link the package globally
654
+ cd dist/packages/gw-tool/npm
655
+ npm link
656
+
657
+ # Now `gw` is available globally via npm
658
+ gw sync feat-branch .env
659
+
660
+ # When you make changes
661
+ cd ~/path/to/gw-tools
662
+ nx run gw-tool:compile-all
663
+ nx run gw-tool:npm-pack
664
+ # The link automatically uses the updated binaries
665
+
666
+ # To unlink when done
667
+ npm unlink -g @gw-tools/gw
668
+ ```
669
+
670
+ #### Watch Mode for Active Development
671
+
672
+ Use the watch mode to automatically restart when files change:
673
+
674
+ ```bash
675
+ # Terminal 1: Run in watch mode
676
+ nx run gw-tool:dev
677
+
678
+ # Terminal 2: Test in another project
679
+ cd ~/some-project
680
+ ~/path/to/gw-tools/dist/packages/gw-tool/gw sync feat-branch .env
681
+ ```
682
+
683
+ **Pro tip**: Combine Method 3 (wrapper script) with watch mode by setting `GW_DEV=1` in your development shell.
684
+
125
685
  ### Available Scripts
126
686
 
127
687
  ```bash
@@ -287,13 +847,32 @@ packages/gw-tool/
287
847
  │ ├── main.ts # CLI entry point and command dispatcher
288
848
  │ ├── index.ts # Public API exports
289
849
  │ ├── commands/ # Command implementations
290
- │ │ └── copy.ts # Copy command
850
+ │ │ ├── add.ts # Add command (create worktree with auto-copy)
851
+ │ │ ├── copy.ts # Sync command (sync files between worktrees)
852
+ │ │ ├── init.ts # Init command
853
+ │ │ ├── root.ts # Root command
854
+ │ │ ├── list.ts # List command (proxy)
855
+ │ │ ├── remove.ts # Remove command (proxy)
856
+ │ │ ├── move.ts # Move command (proxy)
857
+ │ │ ├── prune.ts # Prune command (proxy)
858
+ │ │ ├── lock.ts # Lock command (proxy)
859
+ │ │ ├── unlock.ts # Unlock command (proxy)
860
+ │ │ └── repair.ts # Repair command (proxy)
291
861
  │ └── lib/ # Shared utilities
292
862
  │ ├── types.ts # TypeScript type definitions
293
863
  │ ├── config.ts # Configuration management
294
- │ ├── cli.ts # CLI argument parsing
864
+ │ ├── cli.ts # CLI argument parsing & help
295
865
  │ ├── file-ops.ts # File/directory operations
296
- └── path-resolver.ts # Path resolution utilities
866
+ ├── path-resolver.ts # Path resolution utilities
867
+ │ ├── output.ts # Colored output formatting
868
+ │ └── git-proxy.ts # Git command proxy utilities
869
+ ├── npm/ # npm package files
870
+ │ ├── package.json # npm package metadata
871
+ │ ├── install.js # Binary installation script
872
+ │ └── bin/
873
+ │ └── gw.js # Binary wrapper
874
+ ├── scripts/
875
+ │ └── release.sh # Automated release script
297
876
  ├── deno.json # Deno configuration
298
877
  ├── project.json # Nx project configuration
299
878
  └── README.md # This file
@@ -301,43 +880,94 @@ packages/gw-tool/
301
880
 
302
881
  ### Adding New Commands
303
882
 
304
- To add a new command:
883
+ There are two types of commands you can add:
305
884
 
306
- 1. Create a new file in `src/commands/` (e.g., `init.ts`)
307
- 2. Implement your command function:
885
+ #### Custom Commands (like `add`, `copy`)
886
+
887
+ For commands with custom logic, follow the pattern used by existing commands:
888
+
889
+ 1. **Create a new file** in `src/commands/` (e.g., `list.ts`):
308
890
  ```typescript
309
- export async function executeInit(args: string[]): Promise<void> {
891
+ // src/commands/list.ts
892
+ export async function executeList(args: string[]): Promise<void> {
893
+ // Check for help flag
894
+ if (args.includes("--help") || args.includes("-h")) {
895
+ console.log(`Usage: gw list
896
+
897
+ List all git worktrees in the current repository.
898
+
899
+ Options:
900
+ -h, --help Show this help message
901
+ `);
902
+ Deno.exit(0);
903
+ }
904
+
310
905
  // Command implementation
906
+ // ...
311
907
  }
312
908
  ```
313
- 3. Add the command to the `COMMANDS` object in `src/main.ts`:
909
+
910
+ 2. **Import and register** the command in `src/main.ts`:
314
911
  ```typescript
912
+ import { executeList } from "./commands/list.ts";
913
+
315
914
  const COMMANDS = {
316
- copy: executeCopy,
317
- init: executeInit, // Add your new command
915
+ add: executeAdd,
916
+ sync: executeCopy,
917
+ init: executeInit,
918
+ root: executeRoot,
919
+ list: executeList, // Add your new command
318
920
  };
319
921
  ```
320
922
 
321
- ## Use Case
923
+ 3. **Update global help** in `src/lib/cli.ts`:
924
+ ```typescript
925
+ export function showGlobalHelp(): void {
926
+ console.log(`
927
+ Commands:
928
+ add Create a new worktree with optional auto-copy
929
+ sync Sync files/directories between worktrees
930
+ init Initialize gw configuration for a repository
931
+ root Get the root directory of the current git repository
932
+ list List all git worktrees in the repository
933
+ `);
934
+ }
935
+ ```
322
936
 
323
- This tool was originally created to simplify the workflow of copying secrets and environment files when creating new git worktrees. When you create a new worktree for a feature branch, you often need to copy `.env` files, credentials, and other configuration files from your main worktree to the new one. This tool automates that process.
937
+ #### Git Proxy Commands (like `list`, `remove`)
324
938
 
325
- The tool automatically detects which git repository you're working in by finding the `.git` directory, and creates a local config file (`.gw/config.json`) at the repository root on first use. This means each repository has its own configuration, and you can customize the default source worktree per repository.
939
+ For simple pass-through commands that wrap git worktree operations, use the `git-proxy` utility:
326
940
 
327
- ### Typical Workflow
941
+ 1. **Create a new file** in `src/commands/` (e.g., `list.ts`):
942
+ ```typescript
943
+ // src/commands/list.ts
944
+ import { executeGitWorktree, showProxyHelp } from '../lib/git-proxy.ts';
945
+
946
+ export async function executeList(args: string[]): Promise<void> {
947
+ if (args.includes('--help') || args.includes('-h')) {
948
+ showProxyHelp(
949
+ 'list',
950
+ 'list',
951
+ 'List all worktrees in the repository',
952
+ ['gw list', 'gw list --porcelain', 'gw list -v'],
953
+ );
954
+ Deno.exit(0);
955
+ }
956
+
957
+ await executeGitWorktree('list', args);
958
+ }
959
+ ```
328
960
 
329
- ```bash
330
- # From within any worktree of your repository
331
- # Create a new worktree
332
- git worktree add feat-new-feature
961
+ 2. **Register** in `src/main.ts` (same as above)
333
962
 
334
- # Copy secrets from main worktree to the new one
335
- # gw automatically detects your repository and uses its config
336
- gw copy feat-new-feature .env components/agents/.env components/ui/.vercel
963
+ 3. **Update global help** in `src/lib/cli.ts` (same as above)
337
964
 
338
- # Start working in the new worktree
339
- cd feat-new-feature
340
- ```
965
+ This approach requires minimal maintenance as it simply forwards all arguments to git.
966
+
967
+ **Tips**:
968
+ - Look at [src/commands/root.ts](src/commands/root.ts) for a simple custom command
969
+ - Look at [src/commands/copy.ts](src/commands/copy.ts) for a complex command with argument parsing
970
+ - Look at [src/commands/list.ts](src/commands/list.ts) for a simple proxy command
341
971
 
342
972
  ## License
343
973
 
package/install.js CHANGED
@@ -112,7 +112,13 @@ async function install() {
112
112
  }
113
113
 
114
114
  console.log('✓ Installation complete!');
115
+
116
+ // Install shell integration
117
+ console.log('\n⚙️ Setting up shell integration...');
118
+ await installShellIntegration(binaryPath);
119
+
115
120
  console.log('\nRun "gw --help" to get started.');
121
+ console.log('Tip: Restart your terminal or run "source ~/.zshrc" (or ~/.bashrc) to use "gw cd"');
116
122
  } catch (error) {
117
123
  console.error('\n✗ Installation failed:', error.message);
118
124
  console.error('\nYou can manually download the binary from:');
@@ -125,5 +131,32 @@ async function install() {
125
131
  }
126
132
  }
127
133
 
134
+ /**
135
+ * Install shell integration
136
+ */
137
+ async function installShellIntegration(binaryPath) {
138
+ const { spawn } = require('child_process');
139
+
140
+ return new Promise((resolve) => {
141
+ const child = spawn(binaryPath, ['install-shell', '--quiet'], {
142
+ stdio: 'inherit'
143
+ });
144
+
145
+ child.on('close', (code) => {
146
+ if (code === 0) {
147
+ console.log('✓ Shell integration installed!');
148
+ } else {
149
+ console.log(' (Shell integration can be installed later with: gw install-shell)');
150
+ }
151
+ resolve();
152
+ });
153
+
154
+ child.on('error', (err) => {
155
+ console.log(' (Shell integration can be installed later with: gw install-shell)');
156
+ resolve();
157
+ });
158
+ });
159
+ }
160
+
128
161
  // Run installation
129
162
  install();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gw-tools/gw",
3
- "version": "0.2.0",
3
+ "version": "0.8.0",
4
4
  "description": "A command-line tool for managing git worktrees - copy files between worktrees with ease",
5
5
  "keywords": [
6
6
  "git",
@@ -25,11 +25,13 @@
25
25
  "gw": "./bin/gw.js"
26
26
  },
27
27
  "scripts": {
28
- "postinstall": "node install.js"
28
+ "postinstall": "node install.js",
29
+ "preuninstall": "node uninstall.js"
29
30
  },
30
31
  "files": [
31
32
  "bin/",
32
33
  "install.js",
34
+ "uninstall.js",
33
35
  "README.md"
34
36
  ],
35
37
  "engines": {
package/uninstall.js ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Preuninstall script for @gw-tools/gw
5
+ * Removes shell integration before uninstalling the package
6
+ */
7
+
8
+ const { existsSync } = require('fs');
9
+ const { join } = require('path');
10
+ const { platform } = require('os');
11
+ const { spawnSync } = require('child_process');
12
+
13
+ /**
14
+ * Remove shell integration
15
+ */
16
+ function uninstall() {
17
+ const binDir = join(__dirname, 'bin');
18
+ const binaryPath = join(binDir, platform() === 'win32' ? 'gw.exe' : 'gw');
19
+
20
+ // Check if binary exists
21
+ if (!existsSync(binaryPath)) {
22
+ console.log('Binary not found, skipping shell integration removal.');
23
+ return;
24
+ }
25
+
26
+ console.log('🧹 Removing shell integration...');
27
+
28
+ try {
29
+ const result = spawnSync(binaryPath, ['install-shell', '--remove', '--quiet'], {
30
+ stdio: 'inherit',
31
+ timeout: 5000
32
+ });
33
+
34
+ if (result.error) {
35
+ console.log(' (Could not remove shell integration automatically)');
36
+ console.log(' You can manually remove it with: gw install-shell --remove');
37
+ } else if (result.status === 0) {
38
+ console.log('✓ Shell integration removed!');
39
+ } else {
40
+ console.log(' (Shell integration may not have been installed)');
41
+ }
42
+ } catch (error) {
43
+ console.log(' (Could not remove shell integration)');
44
+ }
45
+
46
+ console.log('\nTip: Restart your terminal to complete the removal.');
47
+ }
48
+
49
+ // Run uninstall
50
+ uninstall();