@jasonfutch/worktree-manager 1.0.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/LICENSE +21 -0
- package/README.md +186 -0
- package/dist/constants.d.ts +152 -0
- package/dist/constants.js +148 -0
- package/dist/errors.d.ts +57 -0
- package/dist/errors.js +117 -0
- package/dist/git/worktree.d.ts +57 -0
- package/dist/git/worktree.js +272 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +336 -0
- package/dist/tui/app.d.ts +39 -0
- package/dist/tui/app.js +842 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.js +4 -0
- package/dist/utils/checks.d.ts +12 -0
- package/dist/utils/checks.js +109 -0
- package/dist/utils/helpers.d.ts +11 -0
- package/dist/utils/helpers.js +20 -0
- package/dist/utils/launch.d.ts +17 -0
- package/dist/utils/launch.js +223 -0
- package/dist/utils/shell.d.ts +28 -0
- package/dist/utils/shell.js +94 -0
- package/dist/version.d.ts +6 -0
- package/dist/version.js +11 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jason Futch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Worktree Manager TUI/CLI
|
|
2
|
+
|
|
3
|
+
A terminal app for managing git worktrees with AI assistance.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **TUI Interface** - Full terminal UI built with blessed
|
|
8
|
+
- **Git Worktree Management** - Create, list, and remove worktrees
|
|
9
|
+
- **IDE Integration** - Open worktrees in VS Code, Cursor, Zed, and more
|
|
10
|
+
- **AI Integration** - Launch Claude, Gemini, or Codex in any worktree
|
|
11
|
+
- **Parallel Development** - Work on multiple features simultaneously
|
|
12
|
+
- **Auto-Update Notifications** - Get notified when a new version is available
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Node.js >= 18
|
|
17
|
+
- Git
|
|
18
|
+
- Optional: VS Code, Cursor, Zed, Claude CLI
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g @jasonfutch/worktree-manager
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Interactive TUI Mode
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Launch TUI in current directory
|
|
32
|
+
wtm
|
|
33
|
+
|
|
34
|
+
# Launch TUI for a specific repo
|
|
35
|
+
wtm /path/to/repo
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Keybindings
|
|
39
|
+
|
|
40
|
+
| Key | Action |
|
|
41
|
+
| ------- | ------------------------- |
|
|
42
|
+
| `↑/k` | Move up |
|
|
43
|
+
| `↓/j` | Move down |
|
|
44
|
+
| `Enter` | Select/Details |
|
|
45
|
+
| `n` | Create new worktree |
|
|
46
|
+
| `d` | Delete worktree |
|
|
47
|
+
| `e` | Open in editor (selector) |
|
|
48
|
+
| `t` | Open terminal |
|
|
49
|
+
| `a` | Launch AI tool (selector) |
|
|
50
|
+
| `r` | Refresh |
|
|
51
|
+
| `?` | Help |
|
|
52
|
+
| `q` | Quit |
|
|
53
|
+
|
|
54
|
+
### CLI Commands
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# List all worktrees
|
|
58
|
+
wtm list
|
|
59
|
+
wtm list /path/to/repo
|
|
60
|
+
|
|
61
|
+
# Create a new worktree
|
|
62
|
+
wtm create feature/my-feature
|
|
63
|
+
wtm create feature/my-feature -b main
|
|
64
|
+
wtm create feature/my-feature -p /custom/path
|
|
65
|
+
|
|
66
|
+
# Remove a worktree
|
|
67
|
+
wtm remove feature/my-feature
|
|
68
|
+
wtm remove feature/my-feature --force
|
|
69
|
+
|
|
70
|
+
# Open worktree in editor
|
|
71
|
+
wtm open feature/my-feature
|
|
72
|
+
wtm open main -e cursor
|
|
73
|
+
# Editors: code, cursor, zed, webstorm, subl, nvim
|
|
74
|
+
|
|
75
|
+
# Open terminal in worktree
|
|
76
|
+
wtm terminal feature/my-feature
|
|
77
|
+
wtm term main
|
|
78
|
+
|
|
79
|
+
# Launch AI tool in worktree
|
|
80
|
+
wtm ai feature/my-feature
|
|
81
|
+
wtm ai main -t gemini
|
|
82
|
+
# Tools: claude, gemini, codex
|
|
83
|
+
|
|
84
|
+
# Update to latest version
|
|
85
|
+
wtm update
|
|
86
|
+
|
|
87
|
+
# Show detailed help
|
|
88
|
+
wtm help
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## How It Works
|
|
92
|
+
|
|
93
|
+
1. **Worktrees** - Uses `git worktree` to create isolated working directories for each branch
|
|
94
|
+
2. **Parallel Development** - Each worktree is independent, allowing you to run different AI coding sessions
|
|
95
|
+
3. **IDE Integration** - Opens editors in the worktree directory so your AI assistant has the right context
|
|
96
|
+
4. **Terminal Sessions** - Opens new terminal windows/tabs in the worktree directory
|
|
97
|
+
|
|
98
|
+
## Updating
|
|
99
|
+
|
|
100
|
+
The CLI automatically checks for updates once per day and notifies you when a new version is available:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
╭─────────────────────────────────────────────────╮
|
|
104
|
+
│ │
|
|
105
|
+
│ Update available 1.0.0 → 1.1.0 │
|
|
106
|
+
│ Run npm i -g @jasonfutch/worktree-manager │
|
|
107
|
+
│ │
|
|
108
|
+
╰─────────────────────────────────────────────────╯
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
You can also manually update at any time:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
wtm update
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Screenshots
|
|
118
|
+
|
|
119
|
+
### Main Interface
|
|
120
|
+
|
|
121
|
+

