@abhaydesu/git-pilot 1.0.3 → 1.2.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/README.md +46 -17
- package/index.js +288 -73
- package/package.json +26 -26
- package/public/logo-dark-new.png +0 -0
package/README.md
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
+
<div align="center" display="inline">
|
|
2
|
+
<img width="40" height="40" alt="logo" src="./public/logo-dark-new.png" />
|
|
3
|
+
</div>
|
|
4
|
+
|
|
1
5
|
# Git Pilot
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/@abhaydesu/git-pilot)
|
|
4
8
|
|
|
5
|
-
An AI-powered assistant that lives in your command line to streamline your Git workflow.
|
|
9
|
+
An AI-powered assistant that lives in your command line to streamline your Git workflow. Never write a commit message or look up a command again.
|
|
6
10
|
|
|
11
|
+
---
|
|
7
12
|
|
|
8
|
-
##
|
|
13
|
+
## The Problem
|
|
9
14
|
Remembering complex commands like interactive rebase can be a pain. Writing well-formatted commit messages is a chore. Git is powerful, but its interface can sometimes get in the way of a fast workflow.
|
|
10
15
|
|
|
11
16
|
**Git Pilot** solves this by acting as your intelligent copilot, translating your natural language intent into the exact commands and messages you need.
|
|
12
17
|
|
|
13
|
-
##
|
|
14
|
-
* **
|
|
15
|
-
* **
|
|
16
|
-
|
|
17
|
-
* **
|
|
18
|
+
## Features
|
|
19
|
+
* **AI-Powered Commit Messages:** Analyzes your staged changes (`git diff`) and generates a perfect commit message following the Conventional Commits specification. Just run `git pilot commit <your_intent>`
|
|
20
|
+
* **Natural Language to Git Command:** Translate plain English requests like "squash the last 3 commits" into the precise Git command. One simple `git pilot run <your_request>`
|
|
21
|
+
* **Magic Undo:** Made a mistake? `git pilot undo` analyzes your recent history and suggests the exact command to reverse your last action.
|
|
22
|
+
* **Intelligent Branching:** Describe your goal, and `git pilot branch` will create a clean, conventional branch name for you.
|
|
23
|
+
* **Interactive & Safe:** Always asks for your confirmation before executing any command. You can also **edit** any AI suggestion to get it just right.
|
|
18
24
|
|
|
19
|
-
##
|
|
25
|
+
## Installation
|
|
20
26
|
Make sure you have Node.js (v18+) and Git installed. Then, run the following command to install Git Pilot globally:
|
|
21
27
|
|
|
22
28
|
```bash
|
|
@@ -25,28 +31,51 @@ npm install -g @abhaydesu/git-pilot
|
|
|
25
31
|
|
|
26
32
|
### ◾ Usage
|
|
27
33
|
|
|
28
|
-
####
|
|
29
|
-
|
|
34
|
+
#### *Generating a Commit Message*
|
|
35
|
+
Stage your files (git add .), then run git pilot commit. This command analyzes your staged changes and generates a conventional commit message.
|
|
36
|
+
|
|
37
|
+
##### With an Intent
|
|
38
|
+
Provide a brief description of your changes, and the AI will use it to write the commit message.
|
|
30
39
|
|
|
31
40
|
```Bash
|
|
32
41
|
|
|
33
|
-
git pilot
|
|
42
|
+
git pilot commit "add new user profile page"
|
|
34
43
|
```
|
|
35
|
-
The tool will suggest the correct Git command and ask for confirmation before executing it.
|
|
36
44
|
|
|
45
|
+
##### Without an Intent
|
|
46
|
+
If you don't provide an intent, the AI will analyze the diff of your staged files and generate a message automatically.
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
```Bash
|
|
49
|
+
|
|
50
|
+
git pilot commit
|
|
51
|
+
```
|
|
52
|
+
After running, you can accept, edit, or abort the suggested commit.
|
|
40
53
|
|
|
41
|
-
|
|
54
|
+
|
|
55
|
+
#### *Running a Git Command*
|
|
56
|
+
Run the run command with the task you want to perform. The tool will suggest a command and ask for confirmation.
|
|
42
57
|
|
|
43
58
|
```Bash
|
|
44
59
|
|
|
45
|
-
git pilot
|
|
60
|
+
git pilot run "cherry-pick the last commit from the main branch"
|
|
46
61
|
```
|
|
47
|
-
The tool will suggest a message and ask for confirmation before committing.
|
|
48
62
|
|
|
63
|
+
#### *Creating a New Branch*
|
|
64
|
+
Describe the purpose of your new branch, and let the AI generate a conventional name.
|
|
49
65
|
|
|
66
|
+
```Bash
|
|
67
|
+
|
|
68
|
+
git pilot branch "create a new feature for the auth system"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### *Undoing a Mistake*
|
|
72
|
+
|
|
73
|
+
If you've made a mistake (like a bad commit or merge), this command will analyze your history and suggest the safest way to undo it.
|
|
74
|
+
|
|
75
|
+
```Bash
|
|
76
|
+
|
|
77
|
+
git pilot undo
|
|
78
|
+
```
|
|
50
79
|
|
|
51
80
|
### ◾ How It Works
|
|
52
81
|
Git Pilot is a CLI tool that communicates with a secure backend API. This API uses Google's Gemini models to understand your intent and analyze code, keeping your API keys safe and off your local machine.
|
package/index.js
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { program } from "commander";
|
|
4
4
|
import { execa, execaCommand } from "execa";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import inquirer from "inquirer";
|
|
7
7
|
import chalk from "chalk";
|
|
8
|
-
|
|
9
8
|
import ora from "ora";
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
10
|
+
const API_BRANCH_URL = "https://git-pilot-api.vercel.app/api/pilot-branch";
|
|
11
|
+
const API_COMMIT_URL = "https://git-pilot-api.vercel.app/api/pilot-commit";
|
|
12
|
+
const API_COMMAND_URL = "https://git-pilot-api.vercel.app/api/pilot-run";
|
|
13
|
+
const API_UNDO_URL = "https://git-pilot-api.vercel.app/api/pilot-undo";
|
|
14
14
|
|
|
15
15
|
const getStagedDiff = async () => {
|
|
16
16
|
try {
|
|
17
17
|
const { stdout } = await execa("git", ["diff", "--staged"]);
|
|
18
18
|
return stdout;
|
|
19
19
|
} catch (error) {
|
|
20
|
-
console.error(
|
|
20
|
+
console.error(
|
|
21
|
+
chalk.red("Error getting git diff:"),
|
|
22
|
+
error?.message || error
|
|
23
|
+
);
|
|
21
24
|
process.exit(1);
|
|
22
25
|
}
|
|
23
26
|
};
|
|
24
27
|
|
|
25
|
-
|
|
26
28
|
program
|
|
27
29
|
.name("git-pilot")
|
|
28
30
|
.description("An AI-powered Git assistant in your command line.");
|
|
@@ -31,60 +33,172 @@ program
|
|
|
31
33
|
.command("commit")
|
|
32
34
|
.description("Generate an AI-powered commit message.")
|
|
33
35
|
.argument(
|
|
34
|
-
"
|
|
35
|
-
'The user\'s intent for the commit (e.g., "add a new feature")'
|
|
36
|
+
"[intent]",
|
|
37
|
+
'Optional: The user\'s intent for the commit (e.g., "add a new feature")'
|
|
36
38
|
)
|
|
37
39
|
.action(async (intent) => {
|
|
38
|
-
const spinner = ora(
|
|
40
|
+
const spinner = ora("Analyzing your staged changes...").start();
|
|
39
41
|
|
|
40
42
|
const diff = await getStagedDiff();
|
|
41
43
|
|
|
42
44
|
if (!diff) {
|
|
43
|
-
spinner.warn(
|
|
45
|
+
spinner.warn(
|
|
46
|
+
"No staged changes found. Please stage your files with `git add`."
|
|
47
|
+
);
|
|
44
48
|
process.exit(0);
|
|
45
49
|
}
|
|
46
50
|
|
|
51
|
+
const MAX_PAYLOAD_SIZE = 4 * 1024 * 1024;
|
|
52
|
+
const diffSize = Buffer.byteLength(diff, 'utf8');
|
|
53
|
+
let diffToSend = diff;
|
|
54
|
+
|
|
55
|
+
if (diffSize > MAX_PAYLOAD_SIZE) {
|
|
56
|
+
|
|
57
|
+
const { stdout: diffSummary } = await execa("git", ["diff", "--staged", "--name-status"]);
|
|
58
|
+
|
|
59
|
+
diffToSend = "The staged changes are too large to display the full diff. " +
|
|
60
|
+
"Please generate a commit message based on the user's intent and this summary of changed files:\n\n" +
|
|
61
|
+
diffSummary;
|
|
62
|
+
}
|
|
63
|
+
|
|
47
64
|
try {
|
|
48
|
-
spinner.text =
|
|
65
|
+
spinner.text = "Generating commit message...";
|
|
49
66
|
|
|
50
|
-
const response = await axios.post(
|
|
51
|
-
|
|
67
|
+
const response = await axios.post(
|
|
68
|
+
API_COMMIT_URL,
|
|
69
|
+
{ intent, diff: diffToSend },
|
|
52
70
|
{ timeout: 30000 }
|
|
53
|
-
|
|
71
|
+
);
|
|
54
72
|
|
|
55
73
|
const suggestedMessage = response.data.message;
|
|
56
|
-
|
|
74
|
+
|
|
57
75
|
spinner.succeed();
|
|
58
76
|
|
|
59
77
|
console.log(chalk.green("\n--- Suggested Message ---"));
|
|
60
78
|
console.log(chalk.cyan(suggestedMessage));
|
|
61
79
|
console.log(chalk.green("-------------------------\n"));
|
|
62
80
|
|
|
81
|
+
const { choice } = await inquirer.prompt([
|
|
82
|
+
{
|
|
83
|
+
type: "list",
|
|
84
|
+
name: "choice",
|
|
85
|
+
message: "What would you like to do?",
|
|
86
|
+
choices: [
|
|
87
|
+
{ name: "Accept", value: "accept" },
|
|
88
|
+
{ name: "Edit", value: "edit" },
|
|
89
|
+
{ name: "Abort", value: "abort" },
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
if (choice === 'abort') {
|
|
95
|
+
console.log(chalk.red('Commit aborted by user.'));
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (choice == "edit") {
|
|
100
|
+
const { editedMessage } = await inquirer.prompt([
|
|
101
|
+
{
|
|
102
|
+
type: "editor",
|
|
103
|
+
name: "editedMessage",
|
|
104
|
+
message: "Edit the commit message: ",
|
|
105
|
+
default: suggestedMessage,
|
|
106
|
+
validate: (input) =>
|
|
107
|
+
input.length > 0 ? true : "Commit message cannot be empty.",
|
|
108
|
+
},
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
await execa("git", ["commit", "-m", editedMessage]);
|
|
112
|
+
console.log(chalk.bgGreen.black("Commit successful!"));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (choice === "accept") {
|
|
116
|
+
await execa("git", ["commit", "-m", suggestedMessage]);
|
|
117
|
+
console.log(chalk.bgGreen.black("Commit successful!"));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error.response) {
|
|
122
|
+
console.error(
|
|
123
|
+
chalk.red(
|
|
124
|
+
`API Error: ${error.response.status} - ${error.response.data.error}`
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
} else {
|
|
128
|
+
console.error(
|
|
129
|
+
chalk.red("An unexpected error occurred: ", error.message)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
program
|
|
138
|
+
.command("run")
|
|
139
|
+
.description("Translate natural language into a Git command.")
|
|
140
|
+
.argument(
|
|
141
|
+
"<string>",
|
|
142
|
+
'The task you want to perform (e.g. "squash the last 3 commits")'
|
|
143
|
+
)
|
|
144
|
+
.action(async (request) => {
|
|
145
|
+
try {
|
|
146
|
+
const spinner = ora("Fetching the right command...").start();
|
|
147
|
+
|
|
148
|
+
const response = await axios.post(
|
|
149
|
+
API_COMMAND_URL,
|
|
150
|
+
{ request },
|
|
151
|
+
{ timeout: 30000 }
|
|
152
|
+
);
|
|
153
|
+
const suggestedCommand = response.data.command;
|
|
154
|
+
|
|
155
|
+
if (suggestedCommand.startsWith("Error:")) {
|
|
156
|
+
spinner.fail(suggestedCommand);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
spinner.succeed();
|
|
161
|
+
|
|
162
|
+
console.log(
|
|
163
|
+
chalk.yellow.bold(
|
|
164
|
+
"\nWARNING: The suggested command will be executed in your shell."
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
console.log(
|
|
168
|
+
chalk.yellow("Always review commands carefully before confirming.\n")
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
console.log(chalk.green("\n------ Suggested Command ------"));
|
|
172
|
+
console.log(chalk.cyan(suggestedCommand));
|
|
173
|
+
console.log(chalk.green("-------------------------------\n"));
|
|
174
|
+
|
|
63
175
|
const { confirm } = await inquirer.prompt([
|
|
64
176
|
{
|
|
65
177
|
type: "confirm",
|
|
66
178
|
name: "confirm",
|
|
67
|
-
message: "
|
|
68
|
-
default:
|
|
179
|
+
message: "Execute this command?",
|
|
180
|
+
default: false,
|
|
69
181
|
},
|
|
70
182
|
]);
|
|
71
183
|
|
|
72
184
|
if (confirm) {
|
|
73
|
-
await
|
|
74
|
-
console.log(chalk.bgGreen.black("
|
|
185
|
+
await execaCommand(suggestedCommand, { stdio: "inherit" });
|
|
186
|
+
console.log(chalk.bgGreen.black("Command executed successfully!"));
|
|
75
187
|
} else {
|
|
76
|
-
console.log(chalk.red("
|
|
188
|
+
console.log(chalk.red("Execution aborted by user."));
|
|
77
189
|
}
|
|
78
190
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
191
|
+
if (error.response) {
|
|
192
|
+
console.error(
|
|
193
|
+
chalk.red(
|
|
194
|
+
`API Error: ${error.response.status} - ${
|
|
195
|
+
error.response.data.error || "No message"
|
|
196
|
+
}`
|
|
197
|
+
)
|
|
198
|
+
);
|
|
85
199
|
} else {
|
|
86
200
|
console.error(
|
|
87
|
-
chalk.red(
|
|
201
|
+
chalk.red(`An unexpected error occurred: ${error.message}`)
|
|
88
202
|
);
|
|
89
203
|
}
|
|
90
204
|
|
|
@@ -92,62 +206,163 @@ program
|
|
|
92
206
|
}
|
|
93
207
|
});
|
|
94
208
|
|
|
95
|
-
|
|
96
209
|
program
|
|
97
|
-
.command(
|
|
98
|
-
.description(
|
|
99
|
-
.
|
|
100
|
-
|
|
210
|
+
.command("undo")
|
|
211
|
+
.description("Suggests a command to undo your last major Git action")
|
|
212
|
+
.action(async () => {
|
|
213
|
+
const spinner = ora("Analyzing your recent Git history...").start();
|
|
214
|
+
|
|
101
215
|
try {
|
|
102
|
-
|
|
216
|
+
const { stdout: reflog } = await execa("git", ["reflog", "-n", "15"]);
|
|
103
217
|
|
|
104
|
-
|
|
105
|
-
API_COMMAND_URL,
|
|
106
|
-
{ request },
|
|
107
|
-
{ timeout: 30000 }
|
|
108
|
-
);
|
|
109
|
-
const suggestedCommand = response.data.command;
|
|
218
|
+
spinner.text = "Suggesting an undo command...";
|
|
110
219
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
220
|
+
const response = await axios.post(API_UNDO_URL, { reflog });
|
|
221
|
+
const { command, explanation } = response.data;
|
|
115
222
|
|
|
116
|
-
|
|
223
|
+
if (!command) {
|
|
224
|
+
spinner.warn("Couldn't determine a safe action to undo.");
|
|
225
|
+
process.exit(0);
|
|
226
|
+
}
|
|
117
227
|
|
|
118
|
-
|
|
119
|
-
console.log(chalk.yellow('Always review commands carefully before confirming.\n'));
|
|
228
|
+
spinner.succeed();
|
|
120
229
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
230
|
+
console.log(chalk.green("\n--- Suggested Undo Command ---"));
|
|
231
|
+
console.log(chalk.cyan(command));
|
|
232
|
+
console.log(chalk.green("------------------------------\n"));
|
|
233
|
+
console.log(chalk.yellow(explanation));
|
|
124
234
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
235
|
+
const { confirm } = await inquirer.prompt([
|
|
236
|
+
{
|
|
237
|
+
type: "confirm",
|
|
238
|
+
name: "confirm",
|
|
239
|
+
message: "Execute this undo command?",
|
|
240
|
+
default: false,
|
|
241
|
+
},
|
|
242
|
+
]);
|
|
243
|
+
|
|
244
|
+
if (confirm) {
|
|
245
|
+
if (command.startsWith('git rebase --abort')) {
|
|
246
|
+
try {
|
|
247
|
+
const { stdout: gitDirRaw } = await execa('git', ['rev-parse', '--git-dir']);
|
|
248
|
+
const gitDir = gitDirRaw.trim();
|
|
249
|
+
|
|
250
|
+
const fs = await import('fs/promises');
|
|
133
251
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
252
|
+
const rebaseApply = `${gitDir}/rebase-apply`;
|
|
253
|
+
const rebaseMerge = `${gitDir}/rebase-merge`;
|
|
254
|
+
|
|
255
|
+
const hasRebaseApply = await fs.access(rebaseApply).then(() => true).catch(() => false);
|
|
256
|
+
const hasRebaseMerge = await fs.access(rebaseMerge).then(() => true).catch(() => false);
|
|
257
|
+
|
|
258
|
+
if (!hasRebaseApply && !hasRebaseMerge) {
|
|
259
|
+
console.log(chalk.yellow('No rebase in progress — abort not necessary.'));
|
|
260
|
+
process.exit(0);
|
|
261
|
+
}
|
|
262
|
+
} catch (e) {
|
|
263
|
+
}
|
|
139
264
|
}
|
|
140
265
|
|
|
266
|
+
await execaCommand(command, { stdio: "inherit" });
|
|
267
|
+
console.log(chalk.bgGreen.black("Action successfully undone!"));
|
|
268
|
+
} else {
|
|
269
|
+
console.log(chalk.red("Execution aborted by user."));
|
|
270
|
+
}
|
|
141
271
|
} catch (error) {
|
|
142
|
-
|
|
143
|
-
console.error(
|
|
144
|
-
chalk.red(`API Error: ${error.response.status} - ${error.response.data.error || 'No message'}`));
|
|
145
|
-
} else {
|
|
146
|
-
console.error(chalk.red(`An unexpected error occurred: ${error.message}`));
|
|
147
|
-
}
|
|
272
|
+
spinner.fail();
|
|
148
273
|
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
274
|
+
if (error.response) {
|
|
275
|
+
console.error(chalk.red(`API Error: ${error.response.status} - ${error.response.data.error || 'No message'}`));
|
|
276
|
+
} else {
|
|
277
|
+
console.error(chalk.red(`An unexpected error occurred: ${error.message}`));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
program
|
|
285
|
+
.command('branch')
|
|
286
|
+
.description('Generates a conventional branch name from a description and creates the branch.')
|
|
287
|
+
.argument('<string>', 'A description of the branch\'s purpose (e.g., "fix login bug")')
|
|
288
|
+
.action(async (description) => {
|
|
289
|
+
const spinner = ora('Generating a conventional branch name...').start();
|
|
290
|
+
try {
|
|
291
|
+
const response = await axios.post(API_BRANCH_URL, { description });
|
|
292
|
+
const { branchName } = response.data;
|
|
293
|
+
|
|
294
|
+
spinner.succeed();
|
|
295
|
+
|
|
296
|
+
console.log(chalk.green('\n--- Suggested Branch Name ---'));
|
|
297
|
+
console.log(chalk.cyan(branchName));
|
|
298
|
+
console.log(chalk.green('-----------------------------\n'));
|
|
299
|
+
|
|
300
|
+
const { choice } = await inquirer.prompt([
|
|
301
|
+
{
|
|
302
|
+
type: 'list',
|
|
303
|
+
name: 'choice',
|
|
304
|
+
message: 'What would you like to do?',
|
|
305
|
+
choices: [
|
|
306
|
+
{ name: 'Accept', value: 'accept' },
|
|
307
|
+
{ name: 'Edit', value: 'edit' },
|
|
308
|
+
{ name: 'Abort', value: 'abort' },
|
|
309
|
+
],
|
|
310
|
+
},
|
|
311
|
+
]);
|
|
312
|
+
|
|
313
|
+
if (choice === 'abort') {
|
|
314
|
+
console.log(chalk.red('Branch creation aborted by user.'));
|
|
315
|
+
process.exit(0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let finalBranchName = branchName;
|
|
319
|
+
|
|
320
|
+
if (choice === 'edit') {
|
|
321
|
+
const editResp = await inquirer.prompt({
|
|
322
|
+
type: 'editor',
|
|
323
|
+
name: 'editedBranchName',
|
|
324
|
+
message: 'Edit the branch name:',
|
|
325
|
+
default: branchName,
|
|
326
|
+
validate: value => (value && value.trim().length > 0) ? true : 'Branch name cannot be empty'
|
|
327
|
+
}, {
|
|
328
|
+
onCancel: () => {
|
|
329
|
+
console.log(chalk.red('\nEdit cancelled.'));
|
|
330
|
+
process.exit(0);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
finalBranchName = editResp.editedBranchName;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const slugifyBranchName = (name) =>
|
|
338
|
+
name
|
|
339
|
+
.toLowerCase()
|
|
340
|
+
.trim()
|
|
341
|
+
.replace(/\s+/g, '-')
|
|
342
|
+
.replace(/[^a-z0-9._\-\/]/g, '')
|
|
343
|
+
.replace(/\/{2,}/g, '/')
|
|
344
|
+
.replace(/^-+|-+$/g, '')
|
|
345
|
+
.slice(0, 250);
|
|
346
|
+
|
|
347
|
+
const safeBranchName = slugifyBranchName(finalBranchName || '');
|
|
348
|
+
|
|
349
|
+
if (!safeBranchName) {
|
|
350
|
+
console.log(chalk.red('Resulting branch name is empty or invalid. Aborting.'));
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
await execa('git', ['switch', '-c', safeBranchName]);
|
|
355
|
+
console.log(chalk.bgGreen.black(`✔ Switched to new branch '${safeBranchName}'`));
|
|
356
|
+
|
|
357
|
+
} catch (error) {
|
|
358
|
+
spinner.fail();
|
|
359
|
+
if (error.response) {
|
|
360
|
+
console.error(chalk.red(`API Error: ${error.response.status} - ${error.response.data.error || 'No message'}`));
|
|
361
|
+
} else {
|
|
362
|
+
console.error(chalk.red(`An unexpected error occurred: ${error.message}`));
|
|
363
|
+
}
|
|
364
|
+
process.exit(1);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
152
367
|
|
|
153
|
-
program.parse(process.argv);
|
|
368
|
+
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@abhaydesu/git-pilot",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
-
},
|
|
9
|
-
"bin": {
|
|
10
|
-
"git-pilot": "./index.js"
|
|
11
|
-
},
|
|
12
|
-
"type": "module",
|
|
13
|
-
"keywords": [],
|
|
14
|
-
"author": "",
|
|
15
|
-
"license": "ISC",
|
|
16
|
-
"preferGlobal": true,
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"axios": "^1.12.2",
|
|
19
|
-
"chalk": "^5.6.2",
|
|
20
|
-
"commander": "^14.0.1",
|
|
21
|
-
"dotenv": "^17.2.2",
|
|
22
|
-
"execa": "^9.6.0",
|
|
23
|
-
"inquirer": "^12.9.6",
|
|
24
|
-
"ora": "^9.0.0"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@abhaydesu/git-pilot",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"git-pilot": "./index.js"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"preferGlobal": true,
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"axios": "^1.12.2",
|
|
19
|
+
"chalk": "^5.6.2",
|
|
20
|
+
"commander": "^14.0.1",
|
|
21
|
+
"dotenv": "^17.2.2",
|
|
22
|
+
"execa": "^9.6.0",
|
|
23
|
+
"inquirer": "^12.9.6",
|
|
24
|
+
"ora": "^9.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
Binary file
|