@jhorst11/wt 2.0.1 → 2.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/src/setup.js DELETED
@@ -1,267 +0,0 @@
1
- import { select, confirm } from '@inquirer/prompts';
2
- import { ExitPromptError } from '@inquirer/core';
3
- import { homedir } from 'os';
4
- import { existsSync, readFileSync, appendFileSync, writeFileSync } from 'fs';
5
- import { join } from 'path';
6
- import {
7
- showMiniLogo,
8
- success,
9
- error,
10
- warning,
11
- info,
12
- heading,
13
- spacer,
14
- colors,
15
- icons,
16
- divider,
17
- } from './ui.js';
18
-
19
- // Shell detection
20
- export function detectShell() {
21
- const shell = process.env.SHELL || '';
22
-
23
- if (shell.includes('zsh')) return 'zsh';
24
- if (shell.includes('bash')) return 'bash';
25
- if (shell.includes('fish')) return 'fish';
26
- if (process.env.FISH_VERSION) return 'fish';
27
- if (process.env.ZSH_VERSION) return 'zsh';
28
- if (process.env.BASH_VERSION) return 'bash';
29
-
30
- return 'unknown';
31
- }
32
-
33
- export function getShellConfig() {
34
- const shell = detectShell();
35
- const home = homedir();
36
-
37
- const configs = {
38
- zsh: {
39
- name: 'Zsh',
40
- rcFile: join(home, '.zshrc'),
41
- wrapper: `
42
- # wt-cli: Git worktree manager shell integration
43
- wt() {
44
- local wt_cd_file="/tmp/wt_cd_$$"
45
- rm -f "$wt_cd_file"
46
- WT_WRAPPER=1 WT_CD_FILE="$wt_cd_file" command wt "$@"
47
- local exit_code=$?
48
- if [[ -f "$wt_cd_file" ]]; then
49
- local dir=$(cat "$wt_cd_file")
50
- rm -f "$wt_cd_file"
51
- [[ -d "$dir" ]] && cd "$dir"
52
- fi
53
- return $exit_code
54
- }`,
55
- },
56
- bash: {
57
- name: 'Bash',
58
- rcFile: join(home, '.bashrc'),
59
- wrapper: `
60
- # wt-cli: Git worktree manager shell integration
61
- wt() {
62
- local wt_cd_file="/tmp/wt_cd_$$"
63
- rm -f "$wt_cd_file"
64
- WT_WRAPPER=1 WT_CD_FILE="$wt_cd_file" command wt "$@"
65
- local exit_code=$?
66
- if [[ -f "$wt_cd_file" ]]; then
67
- local dir=$(cat "$wt_cd_file")
68
- rm -f "$wt_cd_file"
69
- [[ -d "$dir" ]] && cd "$dir"
70
- fi
71
- return $exit_code
72
- }`,
73
- },
74
- fish: {
75
- name: 'Fish',
76
- rcFile: join(home, '.config/fish/config.fish'),
77
- wrapper: `
78
- # wt-cli: Git worktree manager shell integration
79
- function wt
80
- set -l wt_cd_file "/tmp/wt_cd_fish_$fish_pid"
81
- rm -f "$wt_cd_file"
82
- env WT_WRAPPER=1 WT_CD_FILE="$wt_cd_file" command wt $argv
83
- set -l exit_code $status
84
- if test -f "$wt_cd_file"
85
- set -l dir (cat "$wt_cd_file")
86
- rm -f "$wt_cd_file"
87
- test -d "$dir"; and cd "$dir"
88
- end
89
- return $exit_code
90
- end`,
91
- },
92
- };
93
-
94
- return configs[shell] || null;
95
- }
96
-
97
- export function isWrapperInstalled() {
98
- // Check if we're running through the wrapper
99
- // The wrapper would need to set this env var
100
- return process.env.WT_WRAPPER === '1';
101
- }
102
-
103
- export function checkWrapperInRcFile() {
104
- const config = getShellConfig();
105
- if (!config) return { installed: false, reason: 'unknown-shell' };
106
-
107
- if (!existsSync(config.rcFile)) {
108
- return { installed: false, reason: 'no-rc-file', rcFile: config.rcFile };
109
- }
110
-
111
- try {
112
- const content = readFileSync(config.rcFile, 'utf-8');
113
- if (content.includes('wt-cli') || content.includes('__WT_CD__')) {
114
- return { installed: true, rcFile: config.rcFile };
115
- }
116
- return { installed: false, reason: 'not-configured', rcFile: config.rcFile };
117
- } catch {
118
- return { installed: false, reason: 'read-error', rcFile: config.rcFile };
119
- }
120
- }
121
-
122
- export async function setupCommand() {
123
- showMiniLogo();
124
- heading(`${icons.sparkles} Shell Setup`);
125
-
126
- const shell = detectShell();
127
- const config = getShellConfig();
128
-
129
- if (shell === 'unknown' || !config) {
130
- warning(`Could not detect your shell type`);
131
- info(`SHELL environment variable: ${process.env.SHELL || 'not set'}`);
132
- spacer();
133
- console.log(` ${colors.muted('Please manually add the shell wrapper to your shell config.')}`);
134
- console.log(` ${colors.muted('See:')} ${colors.path('https://github.com/jhorst11/wt#shell-integration')}`);
135
- spacer();
136
- return;
137
- }
138
-
139
- success(`Detected shell: ${colors.primary(config.name)}`);
140
- info(`Config file: ${colors.path(config.rcFile)}`);
141
- spacer();
142
-
143
- const status = checkWrapperInRcFile();
144
-
145
- if (status.installed) {
146
- success(`Shell integration is already installed! ${icons.check}`);
147
- spacer();
148
- info(`If directory jumping isn't working, try restarting your terminal`);
149
- info(`or run: ${colors.primary(`source ${config.rcFile}`)}`);
150
- spacer();
151
- return;
152
- }
153
-
154
- // Not installed - offer to install
155
- divider();
156
- spacer();
157
-
158
- console.log(` ${colors.muted('To enable directory jumping (wt go, wt home), we need to')}`);
159
- console.log(` ${colors.muted('add a small shell function to your')} ${colors.path(config.rcFile)}`);
160
- spacer();
161
-
162
- try {
163
- const action = await select({
164
- message: 'How would you like to proceed?',
165
- choices: [
166
- {
167
- name: `${icons.sparkles} Auto-install (append to ${config.rcFile})`,
168
- value: 'auto',
169
- description: 'Recommended - automatically adds the integration',
170
- },
171
- {
172
- name: `${icons.info} Show me the code to copy`,
173
- value: 'show',
174
- description: 'Display the code so you can add it manually',
175
- },
176
- {
177
- name: `${colors.muted(icons.cross + ' Skip for now')}`,
178
- value: 'skip',
179
- },
180
- ],
181
- theme: { prefix: icons.tree },
182
- });
183
-
184
- if (action === 'auto') {
185
- await autoInstall(config);
186
- } else if (action === 'show') {
187
- showManualInstructions(config);
188
- } else {
189
- info('Skipped. You can run `wt setup` anytime to configure shell integration.');
190
- spacer();
191
- }
192
- } catch (err) {
193
- if (err instanceof ExitPromptError) {
194
- spacer();
195
- info('Cancelled');
196
- spacer();
197
- return;
198
- }
199
- throw err;
200
- }
201
- }
202
-
203
- async function autoInstall(config) {
204
- spacer();
205
-
206
- try {
207
- appendFileSync(config.rcFile, '\n' + config.wrapper + '\n');
208
- success(`Added shell integration to ${colors.path(config.rcFile)}`);
209
- spacer();
210
-
211
- console.log(` ${icons.rocket} ${colors.primary('Almost done!')} Run this to activate:`);
212
- spacer();
213
- console.log(` ${colors.secondary(`source ${config.rcFile}`)}`);
214
- spacer();
215
- console.log(` ${colors.muted('Or just restart your terminal.')}`);
216
- spacer();
217
- } catch (err) {
218
- error(`Failed to write to ${config.rcFile}`);
219
- error(err.message);
220
- spacer();
221
- showManualInstructions(config);
222
- }
223
- }
224
-
225
- function showManualInstructions(config) {
226
- spacer();
227
- console.log(` ${colors.muted('Add this to')} ${colors.path(config.rcFile)}${colors.muted(':')}`);
228
- spacer();
229
- divider();
230
- console.log(colors.secondary(config.wrapper));
231
- divider();
232
- spacer();
233
- console.log(` ${colors.muted('Then run:')} ${colors.primary(`source ${config.rcFile}`)}`);
234
- spacer();
235
- }
236
-
237
- // Helper to show a gentle nudge if wrapper isn't set up
238
- export function showCdHint(path) {
239
- // Check if we're running through the shell wrapper with a cd file
240
- const cdFile = process.env.WT_CD_FILE;
241
- if (cdFile && isWrapperInstalled()) {
242
- // Write path to temp file for shell wrapper to read
243
- try {
244
- writeFileSync(cdFile, path);
245
- } catch {
246
- // Fall through to show manual instructions
247
- }
248
- return;
249
- }
250
-
251
- // Fall back to checking rc file
252
- const status = checkWrapperInRcFile();
253
-
254
- if (status.installed) {
255
- // Wrapper is in rc file but not active - show path
256
- spacer();
257
- console.log(` ${icons.rocket} ${colors.muted('Switching to:')} ${colors.path(path)}`);
258
- spacer();
259
- } else {
260
- // No wrapper - show a friendly message instead
261
- spacer();
262
- console.log(` ${icons.rocket} ${colors.muted('Run:')} ${colors.primary(`cd "${path}"`)}`);
263
- spacer();
264
- console.log(` ${colors.muted(`Tip: Run`)} ${colors.secondary('wt setup')} ${colors.muted('to enable auto-navigation')}`);
265
- spacer();
266
- }
267
- }
package/src/ui.js DELETED
@@ -1,147 +0,0 @@
1
- import chalk from 'chalk';
2
- import gradient from 'gradient-string';
3
- import figures from 'figures';
4
- import { createRequire } from 'module';
5
-
6
- const require = createRequire(import.meta.url);
7
- const { version } = require('../package.json');
8
-
9
- // Custom gradient for the logo
10
- const wtGradient = gradient(['#00d4ff', '#7c3aed', '#f472b6']);
11
- const successGradient = gradient(['#10b981', '#34d399']);
12
- const warningGradient = gradient(['#f59e0b', '#fbbf24']);
13
-
14
- export const icons = {
15
- tree: 'đŸŒŗ',
16
- branch: 'đŸŒŋ',
17
- rocket: '🚀',
18
- sparkles: '✨',
19
- folder: '📁',
20
- trash: 'đŸ—‘ī¸',
21
- home: '🏠',
22
- check: figures.tick,
23
- cross: figures.cross,
24
- pointer: figures.pointer,
25
- arrowRight: figures.arrowRight,
26
- bullet: figures.bullet,
27
- star: '⭐',
28
- git: 'ķ°Šĸ',
29
- plus: '➕',
30
- warning: 'âš ī¸',
31
- info: 'â„šī¸',
32
- remote: 'â˜ī¸',
33
- local: 'đŸ’ģ',
34
- };
35
-
36
- export const colors = {
37
- primary: chalk.hex('#7c3aed'),
38
- secondary: chalk.hex('#00d4ff'),
39
- success: chalk.hex('#10b981'),
40
- warning: chalk.hex('#f59e0b'),
41
- error: chalk.hex('#ef4444'),
42
- muted: chalk.gray,
43
- highlight: chalk.hex('#f472b6'),
44
- branch: chalk.hex('#34d399'),
45
- path: chalk.hex('#60a5fa'),
46
- };
47
-
48
- export function showLogo() {
49
- const logo = `
50
- ${wtGradient('â•Ļ â•Ļ╔═╗â•Ļ═╗â•Ļ╔═╔â•Ļ╗â•Ļ═╗╔═╗╔═╗')}
51
- ${wtGradient('║║║║ ║╠â•Ļ╝╠╩╗ ║ ╠â•Ļâ•â•‘â•Ŗ â•‘â•Ŗ ')}
52
- ${wtGradient('╚╩╝╚═╝╩╚═╩ ╩ ╩ ╩╚═╚═╝╚═╝')}
53
- ${chalk.gray(' Git Worktree Manager')}
54
- `;
55
- console.log(logo);
56
- }
57
-
58
- export function showMiniLogo() {
59
- console.log(`\n ${icons.tree} ${wtGradient('worktree')} ${colors.muted(`v${version}`)}\n`);
60
- }
61
-
62
- export function success(message) {
63
- console.log(` ${colors.success(icons.check)} ${message}`);
64
- }
65
-
66
- export function error(message) {
67
- console.log(` ${colors.error(icons.cross)} ${message}`);
68
- }
69
-
70
- export function warning(message) {
71
- console.log(` ${colors.warning(icons.warning)} ${message}`);
72
- }
73
-
74
- export function info(message) {
75
- console.log(` ${colors.secondary(icons.info)} ${message}`);
76
- }
77
-
78
- export function heading(text) {
79
- console.log(`\n ${colors.primary.bold(text)}\n`);
80
- }
81
-
82
- export function subheading(text) {
83
- console.log(` ${colors.muted(text)}`);
84
- }
85
-
86
- export function listItem(text, indent = 2) {
87
- const spaces = ' '.repeat(indent);
88
- console.log(`${spaces}${colors.secondary(icons.bullet)} ${text}`);
89
- }
90
-
91
- export function branchItem(name, isCurrent = false, isRemote = false) {
92
- const icon = isRemote ? icons.remote : icons.local;
93
- const prefix = isCurrent ? colors.success(icons.pointer) : ' ';
94
- const branchName = isCurrent ? colors.success.bold(name) : colors.branch(name);
95
- const typeLabel = isRemote ? colors.muted(' (remote)') : '';
96
- console.log(` ${prefix} ${icon} ${branchName}${typeLabel}`);
97
- }
98
-
99
- export function worktreeItem(name, path, isCurrent = false) {
100
- const prefix = isCurrent ? colors.success(icons.pointer) : ' ';
101
- const nameDisplay = isCurrent ? colors.success.bold(name) : colors.highlight(name);
102
- console.log(` ${prefix} ${icons.folder} ${nameDisplay}`);
103
- console.log(` ${colors.muted(path)}`);
104
- }
105
-
106
- export function divider() {
107
- console.log(colors.muted(' ─'.repeat(20)));
108
- }
109
-
110
- export function spacer() {
111
- console.log('');
112
- }
113
-
114
- export function formatBranchChoice(branch, type = 'local') {
115
- const icon = type === 'remote' ? icons.remote : icons.local;
116
- const typeLabel = type === 'remote' ? chalk.dim(' (remote)') : '';
117
- return `${icon} ${branch}${typeLabel}`;
118
- }
119
-
120
- export function formatWorktreeChoice(wt) {
121
- return `${icons.folder} ${colors.highlight(wt.name)} ${colors.muted(`→ ${wt.branch}`)}`;
122
- }
123
-
124
- export function showHelp() {
125
- showLogo();
126
-
127
- console.log(colors.primary.bold(' Commands:\n'));
128
-
129
- const commands = [
130
- ['wt', 'Interactive menu to manage worktrees'],
131
- ['wt new', 'Create a new worktree interactively'],
132
- ['wt list|ls', 'List all worktrees for current repo'],
133
- ['wt go [name]', 'Jump to a worktree (interactive if no name)'],
134
- ['wt merge', 'Merge a worktree branch into another branch'],
135
- ['wt remove|rm', 'Remove a worktree interactively'],
136
- ['wt home', 'Jump back to the main repository'],
137
- ['wt setup', 'Configure shell integration for auto-navigation'],
138
- ];
139
-
140
- commands.forEach(([cmd, desc]) => {
141
- console.log(` ${colors.secondary(cmd.padEnd(18))} ${colors.muted(desc)}`);
142
- });
143
-
144
- spacer();
145
- console.log(colors.muted(' Run any command without arguments for interactive mode'));
146
- spacer();
147
- }