|
|
122
|
+
|
|
123
|
+
### Create New Worktree
|
|
124
|
+
|
|
125
|
+

|
|
126
|
+
|
|
127
|
+
### Open In Editor
|
|
128
|
+
|
|
129
|
+

|
|
130
|
+
|
|
131
|
+
### Open In AI Tool
|
|
132
|
+
|
|
133
|
+

|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
### Installation from Source
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/jasonfutch/worktree-manager
|
|
143
|
+
cd worktree-manager
|
|
144
|
+
npm install
|
|
145
|
+
npm run build
|
|
146
|
+
|
|
147
|
+
# Link globally for testing
|
|
148
|
+
npm link
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Commands
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm run dev # Run in development mode
|
|
155
|
+
npm run build # Build TypeScript
|
|
156
|
+
npm run clean # Clean build artifacts
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Architecture
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
worktree-manager/
|
|
163
|
+
├── src/
|
|
164
|
+
│ ├── index.ts # CLI entry point
|
|
165
|
+
│ ├── types.ts # TypeScript types
|
|
166
|
+
│ ├── errors.ts # Custom error classes
|
|
167
|
+
│ ├── constants.ts # Application constants
|
|
168
|
+
│ ├── version.ts # Version from package.json
|
|
169
|
+
│ ├── git/
|
|
170
|
+
│ │ └── worktree.ts # Git worktree operations
|
|
171
|
+
│ ├── tui/
|
|
172
|
+
│ │ └── app.ts # Blessed TUI application
|
|
173
|
+
│ └── utils/
|
|
174
|
+
│ ├── helpers.ts # Utility functions
|
|
175
|
+
│ ├── shell.ts # Shell escaping utilities
|
|
176
|
+
│ ├── launch.ts # Editor/terminal launchers
|
|
177
|
+
│ └── checks.ts # Startup validation
|
|
178
|
+
├── dist/ # Compiled output
|
|
179
|
+
├── package.json
|
|
180
|
+
├── tsconfig.json
|
|
181
|
+
└── README.md
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used throughout the worktree manager application
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* UI-related constants
|
|
6
|
+
*/
|
|
7
|
+
export declare const UI: {
|
|
8
|
+
/** Maximum length for branch names in list display */
|
|
9
|
+
readonly BRANCH_TRUNCATE_LENGTH: 30;
|
|
10
|
+
/** Height of the help modal in lines */
|
|
11
|
+
readonly HELP_MODAL_HEIGHT: 26;
|
|
12
|
+
/** Height of the create worktree form in lines */
|
|
13
|
+
readonly CREATE_FORM_HEIGHT: 20;
|
|
14
|
+
/** Width of modal dialogs */
|
|
15
|
+
readonly MODAL_WIDTH: 50;
|
|
16
|
+
/** Width of the editor/AI selection dialog */
|
|
17
|
+
readonly SELECTOR_WIDTH: 40;
|
|
18
|
+
/** Height of the editor selection dialog */
|
|
19
|
+
readonly EDITOR_SELECTOR_HEIGHT: 12;
|
|
20
|
+
/** Height of the AI tool selection dialog */
|
|
21
|
+
readonly AI_SELECTOR_HEIGHT: 9;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Git-related constants
|
|
25
|
+
*/
|
|
26
|
+
export declare const GIT: {
|
|
27
|
+
/** Length of short SHA commit hash */
|
|
28
|
+
readonly SHORT_SHA_LENGTH: 7;
|
|
29
|
+
/** Default base branch name */
|
|
30
|
+
readonly DEFAULT_BASE_BRANCH: "main";
|
|
31
|
+
/** Directory name for worktrees relative to repo */
|
|
32
|
+
readonly WORKTREES_DIR: "worktrees";
|
|
33
|
+
/** Branches that should never be offered for deletion */
|
|
34
|
+
readonly PROTECTED_BRANCHES: readonly ["main", "master", "production", "prod", "dev", "develop", "development", "qa", "stage", "staging", "release", "hotfix"];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Regex patterns for parsing git output
|
|
38
|
+
*/
|
|
39
|
+
export declare const PATTERNS: {
|
|
40
|
+
/** Match commit SHA from porcelain output */
|
|
41
|
+
readonly COMMIT_SHA: RegExp;
|
|
42
|
+
/** Match worktree path from porcelain output */
|
|
43
|
+
readonly WORKTREE_PATH: RegExp;
|
|
44
|
+
/** Match branch from porcelain output */
|
|
45
|
+
readonly BRANCH_REF: RegExp;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Platform detection
|
|
49
|
+
*/
|
|
50
|
+
export declare const PLATFORM: {
|
|
51
|
+
readonly IS_MAC: boolean;
|
|
52
|
+
readonly IS_WIN: boolean;
|
|
53
|
+
readonly IS_LINUX: boolean;
|
|
54
|
+
readonly IS_WSL: boolean;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Editor types and their display names
|
|
58
|
+
*/
|
|
59
|
+
export declare const EDITORS: {
|
|
60
|
+
readonly code: {
|
|
61
|
+
readonly name: "VS Code";
|
|
62
|
+
readonly terminal: false;
|
|
63
|
+
};
|
|
64
|
+
readonly cursor: {
|
|
65
|
+
readonly name: "Cursor";
|
|
66
|
+
readonly terminal: false;
|
|
67
|
+
};
|
|
68
|
+
readonly zed: {
|
|
69
|
+
readonly name: "Zed";
|
|
70
|
+
readonly terminal: false;
|
|
71
|
+
};
|
|
72
|
+
readonly webstorm: {
|
|
73
|
+
readonly name: "WebStorm";
|
|
74
|
+
readonly terminal: false;
|
|
75
|
+
};
|
|
76
|
+
readonly subl: {
|
|
77
|
+
readonly name: "Sublime Text";
|
|
78
|
+
readonly terminal: false;
|
|
79
|
+
};
|
|
80
|
+
readonly nvim: {
|
|
81
|
+
readonly name: "Neovim";
|
|
82
|
+
readonly terminal: true;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* AI tools and their display names
|
|
87
|
+
*/
|
|
88
|
+
export declare const AI_TOOLS: {
|
|
89
|
+
readonly claude: {
|
|
90
|
+
readonly name: "Claude";
|
|
91
|
+
};
|
|
92
|
+
readonly gemini: {
|
|
93
|
+
readonly name: "Gemini";
|
|
94
|
+
};
|
|
95
|
+
readonly codex: {
|
|
96
|
+
readonly name: "Codex";
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Installation instructions by platform
|
|
101
|
+
*/
|
|
102
|
+
export declare const INSTALL_INSTRUCTIONS: {
|
|
103
|
+
readonly code: {
|
|
104
|
+
readonly darwin: "Open VS Code → Cmd+Shift+P → 'Shell Command: Install code'";
|
|
105
|
+
readonly win32: "Add VS Code to PATH during installation";
|
|
106
|
+
readonly linux: "Install via package manager or add to PATH";
|
|
107
|
+
};
|
|
108
|
+
readonly cursor: {
|
|
109
|
+
readonly darwin: "Open Cursor → Cmd+Shift+P → 'Shell Command: Install cursor'";
|
|
110
|
+
readonly win32: "Add Cursor to PATH during installation";
|
|
111
|
+
readonly linux: "Add Cursor to PATH";
|
|
112
|
+
};
|
|
113
|
+
readonly zed: {
|
|
114
|
+
readonly darwin: "Open Zed → Cmd+Shift+P → 'zed: Install CLI'";
|
|
115
|
+
readonly win32: "Zed CLI installation varies by setup";
|
|
116
|
+
readonly linux: "Zed CLI installation varies by setup";
|
|
117
|
+
};
|
|
118
|
+
readonly webstorm: {
|
|
119
|
+
readonly darwin: "Open WebStorm → Tools → Create Command-line Launcher";
|
|
120
|
+
readonly win32: "Add WebStorm to PATH";
|
|
121
|
+
readonly linux: "Add WebStorm to PATH";
|
|
122
|
+
};
|
|
123
|
+
readonly subl: {
|
|
124
|
+
readonly darwin: "See sublimetext.com/docs/command_line.html";
|
|
125
|
+
readonly win32: "See sublimetext.com/docs/command_line.html";
|
|
126
|
+
readonly linux: "See sublimetext.com/docs/command_line.html";
|
|
127
|
+
};
|
|
128
|
+
readonly nvim: {
|
|
129
|
+
readonly darwin: "Install via: brew install neovim";
|
|
130
|
+
readonly win32: "Install via: choco install neovim or scoop install neovim";
|
|
131
|
+
readonly linux: "Install via: apt install neovim or dnf install neovim";
|
|
132
|
+
};
|
|
133
|
+
readonly claude: {
|
|
134
|
+
readonly darwin: "Install Claude CLI: npm install -g @anthropic-ai/claude-code";
|
|
135
|
+
readonly win32: "Install Claude CLI: npm install -g @anthropic-ai/claude-code";
|
|
136
|
+
readonly linux: "Install Claude CLI: npm install -g @anthropic-ai/claude-code";
|
|
137
|
+
};
|
|
138
|
+
readonly gemini: {
|
|
139
|
+
readonly darwin: "Install Gemini CLI from Google";
|
|
140
|
+
readonly win32: "Install Gemini CLI from Google";
|
|
141
|
+
readonly linux: "Install Gemini CLI from Google";
|
|
142
|
+
};
|
|
143
|
+
readonly codex: {
|
|
144
|
+
readonly darwin: "Install Codex CLI from OpenAI";
|
|
145
|
+
readonly win32: "Install Codex CLI from OpenAI";
|
|
146
|
+
readonly linux: "Install Codex CLI from OpenAI";
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Get install instruction for a tool on the current platform
|
|
151
|
+
*/
|
|
152
|
+
export declare function getInstallInstruction(tool: string): string;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants used throughout the worktree manager application
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* UI-related constants
|
|
6
|
+
*/
|
|
7
|
+
export const UI = {
|
|
8
|
+
/** Maximum length for branch names in list display */
|
|
9
|
+
BRANCH_TRUNCATE_LENGTH: 30,
|
|
10
|
+
/** Height of the help modal in lines */
|
|
11
|
+
HELP_MODAL_HEIGHT: 26,
|
|
12
|
+
/** Height of the create worktree form in lines */
|
|
13
|
+
CREATE_FORM_HEIGHT: 20,
|
|
14
|
+
/** Width of modal dialogs */
|
|
15
|
+
MODAL_WIDTH: 50,
|
|
16
|
+
/** Width of the editor/AI selection dialog */
|
|
17
|
+
SELECTOR_WIDTH: 40,
|
|
18
|
+
/** Height of the editor selection dialog */
|
|
19
|
+
EDITOR_SELECTOR_HEIGHT: 12,
|
|
20
|
+
/** Height of the AI tool selection dialog */
|
|
21
|
+
AI_SELECTOR_HEIGHT: 9,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Git-related constants
|
|
25
|
+
*/
|
|
26
|
+
export const GIT = {
|
|
27
|
+
/** Length of short SHA commit hash */
|
|
28
|
+
SHORT_SHA_LENGTH: 7,
|
|
29
|
+
/** Default base branch name */
|
|
30
|
+
DEFAULT_BASE_BRANCH: 'main',
|
|
31
|
+
/** Directory name for worktrees relative to repo */
|
|
32
|
+
WORKTREES_DIR: 'worktrees',
|
|
33
|
+
/** Branches that should never be offered for deletion */
|
|
34
|
+
PROTECTED_BRANCHES: [
|
|
35
|
+
'main',
|
|
36
|
+
'master',
|
|
37
|
+
'production',
|
|
38
|
+
'prod',
|
|
39
|
+
'dev',
|
|
40
|
+
'develop',
|
|
41
|
+
'development',
|
|
42
|
+
'qa',
|
|
43
|
+
'stage',
|
|
44
|
+
'staging',
|
|
45
|
+
'release',
|
|
46
|
+
'hotfix',
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Regex patterns for parsing git output
|
|
51
|
+
*/
|
|
52
|
+
export const PATTERNS = {
|
|
53
|
+
/** Match commit SHA from porcelain output */
|
|
54
|
+
COMMIT_SHA: /^HEAD ([a-f0-9]+)$/,
|
|
55
|
+
/** Match worktree path from porcelain output */
|
|
56
|
+
WORKTREE_PATH: /^worktree (.+)$/,
|
|
57
|
+
/** Match branch from porcelain output */
|
|
58
|
+
BRANCH_REF: /^branch refs\/heads\/(.+)$/,
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Platform detection
|
|
62
|
+
*/
|
|
63
|
+
export const PLATFORM = {
|
|
64
|
+
IS_MAC: process.platform === 'darwin',
|
|
65
|
+
IS_WIN: process.platform === 'win32',
|
|
66
|
+
IS_LINUX: process.platform === 'linux',
|
|
67
|
+
IS_WSL: process.platform === 'linux' && !!process.env.WSL_DISTRO_NAME,
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Editor types and their display names
|
|
71
|
+
*/
|
|
72
|
+
export const EDITORS = {
|
|
73
|
+
code: { name: 'VS Code', terminal: false },
|
|
74
|
+
cursor: { name: 'Cursor', terminal: false },
|
|
75
|
+
zed: { name: 'Zed', terminal: false },
|
|
76
|
+
webstorm: { name: 'WebStorm', terminal: false },
|
|
77
|
+
subl: { name: 'Sublime Text', terminal: false },
|
|
78
|
+
nvim: { name: 'Neovim', terminal: true },
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* AI tools and their display names
|
|
82
|
+
*/
|
|
83
|
+
export const AI_TOOLS = {
|
|
84
|
+
claude: { name: 'Claude' },
|
|
85
|
+
gemini: { name: 'Gemini' },
|
|
86
|
+
codex: { name: 'Codex' },
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Installation instructions by platform
|
|
90
|
+
*/
|
|
91
|
+
export const INSTALL_INSTRUCTIONS = {
|
|
92
|
+
code: {
|
|
93
|
+
darwin: "Open VS Code → Cmd+Shift+P → 'Shell Command: Install code'",
|
|
94
|
+
win32: 'Add VS Code to PATH during installation',
|
|
95
|
+
linux: 'Install via package manager or add to PATH',
|
|
96
|
+
},
|
|
97
|
+
cursor: {
|
|
98
|
+
darwin: "Open Cursor → Cmd+Shift+P → 'Shell Command: Install cursor'",
|
|
99
|
+
win32: 'Add Cursor to PATH during installation',
|
|
100
|
+
linux: 'Add Cursor to PATH',
|
|
101
|
+
},
|
|
102
|
+
zed: {
|
|
103
|
+
darwin: "Open Zed → Cmd+Shift+P → 'zed: Install CLI'",
|
|
104
|
+
win32: 'Zed CLI installation varies by setup',
|
|
105
|
+
linux: 'Zed CLI installation varies by setup',
|
|
106
|
+
},
|
|
107
|
+
webstorm: {
|
|
108
|
+
darwin: 'Open WebStorm → Tools → Create Command-line Launcher',
|
|
109
|
+
win32: 'Add WebStorm to PATH',
|
|
110
|
+
linux: 'Add WebStorm to PATH',
|
|
111
|
+
},
|
|
112
|
+
subl: {
|
|
113
|
+
darwin: 'See sublimetext.com/docs/command_line.html',
|
|
114
|
+
win32: 'See sublimetext.com/docs/command_line.html',
|
|
115
|
+
linux: 'See sublimetext.com/docs/command_line.html',
|
|
116
|
+
},
|
|
117
|
+
nvim: {
|
|
118
|
+
darwin: 'Install via: brew install neovim',
|
|
119
|
+
win32: 'Install via: choco install neovim or scoop install neovim',
|
|
120
|
+
linux: 'Install via: apt install neovim or dnf install neovim',
|
|
121
|
+
},
|
|
122
|
+
claude: {
|
|
123
|
+
darwin: 'Install Claude CLI: npm install -g @anthropic-ai/claude-code',
|
|
124
|
+
win32: 'Install Claude CLI: npm install -g @anthropic-ai/claude-code',
|
|
125
|
+
linux: 'Install Claude CLI: npm install -g @anthropic-ai/claude-code',
|
|
126
|
+
},
|
|
127
|
+
gemini: {
|
|
128
|
+
darwin: 'Install Gemini CLI from Google',
|
|
129
|
+
win32: 'Install Gemini CLI from Google',
|
|
130
|
+
linux: 'Install Gemini CLI from Google',
|
|
131
|
+
},
|
|
132
|
+
codex: {
|
|
133
|
+
darwin: 'Install Codex CLI from OpenAI',
|
|
134
|
+
win32: 'Install Codex CLI from OpenAI',
|
|
135
|
+
linux: 'Install Codex CLI from OpenAI',
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Get install instruction for a tool on the current platform
|
|
140
|
+
*/
|
|
141
|
+
export function getInstallInstruction(tool) {
|
|
142
|
+
const instructions = INSTALL_INSTRUCTIONS[tool];
|
|
143
|
+
if (!instructions) {
|
|
144
|
+
return `Install ${tool}`;
|
|
145
|
+
}
|
|
146
|
+
const platform = process.platform;
|
|
147
|
+
return instructions[platform] || instructions.darwin || `Install ${tool}`;
|
|
148
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for better error handling and debugging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for all worktree manager errors
|
|
6
|
+
*/
|
|
7
|
+
export declare class WorktreeManagerError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Error thrown when a git command fails
|
|
12
|
+
*/
|
|
13
|
+
export declare class GitCommandError extends WorktreeManagerError {
|
|
14
|
+
readonly command: string;
|
|
15
|
+
readonly stderr: string;
|
|
16
|
+
readonly exitCode: number | undefined;
|
|
17
|
+
constructor(message: string, command: string, stderr?: string, exitCode?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Get a user-friendly error message
|
|
20
|
+
*/
|
|
21
|
+
getUserMessage(): string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Error thrown when a worktree is not found
|
|
25
|
+
*/
|
|
26
|
+
export declare class WorktreeNotFoundError extends WorktreeManagerError {
|
|
27
|
+
readonly worktreePath: string;
|
|
28
|
+
constructor(worktreePath: string);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Error thrown when a branch name is invalid
|
|
32
|
+
*/
|
|
33
|
+
export declare class InvalidBranchError extends WorktreeManagerError {
|
|
34
|
+
readonly branch: string;
|
|
35
|
+
readonly reason: string;
|
|
36
|
+
constructor(branch: string, reason?: string);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Error thrown when a path is invalid or contains traversal attempts
|
|
40
|
+
*/
|
|
41
|
+
export declare class InvalidPathError extends WorktreeManagerError {
|
|
42
|
+
readonly invalidPath: string;
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
constructor(invalidPath: string, reason?: string);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Error thrown when an external tool (editor, terminal, AI) is not found
|
|
48
|
+
*/
|
|
49
|
+
export declare class ToolNotFoundError extends WorktreeManagerError {
|
|
50
|
+
readonly toolName: string;
|
|
51
|
+
readonly installHint: string;
|
|
52
|
+
constructor(toolName: string, installHint?: string);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse an error from git command execution into a GitCommandError
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseGitError(error: unknown, command: string): GitCommandError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for better error handling and debugging
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for all worktree manager errors
|
|
6
|
+
*/
|
|
7
|
+
export class WorktreeManagerError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = 'WorktreeManagerError';
|
|
11
|
+
// Maintains proper stack trace for where error was thrown (V8 engines)
|
|
12
|
+
if (Error.captureStackTrace) {
|
|
13
|
+
Error.captureStackTrace(this, this.constructor);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Error thrown when a git command fails
|
|
19
|
+
*/
|
|
20
|
+
export class GitCommandError extends WorktreeManagerError {
|
|
21
|
+
command;
|
|
22
|
+
stderr;
|
|
23
|
+
exitCode;
|
|
24
|
+
constructor(message, command, stderr = '', exitCode) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'GitCommandError';
|
|
27
|
+
this.command = command;
|
|
28
|
+
this.stderr = stderr;
|
|
29
|
+
this.exitCode = exitCode;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get a user-friendly error message
|
|
33
|
+
*/
|
|
34
|
+
getUserMessage() {
|
|
35
|
+
// Parse common git errors into friendly messages
|
|
36
|
+
if (this.stderr.includes('not a git repository')) {
|
|
37
|
+
return 'This directory is not a git repository';
|
|
38
|
+
}
|
|
39
|
+
if (this.stderr.includes('already exists')) {
|
|
40
|
+
return 'A worktree or branch with this name already exists';
|
|
41
|
+
}
|
|
42
|
+
if (this.stderr.includes('is not a valid branch name')) {
|
|
43
|
+
return 'Invalid branch name. Branch names cannot contain spaces or special characters';
|
|
44
|
+
}
|
|
45
|
+
if (this.stderr.includes('invalid reference')) {
|
|
46
|
+
return 'The specified branch or commit does not exist';
|
|
47
|
+
}
|
|
48
|
+
if (this.stderr.includes('contains modified or untracked files')) {
|
|
49
|
+
return 'Worktree has uncommitted changes. Use force to delete anyway';
|
|
50
|
+
}
|
|
51
|
+
// Return original message if no specific parsing applies
|
|
52
|
+
return this.message;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Error thrown when a worktree is not found
|
|
57
|
+
*/
|
|
58
|
+
export class WorktreeNotFoundError extends WorktreeManagerError {
|
|
59
|
+
worktreePath;
|
|
60
|
+
constructor(worktreePath) {
|
|
61
|
+
super(`Worktree not found: ${worktreePath}`);
|
|
62
|
+
this.name = 'WorktreeNotFoundError';
|
|
63
|
+
this.worktreePath = worktreePath;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error thrown when a branch name is invalid
|
|
68
|
+
*/
|
|
69
|
+
export class InvalidBranchError extends WorktreeManagerError {
|
|
70
|
+
branch;
|
|
71
|
+
reason;
|
|
72
|
+
constructor(branch, reason = 'Invalid branch name') {
|
|
73
|
+
super(`Invalid branch name "${branch}": ${reason}`);
|
|
74
|
+
this.name = 'InvalidBranchError';
|
|
75
|
+
this.branch = branch;
|
|
76
|
+
this.reason = reason;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Error thrown when a path is invalid or contains traversal attempts
|
|
81
|
+
*/
|
|
82
|
+
export class InvalidPathError extends WorktreeManagerError {
|
|
83
|
+
invalidPath;
|
|
84
|
+
reason;
|
|
85
|
+
constructor(invalidPath, reason = 'Invalid path') {
|
|
86
|
+
super(`Invalid path "${invalidPath}": ${reason}`);
|
|
87
|
+
this.name = 'InvalidPathError';
|
|
88
|
+
this.invalidPath = invalidPath;
|
|
89
|
+
this.reason = reason;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Error thrown when an external tool (editor, terminal, AI) is not found
|
|
94
|
+
*/
|
|
95
|
+
export class ToolNotFoundError extends WorktreeManagerError {
|
|
96
|
+
toolName;
|
|
97
|
+
installHint;
|
|
98
|
+
constructor(toolName, installHint = '') {
|
|
99
|
+
super(`${toolName} not found${installHint ? `. ${installHint}` : ''}`);
|
|
100
|
+
this.name = 'ToolNotFoundError';
|
|
101
|
+
this.toolName = toolName;
|
|
102
|
+
this.installHint = installHint;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Parse an error from git command execution into a GitCommandError
|
|
107
|
+
*/
|
|
108
|
+
export function parseGitError(error, command) {
|
|
109
|
+
if (error instanceof GitCommandError) {
|
|
110
|
+
return error;
|
|
111
|
+
}
|
|
112
|
+
const err = error;
|
|
113
|
+
const message = err.message || String(error);
|
|
114
|
+
const stderr = err.stderr || '';
|
|
115
|
+
const exitCode = typeof err.code === 'number' ? err.code : undefined;
|
|
116
|
+
return new GitCommandError(message, command, stderr, exitCode);
|
|
117
|
+
}
|