@gw-tools/gw 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +339 -0
  2. package/bin/gw.js +37 -0
  3. package/install.js +129 -0
  4. package/package.json +47 -0
package/README.md ADDED
@@ -0,0 +1,339 @@
1
+ # gw - Git Worktree Tools
2
+
3
+ A command-line tool for managing git worktrees, built with Deno.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install
9
+ npm install -g @gw-tools/gw
10
+
11
+ # Create a new worktree
12
+ git worktree add feat-new-feature
13
+
14
+ # Copy secrets from main to the new worktree
15
+ gw copy feat-new-feature .env
16
+
17
+ # Done! Your new worktree has all the secrets it needs
18
+ cd feat-new-feature
19
+ ```
20
+
21
+ ## Features
22
+
23
+ - **Copy files between worktrees**: Easily copy secrets, environment files, and configurations from one worktree to another
24
+ - **Multi-command architecture**: Extensible framework for adding new worktree management commands
25
+ - **Auto-configured per repository**: Each repository gets its own local config file, automatically created on first use
26
+ - **Dry-run mode**: Preview what would be copied without making changes
27
+ - **Standalone binary**: Compiles to a single executable with no runtime dependencies
28
+
29
+ ## Installation
30
+
31
+ ### Via npm (Recommended)
32
+
33
+ Install globally using npm:
34
+
35
+ ```bash
36
+ npm install -g @gw-tools/gw
37
+ ```
38
+
39
+ This will download the appropriate binary for your platform (macOS, Linux, or Windows) and make the `gw` command available globally.
40
+
41
+ **Supported Platforms:**
42
+ - macOS (Intel & Apple Silicon)
43
+ - Linux (x64 & ARM64)
44
+ - Windows (x64)
45
+
46
+ ### Build from source
47
+
48
+ If you prefer to build from source:
49
+
50
+ ```bash
51
+ # Clone the repository
52
+ git clone https://github.com/mthines/gw-tools.git
53
+ cd gw-tools
54
+
55
+ # Build the project
56
+ nx run gw-tool:compile
57
+
58
+ # The binary will be created at dist/packages/gw-tool/gw
59
+ # You can copy it to a directory in your PATH for global access
60
+ cp dist/packages/gw-tool/gw /usr/local/bin/gw
61
+ ```
62
+
63
+ ## Configuration
64
+
65
+ 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.
66
+
67
+ ### Example Configuration
68
+
69
+ ```json
70
+ {
71
+ "defaultSource": "main"
72
+ }
73
+ ```
74
+
75
+ ### Configuration Options
76
+
77
+ - **defaultSource**: Default source worktree name (optional, defaults to "main")
78
+
79
+ ## Commands
80
+
81
+ ### copy
82
+
83
+ Copy files and directories between worktrees, preserving directory structure.
84
+
85
+ ```bash
86
+ gw copy [options] <target-worktree> <files...>
87
+ ```
88
+
89
+ #### Arguments
90
+
91
+ - `<target-worktree>`: Name or full path of the target worktree
92
+ - `<files...>`: One or more files or directories to copy (paths relative to worktree root)
93
+
94
+ #### Options
95
+
96
+ - `--from <source>`: Source worktree name (default: from config or "main")
97
+ - `-n, --dry-run`: Show what would be copied without actually copying
98
+ - `-h, --help`: Show help message
99
+
100
+ #### Examples
101
+
102
+ ```bash
103
+ # Copy .env file from main to feat-branch
104
+ gw copy feat-branch .env
105
+
106
+ # Copy multiple files
107
+ gw copy feat-branch .env components/agents/.env components/agents/agents.yaml
108
+
109
+ # Copy entire directory
110
+ gw copy feat-branch components/ui/.vercel
111
+
112
+ # Use custom source worktree
113
+ gw copy --from develop feat-branch .env
114
+
115
+ # Dry run to preview changes
116
+ gw copy --dry-run feat-branch .env
117
+
118
+ # Use absolute path as target
119
+ gw copy /full/path/to/repo/feat-branch .env
120
+ ```
121
+
122
+ ## Development
123
+
124
+ ### Available Scripts
125
+
126
+ ```bash
127
+ # Run the tool in development mode
128
+ nx run gw-tool:run -- <args>
129
+
130
+ # Watch mode for development
131
+ nx run gw-tool:dev
132
+
133
+ # Type check
134
+ nx run gw-tool:check
135
+
136
+ # Lint
137
+ nx run gw-tool:lint
138
+
139
+ # Format code
140
+ nx run gw-tool:fmt
141
+
142
+ # Compile to binary (current platform only)
143
+ nx run gw-tool:compile
144
+
145
+ # Compile binaries for all platforms
146
+ nx run gw-tool:compile-all
147
+
148
+ # Prepare npm package
149
+ nx run gw-tool:npm-pack
150
+
151
+ # Automated release (version, build, GitHub release, npm publish)
152
+ nx run gw-tool:release
153
+
154
+ # Publish to JSR (optional, separate ecosystem)
155
+ nx run gw-tool:publish-jsr
156
+
157
+ # Run tests
158
+ nx run gw-tool:test
159
+ ```
160
+
161
+ ### Publishing
162
+
163
+ This tool uses **automated semantic versioning** based on conventional commits. The version is automatically determined from your commit messages.
164
+
165
+ #### Automated Release (Recommended)
166
+
167
+ The simplest way to publish is using the automated release process:
168
+
169
+ ```bash
170
+ # Make sure you're on main/master branch with all changes pushed
171
+ nx run gw-tool:release
172
+ ```
173
+
174
+ This single command will:
175
+ 1. Analyze your commits since the last release
176
+ 2. Automatically determine version bump (major/minor/patch)
177
+ 3. Update npm/package.json with the new version
178
+ 4. Create a git commit and tag
179
+ 5. Push to GitHub
180
+ 6. Build binaries for all platforms
181
+ 7. Create a GitHub release with binaries attached
182
+ 8. Publish to npm
183
+
184
+ **Conventional Commit Format:**
185
+
186
+ Use these commit prefixes to control versioning:
187
+
188
+ - `feat:` - New feature (bumps **MINOR** version: 1.0.0 → 1.1.0)
189
+ - `fix:` - Bug fix (bumps **PATCH** version: 1.0.0 → 1.0.1)
190
+ - `BREAKING CHANGE:` or `feat!:` or `fix!:` - Breaking change (bumps **MAJOR** version: 1.0.0 → 2.0.0)
191
+ - `chore:`, `docs:`, `style:`, `refactor:`, `test:` - No version bump
192
+
193
+ **Examples:**
194
+ ```bash
195
+ git commit -m "feat: add dry-run mode" # 1.0.0 → 1.1.0
196
+ git commit -m "fix: correct path resolution" # 1.0.0 → 1.0.1
197
+ git commit -m "feat!: redesign config structure" # 1.0.0 → 2.0.0
198
+ git commit -m "docs: update README" # no version bump
199
+ ```
200
+
201
+ #### Manual Publishing
202
+
203
+ If you prefer manual control or need to debug the release process:
204
+
205
+ ```bash
206
+ # 1. Update version
207
+ cd packages/gw-tool/npm
208
+ npm version 1.0.0
209
+ cd ../../..
210
+
211
+ # 2. Commit and push
212
+ git add packages/gw-tool/npm/package.json
213
+ git commit -m "chore: bump version to 1.0.0"
214
+ git push
215
+
216
+ # 3. Build binaries
217
+ nx run gw-tool:compile-all
218
+ nx run gw-tool:npm-pack
219
+
220
+ # 4. Create GitHub release
221
+ gh release create "v1.0.0" \
222
+ --title "v1.0.0" \
223
+ --notes "Release notes" \
224
+ dist/packages/gw-tool/binaries/*
225
+
226
+ # 5. Publish to npm
227
+ cd dist/packages/gw-tool/npm
228
+ npm publish --access public
229
+ ```
230
+
231
+ #### Publishing to JSR (Optional)
232
+
233
+ For users who prefer Deno's native package manager.
234
+
235
+ 1. **Add JSR configuration to `deno.json`:**
236
+ ```json
237
+ {
238
+ "name": "@your-scope/gw",
239
+ "version": "1.0.0",
240
+ "exports": "./src/main.ts"
241
+ }
242
+ ```
243
+
244
+ 2. **Publish:**
245
+ ```bash
246
+ nx run gw-tool:publish-jsr
247
+ ```
248
+
249
+ #### Version Management
250
+
251
+ **Automated Approach (Recommended):**
252
+
253
+ Use conventional commits and let the system determine the version:
254
+
255
+ ```bash
256
+ # Make changes
257
+ git add .
258
+ git commit -m "feat: add new awesome feature"
259
+
260
+ # When ready to release
261
+ nx run gw-tool:release
262
+ ```
263
+
264
+ The version is automatically determined from your commits:
265
+ - `feat:` → minor version bump (1.0.0 → 1.1.0)
266
+ - `fix:` → patch version bump (1.0.0 → 1.0.1)
267
+ - `feat!:` or `BREAKING CHANGE:` → major version bump (1.0.0 → 2.0.0)
268
+
269
+ **Manual Approach:**
270
+
271
+ If you prefer manual control:
272
+ 1. Update `packages/gw-tool/npm/package.json` version
273
+ 2. Update `packages/gw-tool/deno.json` version (if using JSR)
274
+ 3. Commit and push changes
275
+ 4. Build, create release, and publish manually
276
+
277
+ ### Project Structure
278
+
279
+ ```
280
+ packages/gw-tool/
281
+ ├── src/
282
+ │ ├── main.ts # CLI entry point and command dispatcher
283
+ │ ├── index.ts # Public API exports
284
+ │ ├── commands/ # Command implementations
285
+ │ │ └── copy.ts # Copy command
286
+ │ └── lib/ # Shared utilities
287
+ │ ├── types.ts # TypeScript type definitions
288
+ │ ├── config.ts # Configuration management
289
+ │ ├── cli.ts # CLI argument parsing
290
+ │ ├── file-ops.ts # File/directory operations
291
+ │ └── path-resolver.ts # Path resolution utilities
292
+ ├── deno.json # Deno configuration
293
+ ├── project.json # Nx project configuration
294
+ └── README.md # This file
295
+ ```
296
+
297
+ ### Adding New Commands
298
+
299
+ To add a new command:
300
+
301
+ 1. Create a new file in `src/commands/` (e.g., `init.ts`)
302
+ 2. Implement your command function:
303
+ ```typescript
304
+ export async function executeInit(args: string[]): Promise<void> {
305
+ // Command implementation
306
+ }
307
+ ```
308
+ 3. Add the command to the `COMMANDS` object in `src/main.ts`:
309
+ ```typescript
310
+ const COMMANDS = {
311
+ copy: executeCopy,
312
+ init: executeInit, // Add your new command
313
+ };
314
+ ```
315
+
316
+ ## Use Case
317
+
318
+ 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.
319
+
320
+ 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.
321
+
322
+ ### Typical Workflow
323
+
324
+ ```bash
325
+ # From within any worktree of your repository
326
+ # Create a new worktree
327
+ git worktree add feat-new-feature
328
+
329
+ # Copy secrets from main worktree to the new one
330
+ # gw automatically detects your repository and uses its config
331
+ gw copy feat-new-feature .env components/agents/.env components/ui/.vercel
332
+
333
+ # Start working in the new worktree
334
+ cd feat-new-feature
335
+ ```
336
+
337
+ ## License
338
+
339
+ See the workspace root for license information.
package/bin/gw.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wrapper script for the gw binary
5
+ * This script launches the appropriate binary for the current platform
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const { join } = require('path');
10
+ const { platform } = require('os');
11
+
12
+ // Path to the binary
13
+ const binaryName = platform() === 'win32' ? 'gw.exe' : 'gw';
14
+ const binaryPath = join(__dirname, binaryName);
15
+
16
+ // Spawn the binary with all arguments
17
+ const child = spawn(binaryPath, process.argv.slice(2), {
18
+ stdio: 'inherit',
19
+ windowsHide: false,
20
+ });
21
+
22
+ // Forward exit code
23
+ child.on('exit', (code, signal) => {
24
+ if (signal) {
25
+ process.kill(process.pid, signal);
26
+ } else {
27
+ process.exit(code || 0);
28
+ }
29
+ });
30
+
31
+ // Handle errors
32
+ child.on('error', (err) => {
33
+ console.error('Failed to start gw:', err.message);
34
+ console.error('\nThe binary may not be installed correctly.');
35
+ console.error('Try reinstalling: npm install -g @gw-tools/gw');
36
+ process.exit(1);
37
+ });
package/install.js ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Postinstall script for @gw-tools/gw
5
+ * Downloads the appropriate binary for the current platform
6
+ */
7
+
8
+ const { existsSync, mkdirSync, chmodSync } = require('fs');
9
+ const { join } = require('path');
10
+ const { arch, platform } = require('os');
11
+ const https = require('https');
12
+ const { createWriteStream } = require('fs');
13
+
14
+ // Package version - this will be updated by the build process
15
+ const VERSION = require('./package.json').version;
16
+
17
+ // GitHub repository details
18
+ const REPO_OWNER = 'mthines';
19
+ const REPO_NAME = 'gw-tools';
20
+
21
+ /**
22
+ * Get the binary name for the current platform
23
+ */
24
+ function getBinaryName() {
25
+ const platformMap = {
26
+ darwin: 'macos',
27
+ linux: 'linux',
28
+ win32: 'windows',
29
+ };
30
+
31
+ const archMap = {
32
+ x64: 'x64',
33
+ arm64: 'arm64',
34
+ };
35
+
36
+ const os = platformMap[platform()];
37
+ const cpu = archMap[arch()];
38
+
39
+ if (!os || !cpu) {
40
+ console.error(
41
+ `Unsupported platform: ${platform()}-${arch()}\n` +
42
+ 'Supported platforms: macOS (x64, arm64), Linux (x64, arm64), Windows (x64, arm64)'
43
+ );
44
+ process.exit(1);
45
+ }
46
+
47
+ const extension = platform() === 'win32' ? '.exe' : '';
48
+ return `gw-${os}-${cpu}${extension}`;
49
+ }
50
+
51
+ /**
52
+ * Download file from URL
53
+ */
54
+ function download(url, dest) {
55
+ return new Promise((resolve, reject) => {
56
+ const file = createWriteStream(dest);
57
+
58
+ https.get(url, { headers: { 'User-Agent': 'gw-npm-installer' } }, (response) => {
59
+ // Handle redirects
60
+ if (response.statusCode === 302 || response.statusCode === 301) {
61
+ return download(response.headers.location, dest).then(resolve).catch(reject);
62
+ }
63
+
64
+ if (response.statusCode !== 200) {
65
+ reject(new Error(`Failed to download: ${response.statusCode} ${response.statusMessage}`));
66
+ return;
67
+ }
68
+
69
+ response.pipe(file);
70
+
71
+ file.on('finish', () => {
72
+ file.close();
73
+ resolve();
74
+ });
75
+ }).on('error', (err) => {
76
+ reject(err);
77
+ });
78
+
79
+ file.on('error', (err) => {
80
+ reject(err);
81
+ });
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Main installation function
87
+ */
88
+ async function install() {
89
+ const binaryName = getBinaryName();
90
+ const binDir = join(__dirname, 'bin');
91
+ const binaryPath = join(binDir, platform() === 'win32' ? 'gw.exe' : 'gw');
92
+
93
+ // Create bin directory if it doesn't exist
94
+ if (!existsSync(binDir)) {
95
+ mkdirSync(binDir, { recursive: true });
96
+ }
97
+
98
+ console.log(`Installing @gw-tools/gw v${VERSION}...`);
99
+ console.log(`Platform: ${platform()}-${arch()}`);
100
+ console.log(`Binary: ${binaryName}`);
101
+
102
+ // Download URL for the binary from GitHub releases
103
+ const downloadUrl = `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}/${binaryName}`;
104
+
105
+ try {
106
+ console.log(`Downloading from: ${downloadUrl}`);
107
+ await download(downloadUrl, binaryPath);
108
+
109
+ // Make binary executable on Unix-like systems
110
+ if (platform() !== 'win32') {
111
+ chmodSync(binaryPath, 0o755);
112
+ }
113
+
114
+ console.log('✓ Installation complete!');
115
+ console.log('\nRun "gw --help" to get started.');
116
+ } catch (error) {
117
+ console.error('\n✗ Installation failed:', error.message);
118
+ console.error('\nYou can manually download the binary from:');
119
+ console.error(` ${downloadUrl}`);
120
+ console.error('\nOr build from source:');
121
+ console.error(' git clone https://github.com/mthines/gw-tools.git');
122
+ console.error(' cd gw-tools');
123
+ console.error(' nx run gw:compile');
124
+ process.exit(1);
125
+ }
126
+ }
127
+
128
+ // Run installation
129
+ install();
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@gw-tools/gw",
3
+ "version": "0.1.1",
4
+ "description": "A command-line tool for managing git worktrees - copy files between worktrees with ease",
5
+ "keywords": [
6
+ "git",
7
+ "worktree",
8
+ "cli",
9
+ "developer-tools",
10
+ "secrets",
11
+ "env-files"
12
+ ],
13
+ "homepage": "https://github.com/mthines/gw-tools#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/mthines/gw-tools/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/mthines/gw-tools.git",
20
+ "directory": "packages/gw-tool"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Michael Thines",
24
+ "bin": {
25
+ "gw": "./bin/gw.js"
26
+ },
27
+ "scripts": {
28
+ "postinstall": "node install.js"
29
+ },
30
+ "files": [
31
+ "bin/",
32
+ "install.js",
33
+ "README.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=14.0.0"
37
+ },
38
+ "os": [
39
+ "darwin",
40
+ "linux",
41
+ "win32"
42
+ ],
43
+ "cpu": [
44
+ "x64",
45
+ "arm64"
46
+ ]
47
+ }