@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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/bin/grove.js +2 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +111 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/cleanup.d.ts +4 -0
  9. package/dist/commands/cleanup.d.ts.map +1 -0
  10. package/dist/commands/cleanup.js +95 -0
  11. package/dist/commands/cleanup.js.map +1 -0
  12. package/dist/commands/code.d.ts +2 -0
  13. package/dist/commands/code.d.ts.map +1 -0
  14. package/dist/commands/code.js +59 -0
  15. package/dist/commands/code.js.map +1 -0
  16. package/dist/commands/init.d.ts +4 -0
  17. package/dist/commands/init.d.ts.map +1 -0
  18. package/dist/commands/init.js +135 -0
  19. package/dist/commands/init.js.map +1 -0
  20. package/dist/commands/list.d.ts +4 -0
  21. package/dist/commands/list.d.ts.map +1 -0
  22. package/dist/commands/list.js +42 -0
  23. package/dist/commands/list.js.map +1 -0
  24. package/dist/commands/path.d.ts +2 -0
  25. package/dist/commands/path.d.ts.map +1 -0
  26. package/dist/commands/path.js +36 -0
  27. package/dist/commands/path.js.map +1 -0
  28. package/dist/commands/remove.d.ts +2 -0
  29. package/dist/commands/remove.d.ts.map +1 -0
  30. package/dist/commands/remove.js +50 -0
  31. package/dist/commands/remove.js.map +1 -0
  32. package/dist/commands/repos.d.ts +2 -0
  33. package/dist/commands/repos.d.ts.map +1 -0
  34. package/dist/commands/repos.js +39 -0
  35. package/dist/commands/repos.js.map +1 -0
  36. package/dist/commands/review.d.ts +4 -0
  37. package/dist/commands/review.d.ts.map +1 -0
  38. package/dist/commands/review.js +96 -0
  39. package/dist/commands/review.js.map +1 -0
  40. package/dist/commands/setup.d.ts +2 -0
  41. package/dist/commands/setup.d.ts.map +1 -0
  42. package/dist/commands/setup.js +227 -0
  43. package/dist/commands/setup.js.map +1 -0
  44. package/dist/commands/shell-init.d.ts +2 -0
  45. package/dist/commands/shell-init.d.ts.map +1 -0
  46. package/dist/commands/shell-init.js +77 -0
  47. package/dist/commands/shell-init.js.map +1 -0
  48. package/dist/commands/sprint.d.ts +4 -0
  49. package/dist/commands/sprint.d.ts.map +1 -0
  50. package/dist/commands/sprint.js +237 -0
  51. package/dist/commands/sprint.js.map +1 -0
  52. package/dist/commands/status.d.ts +4 -0
  53. package/dist/commands/status.d.ts.map +1 -0
  54. package/dist/commands/status.js +47 -0
  55. package/dist/commands/status.js.map +1 -0
  56. package/dist/commands/work.d.ts +4 -0
  57. package/dist/commands/work.d.ts.map +1 -0
  58. package/dist/commands/work.js +104 -0
  59. package/dist/commands/work.js.map +1 -0
  60. package/dist/lib/ai.d.ts +14 -0
  61. package/dist/lib/ai.d.ts.map +1 -0
  62. package/dist/lib/ai.js +36 -0
  63. package/dist/lib/ai.js.map +1 -0
  64. package/dist/lib/config.d.ts +11 -0
  65. package/dist/lib/config.d.ts.map +1 -0
  66. package/dist/lib/config.js +44 -0
  67. package/dist/lib/config.js.map +1 -0
  68. package/dist/lib/credentials.d.ts +11 -0
  69. package/dist/lib/credentials.d.ts.map +1 -0
  70. package/dist/lib/credentials.js +151 -0
  71. package/dist/lib/credentials.js.map +1 -0
  72. package/dist/lib/git.d.ts +23 -0
  73. package/dist/lib/git.d.ts.map +1 -0
  74. package/dist/lib/git.js +136 -0
  75. package/dist/lib/git.js.map +1 -0
  76. package/dist/lib/hooks.d.ts +3 -0
  77. package/dist/lib/hooks.d.ts.map +1 -0
  78. package/dist/lib/hooks.js +44 -0
  79. package/dist/lib/hooks.js.map +1 -0
  80. package/dist/lib/jira.d.ts +21 -0
  81. package/dist/lib/jira.d.ts.map +1 -0
  82. package/dist/lib/jira.js +47 -0
  83. package/dist/lib/jira.js.map +1 -0
  84. package/dist/lib/platform.d.ts +4 -0
  85. package/dist/lib/platform.d.ts.map +1 -0
  86. package/dist/lib/platform.js +10 -0
  87. package/dist/lib/platform.js.map +1 -0
  88. package/dist/lib/providers/bitbucket.d.ts +3 -0
  89. package/dist/lib/providers/bitbucket.d.ts.map +1 -0
  90. package/dist/lib/providers/bitbucket.js +49 -0
  91. package/dist/lib/providers/bitbucket.js.map +1 -0
  92. package/dist/lib/providers/github.d.ts +3 -0
  93. package/dist/lib/providers/github.d.ts.map +1 -0
  94. package/dist/lib/providers/github.js +48 -0
  95. package/dist/lib/providers/github.js.map +1 -0
  96. package/dist/lib/providers/types.d.ts +3 -0
  97. package/dist/lib/providers/types.d.ts.map +1 -0
  98. package/dist/lib/providers/types.js +13 -0
  99. package/dist/lib/providers/types.js.map +1 -0
  100. package/dist/lib/types.d.ts +89 -0
  101. package/dist/lib/types.d.ts.map +1 -0
  102. package/dist/lib/types.js +2 -0
  103. package/dist/lib/types.js.map +1 -0
  104. package/dist/lib/ui.d.ts +14 -0
  105. package/dist/lib/ui.d.ts.map +1 -0
  106. package/dist/lib/ui.js +32 -0
  107. package/dist/lib/ui.js.map +1 -0
  108. 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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/cli.js';
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function cleanupCommand(name?: string, options?: {
2
+ repo?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=cleanup.d.ts.map
@@ -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,2 @@
1
+ export declare function codeCommand(name?: string): Promise<void>;
2
+ //# sourceMappingURL=code.d.ts.map
@@ -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,4 @@
1
+ export declare function initCommand(options: {
2
+ path?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=init.d.ts.map
@@ -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":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAS,MAAM,cAAc,CAAC;AAQ1D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA0B;IAC1D,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;IAEnE,kBAAkB;IAClB,IAAI,OAAe,CAAC;IACpB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,OAAO,GAAG,UAAU,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBACnC;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,4CAA4C;iBACtD;aACF,CAAC,CAAC;YACH,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC;IACrD,MAAM,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAExE,6CAA6C;IAC7C,IAAI,QAAwB,CAAC;IAC7B,IAAI,MAAM,EAAE,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,QAAQ,GAAG;YACT,IAAI,EAAE,WAAW;YACjB,SAAS,EAAE,MAAM,CAAC,KAAK;YACvB,QAAQ,EAAE,MAAM,CAAC,IAAI;YACrB,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;SACtC,CAAC;IACJ,CAAC;SAAM,IAAI,MAAM,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACzC,QAAQ,GAAG;YACT,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,cAAc,EAAE,CAAC,MAAM,CAAC;SACzB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,wBAAwB;QACxB,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAC5C;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,eAAe;gBACxB,OAAO,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC;aACjC;SACF,CAAC,CAAC;QAEH,IAAI,eAAe,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACzC,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBAC/B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,sBAAsB,EAAE;gBACrE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,sBAAsB,EAAE;aACrE,CAAC,CAAC;YACH,QAAQ,GAAG;gBACT,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,QAAQ,EAAE,EAAE,CAAC,QAAQ;gBACrB,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;aACtC,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBAC/B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE;gBAC9D,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE;aAC9D,CAAC,CAAC;YACH,QAAQ,GAAG;gBACT,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,IAAI,EAAE,EAAE,CAAC,IAAI;gBACb,cAAc,EAAE,CAAC,MAAM,CAAC;aACzB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,MAAM,MAAM,GACV,QAAQ,CAAC,IAAI,KAAK,WAAW;QAC3B,CAAC,CAAC,GAAG,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,EAAE;QAC9C,CAAC,CAAC,GAAI,QAAgB,CAAC,KAAK,IAAK,QAAgB,CAAC,IAAI,EAAE,CAAC;IAE7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,EAAE,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,gBAAgB,iBAAiB,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC1C;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,qBAAqB;YAC9B,OAAO,EAAE,IAAI;SACd;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,CAAC,YAAY,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAe;QAC7B,OAAO;QACP,iBAAiB;QACjB,QAAQ;QACR,cAAc,EAAE;YACd,aAAa,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC;SAClD;QACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;KAC1B,CAAC;IAEF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC;IAEjC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC;IAC/B,CAAC;IAED,UAAU,CAAC,MAAM,CAAC,CAAC;IACnB,OAAO,CAAC,SAAS,KAAK,oDAAoD,CAAC,CAAC;IAC5E,IAAI,CAAC,wEAAwE,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO;QACL,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,EAAE;QACT,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function listCommand(options: {
2
+ namesOnly?: boolean;
3
+ }): void;
4
+ //# sourceMappingURL=list.d.ts.map
@@ -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,2 @@
1
+ export declare function pathCommand(name: string): void;
2
+ //# sourceMappingURL=path.d.ts.map
@@ -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"}