@abhaydesu/git-pilot 1.0.2 → 1.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/README.md +82 -33
- package/index.js +273 -71
- package/package.json +26 -25
- package/public/logo-pilot.png +0 -0
package/README.md
CHANGED
|
@@ -1,55 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center" display="inline">
|
|
2
|
+
<img width="30" height="30" alt="logo" src="./public/logo-pilot.png" />
|
|
3
|
+
</div>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
# Git Pilot API
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
This is the backend API server that powers the <a href="https://www.npmjs.com/package/@abhaydesu/git-pilot">`git-pilot`</a> CLI tool. It handles the secure communication with AI models to generate Git commands, commit messages, undo actions, and branch names.
|
|
6
8
|
|
|
9
|
+
## ◼️ Purpose
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
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.
|
|
11
|
+
The primary role of this API is to act as a secure intermediary between the <a href="https://github.com/abhaydesu/git-pilot-cli">`git-pilot-cli` </a> and the AI service (Google Gemini). This architecture ensures that the AI API keys are never exposed on a user's local machine.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## ◼️ Technology Stack
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
* **
|
|
15
|
-
* **AI
|
|
15
|
+
* **Runtime:** Node.js
|
|
16
|
+
* **Framework:** Express.js
|
|
17
|
+
* **AI Service:** Google Gemini API
|
|
18
|
+
* **Deployment:** Vercel
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
## ◼️ API Endpoints
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
Make sure you have Node.js (v18+) and Git installed. Then, run the following command to install Git Pilot globally:
|
|
22
|
+
The API exposes the following endpoints:
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
npm install -g @abhaydesu/git-pilot
|
|
24
|
-
```
|
|
24
|
+
### 1. Generate Commit Message
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
* **Route:** `POST /api/pilot-commit`
|
|
27
|
+
* **Description:** Analyzes a Git diff and a user's intent to generate a conventional commit message.
|
|
28
|
+
* **Request Body (JSON):**
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"intent": "string",
|
|
33
|
+
"diff": "string"
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
* **Success Response (200 - JSON):**
|
|
30
37
|
|
|
31
|
-
```
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"message": "string"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
The tool will suggest the correct Git command and ask for confirmation before executing it.
|
|
44
|
+
### 2. Generate Git Command
|
|
36
45
|
|
|
46
|
+
* **Route:** `POST /api/pilot-run`
|
|
47
|
+
* **Description:** Translates a user's natural language request into an executable, safe Git command.
|
|
48
|
+
* **Request Body (JSON):**
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"request": "string"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
* **Success Response (200 - JSON):**
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"command": "string"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
42
62
|
|
|
43
|
-
|
|
63
|
+
### 3. Undo Last Action
|
|
44
64
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
65
|
+
* **Route:** `POST /api/pilot-undo`
|
|
66
|
+
* **Description:** Suggests a safe Git command to undo the most recent significant action (merge, rebase, commit).
|
|
67
|
+
* **Request Body (JSON):**
|
|
48
68
|
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"reflog": "string"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
* **Success Response (200 - JSON):**
|
|
49
75
|
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"command": "string",
|
|
79
|
+
"explanation": "string"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
50
82
|
|
|
51
|
-
###
|
|
52
|
-
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.
|
|
83
|
+
### 4. Generate Branch Name
|
|
53
84
|
|
|
54
|
-
|
|
55
|
-
|
|
85
|
+
* **Route:** `POST /api/pilot-branch`
|
|
86
|
+
* **Description:** Converts a natural language description into a conventional, kebab-case Git branch name.
|
|
87
|
+
* **Request Body (JSON):**
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"description": "string"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
* **Success Response (200 - JSON):**
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"branchName": "string"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### ◾ Deployment
|
|
103
|
+
|
|
104
|
+
This API is designed for and deployed on Vercel.
|
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.");
|
|
@@ -35,56 +37,155 @@ program
|
|
|
35
37
|
'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
|
|
|
47
51
|
try {
|
|
48
|
-
spinner.text =
|
|
52
|
+
spinner.text = "Generating commit message...";
|
|
49
53
|
|
|
50
|
-
const response = await axios.post(
|
|
51
|
-
|
|
54
|
+
const response = await axios.post(
|
|
55
|
+
API_COMMIT_URL,
|
|
56
|
+
{ intent, diff },
|
|
52
57
|
{ timeout: 30000 }
|
|
53
|
-
|
|
58
|
+
);
|
|
54
59
|
|
|
55
60
|
const suggestedMessage = response.data.message;
|
|
56
|
-
|
|
61
|
+
|
|
57
62
|
spinner.succeed();
|
|
58
63
|
|
|
59
64
|
console.log(chalk.green("\n--- Suggested Message ---"));
|
|
60
65
|
console.log(chalk.cyan(suggestedMessage));
|
|
61
66
|
console.log(chalk.green("-------------------------\n"));
|
|
62
67
|
|
|
68
|
+
const { choice } = await inquirer.prompt([
|
|
69
|
+
{
|
|
70
|
+
type: "list",
|
|
71
|
+
name: "choice",
|
|
72
|
+
message: "What would you like to do?",
|
|
73
|
+
choices: [
|
|
74
|
+
{ name: "Accept", value: "accept" },
|
|
75
|
+
{ name: "Edit", value: "edit" },
|
|
76
|
+
{ name: "Abort", value: "abort" },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
if (choice === 'abort') {
|
|
82
|
+
console.log(chalk.red('Commit aborted by user.'));
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (choice == "edit") {
|
|
87
|
+
const { editedMessage } = await inquirer.prompt([
|
|
88
|
+
{
|
|
89
|
+
type: "editor",
|
|
90
|
+
name: "editedMessage",
|
|
91
|
+
message: "Edit the commit message: ",
|
|
92
|
+
default: suggestedMessage,
|
|
93
|
+
validate: (input) =>
|
|
94
|
+
input.length > 0 ? true : "Commit message cannot be empty.",
|
|
95
|
+
},
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
await execa("git", ["commit", "-m", editedMessage]);
|
|
99
|
+
console.log(chalk.bgGreen.black("Commit successful!"));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (choice === "accept") {
|
|
103
|
+
await execa("git", ["commit", "-m", suggestedMessage]);
|
|
104
|
+
console.log(chalk.bgGreen.black("Commit successful!"));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error.response) {
|
|
109
|
+
console.error(
|
|
110
|
+
chalk.red(
|
|
111
|
+
`API Error: ${error.response.status} - ${error.response.data.error}`
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
} else {
|
|
115
|
+
console.error(
|
|
116
|
+
chalk.red("An unexpected error occurred: ", error.message)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
program
|
|
125
|
+
.command("run")
|
|
126
|
+
.description("Translate natural language into a Git command.")
|
|
127
|
+
.argument(
|
|
128
|
+
"<string>",
|
|
129
|
+
'The task you want to perform (e.g. "squash the last 3 commits")'
|
|
130
|
+
)
|
|
131
|
+
.action(async (request) => {
|
|
132
|
+
try {
|
|
133
|
+
const spinner = ora("Fetching the right command...").start();
|
|
134
|
+
|
|
135
|
+
const response = await axios.post(
|
|
136
|
+
API_COMMAND_URL,
|
|
137
|
+
{ request },
|
|
138
|
+
{ timeout: 30000 }
|
|
139
|
+
);
|
|
140
|
+
const suggestedCommand = response.data.command;
|
|
141
|
+
|
|
142
|
+
if (suggestedCommand.startsWith("Error:")) {
|
|
143
|
+
spinner.fail(suggestedCommand);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
spinner.succeed();
|
|
148
|
+
|
|
149
|
+
console.log(
|
|
150
|
+
chalk.yellow.bold(
|
|
151
|
+
"\nWARNING: The suggested command will be executed in your shell."
|
|
152
|
+
)
|
|
153
|
+
);
|
|
154
|
+
console.log(
|
|
155
|
+
chalk.yellow("Always review commands carefully before confirming.\n")
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
console.log(chalk.green("\n------ Suggested Command ------"));
|
|
159
|
+
console.log(chalk.cyan(suggestedCommand));
|
|
160
|
+
console.log(chalk.green("-------------------------------\n"));
|
|
161
|
+
|
|
63
162
|
const { confirm } = await inquirer.prompt([
|
|
64
163
|
{
|
|
65
164
|
type: "confirm",
|
|
66
165
|
name: "confirm",
|
|
67
|
-
message: "
|
|
68
|
-
default:
|
|
166
|
+
message: "Execute this command?",
|
|
167
|
+
default: false,
|
|
69
168
|
},
|
|
70
169
|
]);
|
|
71
170
|
|
|
72
171
|
if (confirm) {
|
|
73
|
-
await
|
|
74
|
-
console.log(chalk.bgGreen.black("
|
|
172
|
+
await execaCommand(suggestedCommand, { stdio: "inherit" });
|
|
173
|
+
console.log(chalk.bgGreen.black("Command executed successfully!"));
|
|
75
174
|
} else {
|
|
76
|
-
console.log(chalk.red("
|
|
175
|
+
console.log(chalk.red("Execution aborted by user."));
|
|
77
176
|
}
|
|
78
177
|
} catch (error) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
178
|
+
if (error.response) {
|
|
179
|
+
console.error(
|
|
180
|
+
chalk.red(
|
|
181
|
+
`API Error: ${error.response.status} - ${
|
|
182
|
+
error.response.data.error || "No message"
|
|
183
|
+
}`
|
|
184
|
+
)
|
|
185
|
+
);
|
|
85
186
|
} else {
|
|
86
187
|
console.error(
|
|
87
|
-
chalk.red(
|
|
188
|
+
chalk.red(`An unexpected error occurred: ${error.message}`)
|
|
88
189
|
);
|
|
89
190
|
}
|
|
90
191
|
|
|
@@ -92,62 +193,163 @@ program
|
|
|
92
193
|
}
|
|
93
194
|
});
|
|
94
195
|
|
|
95
|
-
|
|
96
196
|
program
|
|
97
|
-
.command(
|
|
98
|
-
.description(
|
|
99
|
-
.
|
|
100
|
-
|
|
197
|
+
.command("undo")
|
|
198
|
+
.description("Suggests a command to undo your last major Git action")
|
|
199
|
+
.action(async () => {
|
|
200
|
+
const spinner = ora("Analyzing your recent Git history...").start();
|
|
201
|
+
|
|
101
202
|
try {
|
|
102
|
-
|
|
203
|
+
const { stdout: reflog } = await execa("git", ["reflog", "-n", "15"]);
|
|
103
204
|
|
|
104
|
-
|
|
105
|
-
API_COMMAND_URL,
|
|
106
|
-
{ request },
|
|
107
|
-
{ timeout: 30000 }
|
|
108
|
-
);
|
|
109
|
-
const suggestedCommand = response.data.command;
|
|
205
|
+
spinner.text = "Suggesting an undo command...";
|
|
110
206
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
207
|
+
const response = await axios.post(API_UNDO_URL, { reflog });
|
|
208
|
+
const { command, explanation } = response.data;
|
|
115
209
|
|
|
116
|
-
|
|
210
|
+
if (!command) {
|
|
211
|
+
spinner.warn("Couldn't determine a safe action to undo.");
|
|
212
|
+
process.exit(0);
|
|
213
|
+
}
|
|
117
214
|
|
|
118
|
-
|
|
119
|
-
console.log(chalk.yellow('Always review commands carefully before confirming.\n'));
|
|
215
|
+
spinner.succeed();
|
|
120
216
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
217
|
+
console.log(chalk.green("\n--- Suggested Undo Command ---"));
|
|
218
|
+
console.log(chalk.cyan(command));
|
|
219
|
+
console.log(chalk.green("------------------------------\n"));
|
|
220
|
+
console.log(chalk.yellow(explanation));
|
|
124
221
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
222
|
+
const { confirm } = await inquirer.prompt([
|
|
223
|
+
{
|
|
224
|
+
type: "confirm",
|
|
225
|
+
name: "confirm",
|
|
226
|
+
message: "Execute this undo command?",
|
|
227
|
+
default: false,
|
|
228
|
+
},
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
if (confirm) {
|
|
232
|
+
if (command.startsWith('git rebase --abort')) {
|
|
233
|
+
try {
|
|
234
|
+
const { stdout: gitDirRaw } = await execa('git', ['rev-parse', '--git-dir']);
|
|
235
|
+
const gitDir = gitDirRaw.trim();
|
|
133
236
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
237
|
+
const fs = await import('fs/promises');
|
|
238
|
+
|
|
239
|
+
const rebaseApply = `${gitDir}/rebase-apply`;
|
|
240
|
+
const rebaseMerge = `${gitDir}/rebase-merge`;
|
|
241
|
+
|
|
242
|
+
const hasRebaseApply = await fs.access(rebaseApply).then(() => true).catch(() => false);
|
|
243
|
+
const hasRebaseMerge = await fs.access(rebaseMerge).then(() => true).catch(() => false);
|
|
244
|
+
|
|
245
|
+
if (!hasRebaseApply && !hasRebaseMerge) {
|
|
246
|
+
console.log(chalk.yellow('No rebase in progress — abort not necessary.'));
|
|
247
|
+
process.exit(0);
|
|
248
|
+
}
|
|
249
|
+
} catch (e) {
|
|
250
|
+
}
|
|
139
251
|
}
|
|
140
252
|
|
|
253
|
+
await execaCommand(command, { stdio: "inherit" });
|
|
254
|
+
console.log(chalk.bgGreen.black("Action successfully undone!"));
|
|
255
|
+
} else {
|
|
256
|
+
console.log(chalk.red("Execution aborted by user."));
|
|
257
|
+
}
|
|
141
258
|
} catch (error) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
}
|
|
259
|
+
spinner.fail();
|
|
260
|
+
|
|
261
|
+
if (error.response) {
|
|
262
|
+
console.error(chalk.red(`API Error: ${error.response.status} - ${error.response.data.error || 'No message'}`));
|
|
263
|
+
} else {
|
|
264
|
+
console.error(chalk.red(`An unexpected error occurred: ${error.message}`));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
148
270
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
271
|
+
program
|
|
272
|
+
.command('branch')
|
|
273
|
+
.description('Generates a conventional branch name from a description and creates the branch.')
|
|
274
|
+
.argument('<string>', 'A description of the branch\'s purpose (e.g., "fix login bug")')
|
|
275
|
+
.action(async (description) => {
|
|
276
|
+
const spinner = ora('Generating a conventional branch name...').start();
|
|
277
|
+
try {
|
|
278
|
+
const response = await axios.post(API_BRANCH_URL, { description });
|
|
279
|
+
const { branchName } = response.data;
|
|
280
|
+
|
|
281
|
+
spinner.succeed();
|
|
282
|
+
|
|
283
|
+
console.log(chalk.green('\n--- Suggested Branch Name ---'));
|
|
284
|
+
console.log(chalk.cyan(branchName));
|
|
285
|
+
console.log(chalk.green('-----------------------------\n'));
|
|
286
|
+
|
|
287
|
+
const { choice } = await inquirer.prompt([
|
|
288
|
+
{
|
|
289
|
+
type: 'list',
|
|
290
|
+
name: 'choice',
|
|
291
|
+
message: 'What would you like to do?',
|
|
292
|
+
choices: [
|
|
293
|
+
{ name: 'Accept', value: 'accept' },
|
|
294
|
+
{ name: 'Edit', value: 'edit' },
|
|
295
|
+
{ name: 'Abort', value: 'abort' },
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
]);
|
|
299
|
+
|
|
300
|
+
if (choice === 'abort') {
|
|
301
|
+
console.log(chalk.red('Branch creation aborted by user.'));
|
|
302
|
+
process.exit(0);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let finalBranchName = branchName;
|
|
306
|
+
|
|
307
|
+
if (choice === 'edit') {
|
|
308
|
+
const editResp = await inquirer.prompt({
|
|
309
|
+
type: 'editor',
|
|
310
|
+
name: 'editedBranchName',
|
|
311
|
+
message: 'Edit the branch name:',
|
|
312
|
+
default: branchName,
|
|
313
|
+
validate: value => (value && value.trim().length > 0) ? true : 'Branch name cannot be empty'
|
|
314
|
+
}, {
|
|
315
|
+
onCancel: () => {
|
|
316
|
+
console.log(chalk.red('\nEdit cancelled.'));
|
|
317
|
+
process.exit(0);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
finalBranchName = editResp.editedBranchName;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const slugifyBranchName = (name) =>
|
|
325
|
+
name
|
|
326
|
+
.toLowerCase()
|
|
327
|
+
.trim()
|
|
328
|
+
.replace(/\s+/g, '-')
|
|
329
|
+
.replace(/[^a-z0-9._\-\/]/g, '')
|
|
330
|
+
.replace(/\/{2,}/g, '/')
|
|
331
|
+
.replace(/^-+|-+$/g, '')
|
|
332
|
+
.slice(0, 250);
|
|
333
|
+
|
|
334
|
+
const safeBranchName = slugifyBranchName(finalBranchName || '');
|
|
335
|
+
|
|
336
|
+
if (!safeBranchName) {
|
|
337
|
+
console.log(chalk.red('Resulting branch name is empty or invalid. Aborting.'));
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
await execa('git', ['switch', '-c', safeBranchName]);
|
|
342
|
+
console.log(chalk.bgGreen.black(`✔ Switched to new branch '${safeBranchName}'`));
|
|
343
|
+
|
|
344
|
+
} catch (error) {
|
|
345
|
+
spinner.fail();
|
|
346
|
+
if (error.response) {
|
|
347
|
+
console.error(chalk.red(`API Error: ${error.response.status} - ${error.response.data.error || 'No message'}`));
|
|
348
|
+
} else {
|
|
349
|
+
console.error(chalk.red(`An unexpected error occurred: ${error.message}`));
|
|
350
|
+
}
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
152
354
|
|
|
153
|
-
program.parse(process.argv);
|
|
355
|
+
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,25 +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
|
-
"
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@abhaydesu/git-pilot",
|
|
3
|
+
"version": "1.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
|
+
}
|
|
Binary file
|