@gw-tools/gw 0.20.14 → 0.21.0-beta.2
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 +23 -23
- package/install.js +43 -60
- package/package.json +1 -1
- package/uninstall.js +42 -24
package/README.md
CHANGED
|
@@ -234,7 +234,7 @@ gw sync feat-existing-branch .env
|
|
|
234
234
|
- **Auto-copy files**: Configure once, automatically copy `.env`, secrets, and config files to every new worktree
|
|
235
235
|
- **Hooks support**: Run commands before/after worktree creation (install dependencies, validate setup, etc.)
|
|
236
236
|
- **Copy files between worktrees**: Easily copy secrets, environment files, and configurations from one worktree to another
|
|
237
|
-
- **Automatic shell integration**:
|
|
237
|
+
- **Automatic shell integration**: Eval-based shell integration keeps `gw cd` navigation always up-to-date
|
|
238
238
|
- **Auto-configured per repository**: Each repository gets its own local config file, automatically created on first use
|
|
239
239
|
- **Dry-run mode**: Preview what would be copied without making changes
|
|
240
240
|
- **Standalone binary**: Compiles to a single executable with no runtime dependencies
|
|
@@ -556,13 +556,13 @@ gw cd api
|
|
|
556
556
|
|
|
557
557
|
#### How It Works
|
|
558
558
|
|
|
559
|
-
The `cd` command integrates with your shell through an
|
|
559
|
+
The `cd` command integrates with your shell through an eval-based function (see [install-shell](#install-shell)). When you run `gw cd <worktree>`:
|
|
560
560
|
|
|
561
561
|
1. The command finds the matching worktree path
|
|
562
562
|
2. The shell function intercepts the call and navigates you there
|
|
563
563
|
3. All other `gw` commands pass through normally
|
|
564
564
|
|
|
565
|
-
**Note**: Shell integration is automatically
|
|
565
|
+
**Note**: Shell integration is set up automatically when you install via npm. You can also add it manually by adding `eval "$(gw install-shell)"` to your shell config.
|
|
566
566
|
|
|
567
567
|
### pr
|
|
568
568
|
|
|
@@ -722,9 +722,7 @@ If not configured, defaults to "main" branch and "merge" strategy.
|
|
|
722
722
|
|
|
723
723
|
### install-shell
|
|
724
724
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
The installation creates an integration script in `~/.gw/shell/` and adds a single line to your shell configuration to source it, keeping your shell config clean and minimal.
|
|
725
|
+
Output shell integration code for the `gw cd` command and enable real-time streaming output. The shell code is always generated from the current binary, so updates happen automatically.
|
|
728
726
|
|
|
729
727
|
Shell integration provides:
|
|
730
728
|
|
|
@@ -734,42 +732,44 @@ Shell integration provides:
|
|
|
734
732
|
- **Multi-alias support**: Install for different command names (e.g., `gw-dev` for development)
|
|
735
733
|
|
|
736
734
|
```bash
|
|
737
|
-
|
|
735
|
+
# Add to ~/.zshrc or ~/.bashrc
|
|
736
|
+
eval "$(gw install-shell)"
|
|
737
|
+
|
|
738
|
+
# Add to ~/.config/fish/config.fish
|
|
739
|
+
gw install-shell | source
|
|
738
740
|
```
|
|
739
741
|
|
|
740
742
|
#### Options
|
|
741
743
|
|
|
742
|
-
- `--name, -n NAME`:
|
|
744
|
+
- `--name, -n NAME`: Output for a different command name (default: `gw`)
|
|
743
745
|
- `--command, -c CMD`: Actual command to run (use with `--name` for aliases/dev)
|
|
744
|
-
- `--remove`: Remove shell integration
|
|
745
|
-
- `--quiet, -q`: Suppress output messages
|
|
746
|
+
- `--remove`: Remove shell integration from config files
|
|
747
|
+
- `--quiet, -q`: Suppress output messages (for `--remove`)
|
|
746
748
|
- `-h, --help`: Show help message
|
|
747
749
|
|
|
748
750
|
#### Examples
|
|
749
751
|
|
|
750
752
|
```bash
|
|
751
|
-
#
|
|
753
|
+
# Preview the shell function output
|
|
752
754
|
gw install-shell
|
|
753
755
|
|
|
754
|
-
#
|
|
755
|
-
|
|
756
|
-
gw install-shell --name gw-dev \
|
|
757
|
-
--command "deno run --allow-all ~/path/to/gw-tools/packages/gw-tool/src/main.ts"
|
|
756
|
+
# Add to your shell config (zsh/bash)
|
|
757
|
+
echo 'eval "$(gw install-shell)"' >> ~/.zshrc
|
|
758
758
|
|
|
759
|
-
#
|
|
760
|
-
gw install-shell --name gw-dev --
|
|
759
|
+
# Add for development (with Deno)
|
|
760
|
+
echo 'eval "$(gw install-shell --name gw-dev --command \"deno run --allow-all ~/path/to/main.ts\")"' >> ~/.zshrc
|
|
761
761
|
|
|
762
|
-
#
|
|
763
|
-
gw install-shell --
|
|
762
|
+
# Remove shell integration (legacy files + eval lines)
|
|
763
|
+
gw install-shell --remove
|
|
764
764
|
```
|
|
765
765
|
|
|
766
766
|
**Supported Shells:**
|
|
767
767
|
|
|
768
|
-
- **Zsh
|
|
769
|
-
- **Bash
|
|
770
|
-
- **Fish
|
|
768
|
+
- **Zsh**: `eval "$(gw install-shell)"` in `~/.zshrc`
|
|
769
|
+
- **Bash**: `eval "$(gw install-shell)"` in `~/.bashrc`
|
|
770
|
+
- **Fish**: `gw install-shell | source` in `~/.config/fish/config.fish`
|
|
771
771
|
|
|
772
|
-
The
|
|
772
|
+
The `--remove` flag cleans up both the new eval-based format and any legacy file-based installations.
|
|
773
773
|
|
|
774
774
|
### root
|
|
775
775
|
|
package/install.js
CHANGED
|
@@ -134,10 +134,10 @@ async function install() {
|
|
|
134
134
|
// Try to install shell integration, but don't fail if it errors
|
|
135
135
|
console.log('\n⚙️ Setting up shell integration...');
|
|
136
136
|
try {
|
|
137
|
-
|
|
137
|
+
installShellIntegration();
|
|
138
138
|
} catch (error) {
|
|
139
139
|
console.log(' Shell integration setup encountered an issue.');
|
|
140
|
-
console.log(' You can
|
|
140
|
+
console.log(' You can add it manually: eval \'"$(gw install-shell)"\' in your shell config');
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
console.log('\nRun "gw --help" to get started.');
|
|
@@ -154,79 +154,62 @@ async function install() {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* Install shell integration
|
|
157
|
+
* Install shell integration by appending eval line to shell config
|
|
158
158
|
*/
|
|
159
|
-
|
|
160
|
-
const {
|
|
159
|
+
function installShellIntegration() {
|
|
160
|
+
const { existsSync: fsExists, readFileSync: fsRead, writeFileSync: fsWrite, mkdirSync: fsMkdir } = require('fs');
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
const
|
|
162
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
163
|
+
const shell = process.env.SHELL || '';
|
|
164
|
+
const shellName = shell.split('/').pop() || '';
|
|
165
165
|
|
|
166
|
-
if (!
|
|
166
|
+
if (!home) {
|
|
167
167
|
console.log(' Skipping shell integration: HOME environment variable not set');
|
|
168
|
-
console.log('
|
|
168
|
+
console.log(' Add eval \'"$(gw install-shell)"\' to your shell config manually');
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
if (!
|
|
172
|
+
if (!shellName) {
|
|
173
173
|
console.log(' Skipping shell integration: SHELL environment variable not set');
|
|
174
|
-
console.log('
|
|
174
|
+
console.log(' Add eval \'"$(gw install-shell)"\' to your shell config manually');
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
let configFile;
|
|
179
|
+
let evalLine;
|
|
180
|
+
|
|
181
|
+
if (shellName === 'zsh') {
|
|
182
|
+
configFile = join(home, '.zshrc');
|
|
183
|
+
evalLine = 'eval "$(gw install-shell)"';
|
|
184
|
+
} else if (shellName === 'bash') {
|
|
185
|
+
configFile = join(home, '.bashrc');
|
|
186
|
+
evalLine = 'eval "$(gw install-shell)"';
|
|
187
|
+
} else if (shellName === 'fish') {
|
|
188
|
+
const configDir = join(home, '.config', 'fish');
|
|
189
|
+
if (!fsExists(configDir)) {
|
|
190
|
+
fsMkdir(configDir, { recursive: true });
|
|
191
|
+
}
|
|
192
|
+
configFile = join(configDir, 'config.fish');
|
|
193
|
+
evalLine = 'gw install-shell | source';
|
|
194
|
+
} else {
|
|
195
|
+
console.log(` Unsupported shell: ${shellName}`);
|
|
196
|
+
console.log(' Add eval \'"$(gw install-shell)"\' to your shell config manually');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
180
199
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// Catch synchronous spawn errors (e.g., ETXTBSY thrown immediately)
|
|
187
|
-
if (err.code === 'ETXTBSY' && retries > 0) {
|
|
188
|
-
setTimeout(() => {
|
|
189
|
-
installShellIntegration(binaryPath, retries - 1).then(resolve);
|
|
190
|
-
}, 200);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
console.log(' Shell integration setup encountered an issue.');
|
|
194
|
-
console.log(' You can install it manually later with: gw install-shell');
|
|
195
|
-
resolve();
|
|
200
|
+
// Check if already present
|
|
201
|
+
if (fsExists(configFile)) {
|
|
202
|
+
const content = fsRead(configFile, 'utf8');
|
|
203
|
+
if (content.includes('gw install-shell')) {
|
|
204
|
+
console.log('✓ Shell integration already configured!');
|
|
196
205
|
return;
|
|
197
206
|
}
|
|
207
|
+
}
|
|
198
208
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
process.stderr.write(data);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
child.on('close', (code) => {
|
|
207
|
-
if (code === 0) {
|
|
208
|
-
console.log('✓ Shell integration installed!');
|
|
209
|
-
} else {
|
|
210
|
-
console.log(' Shell integration failed with exit code:', code);
|
|
211
|
-
if (stderrOutput) {
|
|
212
|
-
console.log(' Error:', stderrOutput.trim());
|
|
213
|
-
}
|
|
214
|
-
console.log(' You can install it manually later with: gw install-shell');
|
|
215
|
-
}
|
|
216
|
-
resolve();
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
child.on('error', async (err) => {
|
|
220
|
-
// Retry on ETXTBSY (text file busy) error
|
|
221
|
-
if (err.code === 'ETXTBSY' && retries > 0) {
|
|
222
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
223
|
-
return installShellIntegration(binaryPath, retries - 1).then(resolve);
|
|
224
|
-
}
|
|
225
|
-
console.log(' Shell integration setup encountered an issue.');
|
|
226
|
-
console.log(' You can install it manually later with: gw install-shell');
|
|
227
|
-
resolve();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
209
|
+
// Append eval line
|
|
210
|
+
fsWrite(configFile, '\n' + evalLine + '\n', { flag: 'a' });
|
|
211
|
+
console.log(`✓ Shell integration added to ${configFile}`);
|
|
212
|
+
console.log(' Restart your terminal or source your shell config to activate.');
|
|
230
213
|
}
|
|
231
214
|
|
|
232
215
|
// Run installation
|
package/package.json
CHANGED
package/uninstall.js
CHANGED
|
@@ -18,47 +18,57 @@ function manualRemoval() {
|
|
|
18
18
|
const shell = process.env.SHELL || '';
|
|
19
19
|
const shellName = shell.split('/').pop() || '';
|
|
20
20
|
|
|
21
|
-
let configFile;
|
|
22
|
-
let scriptFile;
|
|
23
21
|
let removed = false;
|
|
24
22
|
|
|
23
|
+
// Remove legacy integration script files
|
|
24
|
+
const legacyFiles = [
|
|
25
|
+
join(home, '.gw', 'shell', 'integration.zsh'),
|
|
26
|
+
join(home, '.gw', 'shell', 'integration.bash'),
|
|
27
|
+
join(home, '.config', 'fish', 'functions', 'gw.fish'),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
for (const scriptFile of legacyFiles) {
|
|
31
|
+
if (existsSync(scriptFile)) {
|
|
32
|
+
try {
|
|
33
|
+
unlinkSync(scriptFile);
|
|
34
|
+
console.log(` Removed: ${scriptFile}`);
|
|
35
|
+
removed = true;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.log(` Could not remove: ${scriptFile}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Determine config files to clean up
|
|
43
|
+
const configFiles = [];
|
|
25
44
|
if (shellName === 'zsh') {
|
|
26
|
-
|
|
27
|
-
scriptFile = join(home, '.gw', 'shell', 'integration.zsh');
|
|
45
|
+
configFiles.push(join(home, '.zshrc'));
|
|
28
46
|
} else if (shellName === 'bash') {
|
|
29
|
-
|
|
30
|
-
scriptFile = join(home, '.gw', 'shell', 'integration.bash');
|
|
47
|
+
configFiles.push(join(home, '.bashrc'));
|
|
31
48
|
} else if (shellName === 'fish') {
|
|
32
|
-
|
|
33
|
-
configFile = null; // Fish doesn't need config file cleanup
|
|
49
|
+
configFiles.push(join(home, '.config', 'fish', 'config.fish'));
|
|
34
50
|
} else {
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
// Try all common config files
|
|
52
|
+
configFiles.push(join(home, '.zshrc'));
|
|
53
|
+
configFiles.push(join(home, '.bashrc'));
|
|
54
|
+
configFiles.push(join(home, '.config', 'fish', 'config.fish'));
|
|
37
55
|
}
|
|
38
56
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
unlinkSync(scriptFile);
|
|
43
|
-
console.log(` Removed: ${scriptFile}`);
|
|
44
|
-
removed = true;
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.log(` Could not remove: ${scriptFile}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
57
|
+
for (const configFile of configFiles) {
|
|
58
|
+
if (!existsSync(configFile)) continue;
|
|
49
59
|
|
|
50
|
-
// Remove source line from config file (for bash/zsh)
|
|
51
|
-
if (configFile && existsSync(configFile)) {
|
|
52
60
|
try {
|
|
53
61
|
const content = readFileSync(configFile, 'utf8');
|
|
54
62
|
const lines = content.split('\n');
|
|
55
63
|
const filtered = [];
|
|
56
64
|
let skipNext = false;
|
|
65
|
+
let fileModified = false;
|
|
57
66
|
|
|
58
67
|
for (const line of lines) {
|
|
68
|
+
// Remove old format: comment + source line
|
|
59
69
|
if (line.includes('# gw-tools shell integration')) {
|
|
60
70
|
skipNext = true;
|
|
61
|
-
|
|
71
|
+
fileModified = true;
|
|
62
72
|
continue;
|
|
63
73
|
}
|
|
64
74
|
if (skipNext && line.includes('source ~/.gw/shell/integration')) {
|
|
@@ -66,12 +76,20 @@ function manualRemoval() {
|
|
|
66
76
|
continue;
|
|
67
77
|
}
|
|
68
78
|
skipNext = false;
|
|
79
|
+
|
|
80
|
+
// Remove new eval-based format and fish source format
|
|
81
|
+
if (line.includes('gw install-shell')) {
|
|
82
|
+
fileModified = true;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
filtered.push(line);
|
|
70
87
|
}
|
|
71
88
|
|
|
72
|
-
if (
|
|
89
|
+
if (fileModified) {
|
|
73
90
|
writeFileSync(configFile, filtered.join('\n'));
|
|
74
91
|
console.log(` Updated: ${configFile}`);
|
|
92
|
+
removed = true;
|
|
75
93
|
}
|
|
76
94
|
} catch (error) {
|
|
77
95
|
console.log(` Could not update: ${configFile}`);
|