@paulbeliavskis/git-grove 0.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/LICENSE +21 -0
- package/README.md +90 -0
- package/bin/grove.js +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +111 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/cleanup.d.ts +4 -0
- package/dist/commands/cleanup.d.ts.map +1 -0
- package/dist/commands/cleanup.js +95 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/code.d.ts +2 -0
- package/dist/commands/code.d.ts.map +1 -0
- package/dist/commands/code.js +59 -0
- package/dist/commands/code.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +135 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +4 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +42 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/path.d.ts +2 -0
- package/dist/commands/path.d.ts.map +1 -0
- package/dist/commands/path.js +36 -0
- package/dist/commands/path.js.map +1 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +50 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/repos.d.ts +2 -0
- package/dist/commands/repos.d.ts.map +1 -0
- package/dist/commands/repos.js +39 -0
- package/dist/commands/repos.js.map +1 -0
- package/dist/commands/review.d.ts +4 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +96 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +227 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/shell-init.d.ts +2 -0
- package/dist/commands/shell-init.d.ts.map +1 -0
- package/dist/commands/shell-init.js +77 -0
- package/dist/commands/shell-init.js.map +1 -0
- package/dist/commands/sprint.d.ts +4 -0
- package/dist/commands/sprint.d.ts.map +1 -0
- package/dist/commands/sprint.js +237 -0
- package/dist/commands/sprint.js.map +1 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +47 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/work.d.ts +4 -0
- package/dist/commands/work.d.ts.map +1 -0
- package/dist/commands/work.js +104 -0
- package/dist/commands/work.js.map +1 -0
- package/dist/lib/ai.d.ts +14 -0
- package/dist/lib/ai.d.ts.map +1 -0
- package/dist/lib/ai.js +36 -0
- package/dist/lib/ai.js.map +1 -0
- package/dist/lib/config.d.ts +11 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +44 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/credentials.d.ts +11 -0
- package/dist/lib/credentials.d.ts.map +1 -0
- package/dist/lib/credentials.js +151 -0
- package/dist/lib/credentials.js.map +1 -0
- package/dist/lib/git.d.ts +23 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +136 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/hooks.d.ts +3 -0
- package/dist/lib/hooks.d.ts.map +1 -0
- package/dist/lib/hooks.js +44 -0
- package/dist/lib/hooks.js.map +1 -0
- package/dist/lib/jira.d.ts +21 -0
- package/dist/lib/jira.d.ts.map +1 -0
- package/dist/lib/jira.js +47 -0
- package/dist/lib/jira.js.map +1 -0
- package/dist/lib/platform.d.ts +4 -0
- package/dist/lib/platform.d.ts.map +1 -0
- package/dist/lib/platform.js +10 -0
- package/dist/lib/platform.js.map +1 -0
- package/dist/lib/providers/bitbucket.d.ts +3 -0
- package/dist/lib/providers/bitbucket.d.ts.map +1 -0
- package/dist/lib/providers/bitbucket.js +49 -0
- package/dist/lib/providers/bitbucket.js.map +1 -0
- package/dist/lib/providers/github.d.ts +3 -0
- package/dist/lib/providers/github.d.ts.map +1 -0
- package/dist/lib/providers/github.js +48 -0
- package/dist/lib/providers/github.js.map +1 -0
- package/dist/lib/providers/types.d.ts +3 -0
- package/dist/lib/providers/types.d.ts.map +1 -0
- package/dist/lib/providers/types.js +13 -0
- package/dist/lib/providers/types.js.map +1 -0
- package/dist/lib/types.d.ts +89 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/ui.d.ts +14 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +32 -0
- package/dist/lib/ui.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Paul Beliavskis
|
|
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,90 @@
|
|
|
1
|
+
# grove
|
|
2
|
+
|
|
3
|
+
Git worktree manager CLI with PR review and AI integration. Works from anywhere, supports multiple repos, and streamlines the full worktree + AI-assisted PR review workflow.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g git-grove
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Register a repo
|
|
15
|
+
grove init
|
|
16
|
+
|
|
17
|
+
# Create a worktree for a ticket
|
|
18
|
+
grove work BO-2048
|
|
19
|
+
|
|
20
|
+
# List worktrees
|
|
21
|
+
grove list
|
|
22
|
+
|
|
23
|
+
# Switch to a worktree (with shell integration)
|
|
24
|
+
gw BO-2048
|
|
25
|
+
|
|
26
|
+
# Review PRs
|
|
27
|
+
grove review
|
|
28
|
+
|
|
29
|
+
# Launch AI tool in a worktree
|
|
30
|
+
grove code BO-2048
|
|
31
|
+
|
|
32
|
+
# Clean up worktrees
|
|
33
|
+
grove cleanup
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Shell Integration
|
|
37
|
+
|
|
38
|
+
Add to your shell profile for the `gw` function (cd into worktrees) with tab completion:
|
|
39
|
+
|
|
40
|
+
**PowerShell:**
|
|
41
|
+
```powershell
|
|
42
|
+
Invoke-Expression (grove shell-init powershell)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Bash/Zsh:**
|
|
46
|
+
```bash
|
|
47
|
+
eval "$(grove shell-init bash)"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Commands
|
|
51
|
+
|
|
52
|
+
| Command | Description |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `grove init` | Register a repo interactively |
|
|
55
|
+
| `grove work <ticket>` | Create worktree for a ticket/branch |
|
|
56
|
+
| `grove list` | List all worktrees across repos |
|
|
57
|
+
| `grove switch <name>` | Output worktree path (used by `gw`) |
|
|
58
|
+
| `grove cleanup [name]` | Remove worktrees (interactive if no name) |
|
|
59
|
+
| `grove review` | Browse and review PRs (Bitbucket/GitHub) |
|
|
60
|
+
| `grove code [name]` | Launch AI tool in a worktree |
|
|
61
|
+
| `grove repos` | List registered repos |
|
|
62
|
+
| `grove status` | Dashboard with dirty/ahead-behind status |
|
|
63
|
+
| `grove shell-init` | Output shell integration script |
|
|
64
|
+
|
|
65
|
+
## Git Providers
|
|
66
|
+
|
|
67
|
+
Grove supports **Bitbucket** and **GitHub**. Configure during `grove init`.
|
|
68
|
+
|
|
69
|
+
### Credential Auto-Detection
|
|
70
|
+
|
|
71
|
+
**Bitbucket:** Checks env vars (`ATLASSIAN_USER_EMAIL`/`ATLASSIAN_API_TOKEN`), `~/.claude.json` MCP server config, then git credential manager.
|
|
72
|
+
|
|
73
|
+
**GitHub:** Checks `GITHUB_TOKEN` env var, `gh auth token` (GitHub CLI), then git credential manager.
|
|
74
|
+
|
|
75
|
+
Grove never stores credentials itself.
|
|
76
|
+
|
|
77
|
+
## AI Integration
|
|
78
|
+
|
|
79
|
+
Configure your AI CLI tool once in `grove init`. Grove supports any CLI tool (Claude Code, Cursor, Aider, Copilot CLI, etc.).
|
|
80
|
+
|
|
81
|
+
- `grove review` can spawn your AI tool with a review prompt template
|
|
82
|
+
- `grove code` launches your AI tool with cwd set to a worktree
|
|
83
|
+
|
|
84
|
+
## Config
|
|
85
|
+
|
|
86
|
+
Stored at `~/.grove/config.json`. Supports multiple repos, each with their own provider, branch patterns, and post-create hooks (copy files, mkdir, npm install, shell commands).
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
package/bin/grove.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('grove')
|
|
10
|
+
.description('Git worktree manager with PR review and AI integration')
|
|
11
|
+
.version(pkg.version);
|
|
12
|
+
program
|
|
13
|
+
.command('setup')
|
|
14
|
+
.description('View config and configure AI, credentials, defaults')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
const { setupCommand } = await import('./commands/setup.js');
|
|
17
|
+
await setupCommand();
|
|
18
|
+
});
|
|
19
|
+
program
|
|
20
|
+
.command('init')
|
|
21
|
+
.description('Register a repo with grove')
|
|
22
|
+
.option('--path <path>', 'Path to git repository')
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
const { initCommand } = await import('./commands/init.js');
|
|
25
|
+
await initCommand(options);
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command('work <ticket>')
|
|
29
|
+
.description('Create a worktree for a ticket/branch')
|
|
30
|
+
.option('-r, --repo <name>', 'Repo alias to use')
|
|
31
|
+
.action(async (ticket, options) => {
|
|
32
|
+
const { workCommand } = await import('./commands/work.js');
|
|
33
|
+
await workCommand(ticket, options);
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command('sprint')
|
|
37
|
+
.description('Pick a ticket from your active sprint and create a worktree')
|
|
38
|
+
.option('-r, --repo <name>', 'Repo alias to use')
|
|
39
|
+
.action(async (options) => {
|
|
40
|
+
const { sprintCommand } = await import('./commands/sprint.js');
|
|
41
|
+
await sprintCommand(options);
|
|
42
|
+
});
|
|
43
|
+
program
|
|
44
|
+
.command('list')
|
|
45
|
+
.description('List all worktrees')
|
|
46
|
+
.option('--names-only', 'Output only folder names')
|
|
47
|
+
.action(async (options) => {
|
|
48
|
+
const { listCommand } = await import('./commands/list.js');
|
|
49
|
+
listCommand(options);
|
|
50
|
+
});
|
|
51
|
+
program
|
|
52
|
+
.command('path <name>')
|
|
53
|
+
.description('Output worktree path for cd (use with gw shell function)')
|
|
54
|
+
.action(async (name) => {
|
|
55
|
+
const { pathCommand } = await import('./commands/path.js');
|
|
56
|
+
pathCommand(name);
|
|
57
|
+
});
|
|
58
|
+
program
|
|
59
|
+
.command('cleanup [name]')
|
|
60
|
+
.description('Remove worktrees')
|
|
61
|
+
.option('-r, --repo <name>', 'Repo alias to use')
|
|
62
|
+
.action(async (name, options) => {
|
|
63
|
+
const { cleanupCommand } = await import('./commands/cleanup.js');
|
|
64
|
+
await cleanupCommand(name, options);
|
|
65
|
+
});
|
|
66
|
+
program
|
|
67
|
+
.command('review')
|
|
68
|
+
.description('Browse and review pull requests')
|
|
69
|
+
.option('-r, --repo <name>', 'Repo alias to use')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
const { reviewCommand } = await import('./commands/review.js');
|
|
72
|
+
await reviewCommand(options);
|
|
73
|
+
});
|
|
74
|
+
program
|
|
75
|
+
.command('code [name]')
|
|
76
|
+
.description('Launch AI tool in a worktree')
|
|
77
|
+
.action(async (name) => {
|
|
78
|
+
const { codeCommand } = await import('./commands/code.js');
|
|
79
|
+
await codeCommand(name);
|
|
80
|
+
});
|
|
81
|
+
program
|
|
82
|
+
.command('remove [name]')
|
|
83
|
+
.description('Unregister a repo from grove')
|
|
84
|
+
.action(async (name) => {
|
|
85
|
+
const { removeCommand } = await import('./commands/remove.js');
|
|
86
|
+
await removeCommand(name);
|
|
87
|
+
});
|
|
88
|
+
program
|
|
89
|
+
.command('repos')
|
|
90
|
+
.description('List registered repos')
|
|
91
|
+
.action(async () => {
|
|
92
|
+
const { reposCommand } = await import('./commands/repos.js');
|
|
93
|
+
reposCommand();
|
|
94
|
+
});
|
|
95
|
+
program
|
|
96
|
+
.command('status')
|
|
97
|
+
.description('Dashboard view of all worktrees')
|
|
98
|
+
.option('--no-remote', 'Skip remote checks (fast local-only mode)')
|
|
99
|
+
.action(async (options) => {
|
|
100
|
+
const { statusCommand } = await import('./commands/status.js');
|
|
101
|
+
statusCommand({ noRemote: !options.remote });
|
|
102
|
+
});
|
|
103
|
+
program
|
|
104
|
+
.command('shell-init [shell]')
|
|
105
|
+
.description('Output shell integration (powershell or bash)')
|
|
106
|
+
.action(async (shell) => {
|
|
107
|
+
const { shellInitCommand } = await import('./commands/shell-init.js');
|
|
108
|
+
shellInitCommand(shell);
|
|
109
|
+
});
|
|
110
|
+
program.parse();
|
|
111
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"AAaA,wBAAsB,cAAc,CAClC,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,iBAqG5B"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import { existsSync, rmSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { loadConfig, getRepoConfig } from '../lib/config.js';
|
|
5
|
+
import { listWorktrees, removeWorktree, pruneWorktrees, deleteBranch, isWorktreeDirty, } from '../lib/git.js';
|
|
6
|
+
import { info, success, warn, error } from '../lib/ui.js';
|
|
7
|
+
export async function cleanupCommand(name, options) {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const { name: repoName, repo } = getRepoConfig(config, options?.repo);
|
|
10
|
+
const worktrees = listWorktrees(repo.gitRoot);
|
|
11
|
+
const nonMain = worktrees.filter((wt) => !wt.bare &&
|
|
12
|
+
wt.path.replace(/\\/g, '/') !== repo.gitRoot.replace(/\\/g, '/'));
|
|
13
|
+
if (nonMain.length === 0) {
|
|
14
|
+
warn('No worktrees to clean up.');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let selected;
|
|
18
|
+
if (name) {
|
|
19
|
+
const match = nonMain.filter((wt) => wt.folderName.toLowerCase().includes(name.toLowerCase()));
|
|
20
|
+
if (match.length === 0) {
|
|
21
|
+
error(`No worktree matching "${name}"`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
selected = match;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const { chosen } = await inquirer.prompt([
|
|
28
|
+
{
|
|
29
|
+
type: 'checkbox',
|
|
30
|
+
name: 'chosen',
|
|
31
|
+
message: 'Select worktrees to remove:',
|
|
32
|
+
choices: nonMain.map((wt) => {
|
|
33
|
+
const dirty = isWorktreeDirty(wt.path);
|
|
34
|
+
return {
|
|
35
|
+
name: `${wt.folderName} (${wt.branch})${dirty ? ' [modified]' : ''}`,
|
|
36
|
+
value: wt,
|
|
37
|
+
};
|
|
38
|
+
}),
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
if (chosen.length === 0) {
|
|
42
|
+
warn('Nothing selected.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
selected = chosen;
|
|
46
|
+
}
|
|
47
|
+
for (const wt of selected) {
|
|
48
|
+
// Warn about uncommitted changes
|
|
49
|
+
if (isWorktreeDirty(wt.path)) {
|
|
50
|
+
const { proceed } = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: 'confirm',
|
|
53
|
+
name: 'proceed',
|
|
54
|
+
message: `${wt.folderName} has uncommitted changes. Remove anyway?`,
|
|
55
|
+
default: false,
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
if (!proceed) {
|
|
59
|
+
info(`Skipped ${wt.folderName}`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Remove .vs folder first (Visual Studio lock issue)
|
|
64
|
+
const vsFolder = join(wt.path, '.vs');
|
|
65
|
+
if (existsSync(vsFolder)) {
|
|
66
|
+
info('Removing .vs folder...');
|
|
67
|
+
try {
|
|
68
|
+
rmSync(vsFolder, { recursive: true, force: true });
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
warn(`Could not remove .vs folder: ${err.message}. Close Visual Studio and try again.`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Remove worktree
|
|
76
|
+
try {
|
|
77
|
+
removeWorktree(repo.gitRoot, wt.path);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
warn('git worktree remove failed. Trying manual removal...');
|
|
81
|
+
try {
|
|
82
|
+
rmSync(wt.path, { recursive: true, force: true });
|
|
83
|
+
pruneWorktrees(repo.gitRoot);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
error(`Could not remove folder: ${err.message}`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Clean up temp branch
|
|
91
|
+
deleteBranch(repo.gitRoot, `${wt.folderName}-temp`);
|
|
92
|
+
success(`Cleaned up: ${wt.folderName}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/commands/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../src/commands/code.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,iBA6D9C"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import { loadConfig } from '../lib/config.js';
|
|
3
|
+
import { listWorktrees } from '../lib/git.js';
|
|
4
|
+
import { launchAiInWorktree } from '../lib/ai.js';
|
|
5
|
+
import { info, error, warn } from '../lib/ui.js';
|
|
6
|
+
export async function codeCommand(name) {
|
|
7
|
+
const config = loadConfig();
|
|
8
|
+
if (!config.ai?.command) {
|
|
9
|
+
error('No AI tool configured. Add an "ai" block to ~/.grove/config.json:');
|
|
10
|
+
console.log(' { "ai": { "command": "claude", "reviewPrompt": "...", "args": [] } }');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
// Collect all non-main worktrees across repos
|
|
14
|
+
const allWorktrees = [];
|
|
15
|
+
for (const repo of Object.values(config.repos)) {
|
|
16
|
+
const wts = listWorktrees(repo.gitRoot);
|
|
17
|
+
const nonMain = wts.filter((wt) => !wt.bare &&
|
|
18
|
+
wt.path.replace(/\\/g, '/') !== repo.gitRoot.replace(/\\/g, '/'));
|
|
19
|
+
allWorktrees.push(...nonMain);
|
|
20
|
+
}
|
|
21
|
+
if (allWorktrees.length === 0) {
|
|
22
|
+
warn('No worktrees found. Create one with `grove work <ticket>`.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let target;
|
|
26
|
+
if (name) {
|
|
27
|
+
const q = name.toLowerCase();
|
|
28
|
+
const match = allWorktrees.find((wt) => wt.folderName.toLowerCase() === q) ||
|
|
29
|
+
allWorktrees.find((wt) => wt.folderName.toLowerCase().startsWith(q)) ||
|
|
30
|
+
allWorktrees.find((wt) => wt.folderName.toLowerCase().includes(q));
|
|
31
|
+
if (!match) {
|
|
32
|
+
error(`No worktree matching "${name}"`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
target = match;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const { selected } = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: 'list',
|
|
41
|
+
name: 'selected',
|
|
42
|
+
message: 'Select worktree:',
|
|
43
|
+
choices: allWorktrees.map((wt) => ({
|
|
44
|
+
name: `${wt.folderName} (${wt.branch})`,
|
|
45
|
+
value: wt,
|
|
46
|
+
})),
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
target = selected;
|
|
50
|
+
}
|
|
51
|
+
info(`Launching ${config.ai.command} in ${target.folderName}...`);
|
|
52
|
+
try {
|
|
53
|
+
launchAiInWorktree(config.ai, target.path);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
error(`Failed to launch AI tool: ${err.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/commands/code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAWA,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,iBAmI3D"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import { loadConfig, saveConfig, configExists } from '../lib/config.js';
|
|
3
|
+
import { getGitRoot, getRemoteUrl, parseRemoteUrl } from '../lib/git.js';
|
|
4
|
+
import { success, info, warn } from '../lib/ui.js';
|
|
5
|
+
export async function initCommand(options) {
|
|
6
|
+
const config = configExists() ? loadConfig() : createFreshConfig();
|
|
7
|
+
// Detect git root
|
|
8
|
+
let gitRoot;
|
|
9
|
+
if (options.path) {
|
|
10
|
+
gitRoot = options.path;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
try {
|
|
14
|
+
gitRoot = getGitRoot();
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
const answer = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'input',
|
|
20
|
+
name: 'path',
|
|
21
|
+
message: 'Not in a git repo. Path to git repository:',
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
gitRoot = answer.path;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Auto-detect from remote URL
|
|
28
|
+
const remoteUrl = getRemoteUrl(gitRoot);
|
|
29
|
+
const parsed = remoteUrl ? parseRemoteUrl(remoteUrl) : null;
|
|
30
|
+
const alias = gitRoot.split(/[\\/]/).pop() || 'repo';
|
|
31
|
+
const worktreeParentDir = gitRoot.split(/[\\/]/).slice(0, -1).join('/');
|
|
32
|
+
// Build provider config from detected values
|
|
33
|
+
let provider;
|
|
34
|
+
if (parsed?.provider === 'bitbucket') {
|
|
35
|
+
provider = {
|
|
36
|
+
type: 'bitbucket',
|
|
37
|
+
workspace: parsed.owner,
|
|
38
|
+
repoSlug: parsed.repo,
|
|
39
|
+
targetBranches: ['develop', 'master'],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else if (parsed?.provider === 'github') {
|
|
43
|
+
provider = {
|
|
44
|
+
type: 'github',
|
|
45
|
+
owner: parsed.owner,
|
|
46
|
+
repo: parsed.repo,
|
|
47
|
+
targetBranches: ['main'],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Couldn't detect - ask
|
|
52
|
+
warn('Could not detect provider from remote URL.');
|
|
53
|
+
const providerAnswers = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'list',
|
|
56
|
+
name: 'type',
|
|
57
|
+
message: 'Git provider:',
|
|
58
|
+
choices: ['bitbucket', 'github'],
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
if (providerAnswers.type === 'bitbucket') {
|
|
62
|
+
const bb = await inquirer.prompt([
|
|
63
|
+
{ type: 'input', name: 'workspace', message: 'Bitbucket workspace:' },
|
|
64
|
+
{ type: 'input', name: 'repoSlug', message: 'Bitbucket repo slug:' },
|
|
65
|
+
]);
|
|
66
|
+
provider = {
|
|
67
|
+
type: 'bitbucket',
|
|
68
|
+
workspace: bb.workspace,
|
|
69
|
+
repoSlug: bb.repoSlug,
|
|
70
|
+
targetBranches: ['develop', 'master'],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const gh = await inquirer.prompt([
|
|
75
|
+
{ type: 'input', name: 'owner', message: 'GitHub owner/org:' },
|
|
76
|
+
{ type: 'input', name: 'repo', message: 'GitHub repo name:' },
|
|
77
|
+
]);
|
|
78
|
+
provider = {
|
|
79
|
+
type: 'github',
|
|
80
|
+
owner: gh.owner,
|
|
81
|
+
repo: gh.repo,
|
|
82
|
+
targetBranches: ['main'],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Show summary and confirm
|
|
87
|
+
const remote = provider.type === 'bitbucket'
|
|
88
|
+
? `${provider.workspace}/${provider.repoSlug}`
|
|
89
|
+
: `${provider.owner}/${provider.repo}`;
|
|
90
|
+
console.log('');
|
|
91
|
+
info('Detected repo settings:');
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(` Alias: ${alias}`);
|
|
94
|
+
console.log(` Git root: ${gitRoot}`);
|
|
95
|
+
console.log(` Worktrees: ${worktreeParentDir}`);
|
|
96
|
+
console.log(` Provider: ${provider.type} (${remote})`);
|
|
97
|
+
console.log(` Targets: ${provider.targetBranches.join(', ')}`);
|
|
98
|
+
console.log('');
|
|
99
|
+
const { confirmed } = await inquirer.prompt([
|
|
100
|
+
{
|
|
101
|
+
type: 'confirm',
|
|
102
|
+
name: 'confirmed',
|
|
103
|
+
message: 'Register this repo?',
|
|
104
|
+
default: true,
|
|
105
|
+
},
|
|
106
|
+
]);
|
|
107
|
+
if (!confirmed) {
|
|
108
|
+
warn('Cancelled.');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const repoConfig = {
|
|
112
|
+
gitRoot,
|
|
113
|
+
worktreeParentDir,
|
|
114
|
+
provider,
|
|
115
|
+
branchPatterns: {
|
|
116
|
+
stripPrefixes: ['feature/', 'bugfix/', 'hotfix/'],
|
|
117
|
+
},
|
|
118
|
+
hooks: { postCreate: [] },
|
|
119
|
+
};
|
|
120
|
+
config.repos[alias] = repoConfig;
|
|
121
|
+
if (!config.defaults.repo) {
|
|
122
|
+
config.defaults.repo = alias;
|
|
123
|
+
}
|
|
124
|
+
saveConfig(config);
|
|
125
|
+
success(`Repo "${alias}" registered. Config saved to ~/.grove/config.json`);
|
|
126
|
+
info('Edit ~/.grove/config.json to add post-create hooks or adjust settings.');
|
|
127
|
+
}
|
|
128
|
+
function createFreshConfig() {
|
|
129
|
+
return {
|
|
130
|
+
version: 1,
|
|
131
|
+
repos: {},
|
|
132
|
+
defaults: {},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,OAAO,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,QA+C3D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { loadConfig } from '../lib/config.js';
|
|
2
|
+
import { listWorktrees, isWorktreeDirty } from '../lib/git.js';
|
|
3
|
+
import { createTable, warn } from '../lib/ui.js';
|
|
4
|
+
export function listCommand(options) {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
const repos = Object.entries(config.repos);
|
|
7
|
+
if (repos.length === 0) {
|
|
8
|
+
warn('No repos registered. Run `grove init` first.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (const [name, repo] of repos) {
|
|
12
|
+
const worktrees = listWorktrees(repo.gitRoot);
|
|
13
|
+
// Exclude the main worktree (bare or gitRoot itself)
|
|
14
|
+
const nonMain = worktrees.filter((wt) => !wt.bare && wt.path.replace(/\\/g, '/') !== repo.gitRoot.replace(/\\/g, '/'));
|
|
15
|
+
if (options.namesOnly) {
|
|
16
|
+
for (const wt of nonMain) {
|
|
17
|
+
console.log(wt.folderName);
|
|
18
|
+
}
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (repos.length > 1) {
|
|
22
|
+
console.log(`\n${name}:`);
|
|
23
|
+
}
|
|
24
|
+
if (nonMain.length === 0) {
|
|
25
|
+
warn(' No worktrees');
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const table = createTable({
|
|
29
|
+
head: ['Folder', 'Branch', 'Status'],
|
|
30
|
+
});
|
|
31
|
+
for (const wt of nonMain) {
|
|
32
|
+
const dirty = isWorktreeDirty(wt.path);
|
|
33
|
+
table.push([
|
|
34
|
+
wt.folderName,
|
|
35
|
+
wt.branch,
|
|
36
|
+
dirty ? 'modified' : 'clean',
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
console.log(table.toString());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,UAAU,WAAW,CAAC,OAAgC;IAC1D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACrD,OAAO;IACT,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,qDAAqD;QACrD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAC9B,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CACrF,CAAC;QAEF,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;YAC7B,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,WAAW,CAAC;YACxB,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;SACrC,CAAC,CAAC;QAEH,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,CAAC,UAAU;gBACb,EAAE,CAAC,MAAM;gBACT,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO;aAC7B,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAChC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/commands/path.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,QAuBvC"}
|