@snapcommit/cli 2.0.5 → 2.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/dist/commands/cursor-style.js +47 -255
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Cursor-style natural language Git assistant
|
|
4
|
-
*
|
|
4
|
+
* DEAD SIMPLE: Check status → Show changes → Commit → Push → Done!
|
|
5
5
|
*/
|
|
6
6
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -10,7 +10,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.executeCursorStyle = executeCursorStyle;
|
|
11
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
12
12
|
const child_process_1 = require("child_process");
|
|
13
|
-
const readline_1 = __importDefault(require("readline"));
|
|
14
13
|
const git_1 = require("../utils/git");
|
|
15
14
|
const auth_1 = require("../lib/auth");
|
|
16
15
|
async function executeCursorStyle(userInput) {
|
|
@@ -18,132 +17,62 @@ async function executeCursorStyle(userInput) {
|
|
|
18
17
|
console.log(chalk_1.default.red('\n❌ Not a git repository\n'));
|
|
19
18
|
return;
|
|
20
19
|
}
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
25
|
-
console.log(chalk_1.default.
|
|
20
|
+
// Check if there are any changes first
|
|
21
|
+
const status = (0, git_1.getGitStatus)();
|
|
22
|
+
const hasChanges = status.staged > 0 || status.unstaged > 0 || status.untracked > 0;
|
|
23
|
+
if (!hasChanges) {
|
|
24
|
+
console.log(chalk_1.default.gray('\n✓ Branch clean - no changes to commit\n'));
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
28
|
-
// Show
|
|
29
|
-
console.log(chalk_1.default.
|
|
30
|
-
|
|
31
|
-
console.log(chalk_1.default.
|
|
32
|
-
|
|
27
|
+
// Show what changed
|
|
28
|
+
console.log(chalk_1.default.blue('\n📦 Changes detected:\n'));
|
|
29
|
+
if (status.unstaged > 0)
|
|
30
|
+
console.log(chalk_1.default.yellow(` • ${status.unstaged} modified`));
|
|
31
|
+
if (status.untracked > 0)
|
|
32
|
+
console.log(chalk_1.default.yellow(` • ${status.untracked} new`));
|
|
33
|
+
if (status.staged > 0)
|
|
34
|
+
console.log(chalk_1.default.green(` • ${status.staged} staged`));
|
|
33
35
|
console.log();
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log();
|
|
38
|
-
}
|
|
39
|
-
// Ask for confirmation (natural language!)
|
|
40
|
-
const needsConfirm = plan.actions.some(a => a.requiresConfirmation);
|
|
41
|
-
if (needsConfirm) {
|
|
42
|
-
const confirmPrompt = plan.commitMessage
|
|
43
|
-
? chalk_1.default.cyan('What next? ') + chalk_1.default.gray('(') + chalk_1.default.white('continue') + chalk_1.default.gray(' • ') + chalk_1.default.white('cancel') + chalk_1.default.gray(' • ') + chalk_1.default.white('edit message') + chalk_1.default.gray('): ')
|
|
44
|
-
: chalk_1.default.cyan('What next? ') + chalk_1.default.gray('(') + chalk_1.default.white('continue') + chalk_1.default.gray(' • ') + chalk_1.default.white('cancel') + chalk_1.default.gray('): ');
|
|
45
|
-
const answer = await askQuestion(confirmPrompt);
|
|
46
|
-
const input = answer.toLowerCase().trim();
|
|
47
|
-
// Cancel commands
|
|
48
|
-
if (input === 'cancel' || input === 'no' || input === 'n' || input === 'stop' || input === 'abort') {
|
|
49
|
-
console.log(chalk_1.default.gray('\n✗ Cancelled\n'));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// Edit commands
|
|
53
|
-
if (plan.commitMessage && (input === 'edit' || input === 'e' || input === 'change' || input === 'edit message')) {
|
|
54
|
-
plan.commitMessage = await editMessage(plan.commitMessage);
|
|
55
|
-
}
|
|
56
|
-
// Everything else (including "continue", "yes", "go ahead", "do it", "y", or just Enter) → proceed
|
|
36
|
+
// Stage everything
|
|
37
|
+
try {
|
|
38
|
+
(0, git_1.stageAllChanges)();
|
|
57
39
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
await executeAction(action, plan.commitMessage);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
// Try to auto-fix common errors
|
|
66
|
-
const fixed = await tryAutoFix(error, action);
|
|
67
|
-
if (!fixed) {
|
|
68
|
-
console.log(chalk_1.default.red(`\n❌ Error: ${error.message}\n`));
|
|
69
|
-
console.log(chalk_1.default.yellow('💡 Try: "undo last change" to revert\n'));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.log(chalk_1.default.red(`❌ Failed to stage changes: ${error.message}\n`));
|
|
42
|
+
return;
|
|
73
43
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (input.includes('commit') && input.includes('push')) {
|
|
84
|
-
// Generate commit message
|
|
85
|
-
const diff = await getChangeDiff();
|
|
86
|
-
if (diff) {
|
|
87
|
-
commitMessage = await generateCommitMessage(diff);
|
|
88
|
-
}
|
|
89
|
-
actions.push({
|
|
90
|
-
type: 'stage',
|
|
91
|
-
description: 'Stage all changes',
|
|
92
|
-
requiresConfirmation: false,
|
|
93
|
-
});
|
|
94
|
-
actions.push({
|
|
95
|
-
type: 'commit',
|
|
96
|
-
description: `Commit with message: "${commitMessage || 'Update'}"`,
|
|
97
|
-
requiresConfirmation: true,
|
|
98
|
-
requiresCommitMessage: true,
|
|
99
|
-
});
|
|
100
|
-
actions.push({
|
|
101
|
-
type: 'push',
|
|
102
|
-
description: 'Push to origin',
|
|
103
|
-
command: 'git push',
|
|
104
|
-
requiresConfirmation: true,
|
|
105
|
-
});
|
|
106
|
-
return {
|
|
107
|
-
actions,
|
|
108
|
-
commitMessage,
|
|
109
|
-
explanation: 'Stage all changes, commit with AI-generated message, and push to remote',
|
|
110
|
-
};
|
|
44
|
+
// Generate commit message
|
|
45
|
+
console.log(chalk_1.default.blue('🤖 Generating commit message...'));
|
|
46
|
+
const diff = (0, git_1.getGitDiff)(true);
|
|
47
|
+
const commitMessage = await generateCommitMessage(diff);
|
|
48
|
+
console.log(chalk_1.default.green(`\n📝 ${commitMessage.split('\n')[0]}\n`));
|
|
49
|
+
// Commit
|
|
50
|
+
try {
|
|
51
|
+
(0, child_process_1.execSync)(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
52
|
+
console.log(chalk_1.default.green('✓ Committed'));
|
|
111
53
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (diff) {
|
|
116
|
-
commitMessage = await generateCommitMessage(diff);
|
|
117
|
-
}
|
|
118
|
-
actions.push({
|
|
119
|
-
type: 'stage',
|
|
120
|
-
description: 'Stage all changes',
|
|
121
|
-
requiresConfirmation: false,
|
|
122
|
-
});
|
|
123
|
-
actions.push({
|
|
124
|
-
type: 'commit',
|
|
125
|
-
description: `Commit with message: "${commitMessage || 'Update'}"`,
|
|
126
|
-
requiresConfirmation: true,
|
|
127
|
-
requiresCommitMessage: true,
|
|
128
|
-
});
|
|
129
|
-
return {
|
|
130
|
-
actions,
|
|
131
|
-
commitMessage,
|
|
132
|
-
explanation: 'Stage and commit changes with AI-generated message',
|
|
133
|
-
};
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.log(chalk_1.default.red(`❌ Commit failed: ${error.message}\n`));
|
|
56
|
+
return;
|
|
134
57
|
}
|
|
135
|
-
//
|
|
136
|
-
return await getAIInterpretation(userInput);
|
|
137
|
-
}
|
|
138
|
-
async function getChangeDiff() {
|
|
58
|
+
// Push
|
|
139
59
|
try {
|
|
140
|
-
(
|
|
141
|
-
|
|
60
|
+
console.log(chalk_1.default.blue('⬆️ Pushing to remote...'));
|
|
61
|
+
(0, child_process_1.execSync)('git push', { encoding: 'utf-8', stdio: 'pipe' });
|
|
62
|
+
console.log(chalk_1.default.green('✓ Pushed\n'));
|
|
142
63
|
}
|
|
143
|
-
catch {
|
|
144
|
-
|
|
64
|
+
catch (error) {
|
|
65
|
+
// If push fails (e.g., no remote), that's okay
|
|
66
|
+
if (error.message.includes('no configured push destination')) {
|
|
67
|
+
console.log(chalk_1.default.yellow('⚠️ No remote configured - changes committed locally\n'));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log(chalk_1.default.yellow(`⚠️ Push failed: ${error.message}\n`));
|
|
71
|
+
}
|
|
145
72
|
}
|
|
73
|
+
console.log(chalk_1.default.green('✅ Done!\n'));
|
|
146
74
|
}
|
|
75
|
+
// All removed - we're keeping it SUPER simple now!
|
|
147
76
|
async function generateCommitMessage(diff) {
|
|
148
77
|
const token = (0, auth_1.getToken)();
|
|
149
78
|
if (!token) {
|
|
@@ -176,141 +105,4 @@ async function generateCommitMessage(diff) {
|
|
|
176
105
|
return 'Update changes';
|
|
177
106
|
}
|
|
178
107
|
}
|
|
179
|
-
|
|
180
|
-
const token = (0, auth_1.getToken)();
|
|
181
|
-
if (!token)
|
|
182
|
-
return null;
|
|
183
|
-
try {
|
|
184
|
-
const currentBranch = (0, git_1.getCurrentBranch)();
|
|
185
|
-
const status = (0, git_1.getGitStatus)();
|
|
186
|
-
const response = await fetch('https://snapcommit.dev/api/ai/interpret', {
|
|
187
|
-
method: 'POST',
|
|
188
|
-
headers: { 'Content-Type': 'application/json' },
|
|
189
|
-
body: JSON.stringify({
|
|
190
|
-
userInput,
|
|
191
|
-
token,
|
|
192
|
-
context: {
|
|
193
|
-
currentBranch,
|
|
194
|
-
hasUncommittedChanges: status.unstaged > 0 || status.untracked > 0,
|
|
195
|
-
lastCommitHash: (0, child_process_1.execSync)('git log -1 --format=%H 2>/dev/null || echo ""', { encoding: 'utf-8' }).trim(),
|
|
196
|
-
remoteBranch: (0, child_process_1.execSync)('git rev-parse --abbrev-ref @{upstream} 2>/dev/null || echo ""', { encoding: 'utf-8' }).trim(),
|
|
197
|
-
},
|
|
198
|
-
}),
|
|
199
|
-
});
|
|
200
|
-
const data = await response.json();
|
|
201
|
-
// Convert AI intent to execution plan
|
|
202
|
-
// This is a simplified version - in production, this would be more sophisticated
|
|
203
|
-
return convertIntentToPlan(data.intent);
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
function convertIntentToPlan(intent) {
|
|
210
|
-
// Convert the AI intent format to our execution plan format
|
|
211
|
-
// This bridges the existing intent format with the new Cursor-style execution
|
|
212
|
-
if (!intent || !intent.gitCommands)
|
|
213
|
-
return null;
|
|
214
|
-
const actions = intent.gitCommands.map((cmd, i) => ({
|
|
215
|
-
type: inferActionType(cmd),
|
|
216
|
-
description: intent.explanation || `Execute: ${cmd}`,
|
|
217
|
-
command: cmd,
|
|
218
|
-
requiresConfirmation: intent.needsConfirmation || intent.riskLevel !== 'safe',
|
|
219
|
-
}));
|
|
220
|
-
return {
|
|
221
|
-
actions,
|
|
222
|
-
explanation: intent.explanation,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
function inferActionType(command) {
|
|
226
|
-
if (command.includes('git add'))
|
|
227
|
-
return 'stage';
|
|
228
|
-
if (command.includes('git commit'))
|
|
229
|
-
return 'commit';
|
|
230
|
-
if (command.includes('git push'))
|
|
231
|
-
return 'push';
|
|
232
|
-
if (command.includes('git checkout') || command.includes('git switch'))
|
|
233
|
-
return 'checkout';
|
|
234
|
-
if (command.includes('git merge'))
|
|
235
|
-
return 'merge';
|
|
236
|
-
if (command.includes('git reset'))
|
|
237
|
-
return 'reset';
|
|
238
|
-
if (command.includes('git branch'))
|
|
239
|
-
return 'branch';
|
|
240
|
-
if (command.includes('git pull'))
|
|
241
|
-
return 'pull';
|
|
242
|
-
if (command.includes('git rebase'))
|
|
243
|
-
return 'rebase';
|
|
244
|
-
if (command.includes('git cherry-pick'))
|
|
245
|
-
return 'cherry-pick';
|
|
246
|
-
return 'stage';
|
|
247
|
-
}
|
|
248
|
-
async function executeAction(action, commitMessage) {
|
|
249
|
-
switch (action.type) {
|
|
250
|
-
case 'stage':
|
|
251
|
-
(0, git_1.stageAllChanges)();
|
|
252
|
-
console.log(chalk_1.default.green(' ✓ Staged all changes'));
|
|
253
|
-
break;
|
|
254
|
-
case 'commit':
|
|
255
|
-
if (commitMessage) {
|
|
256
|
-
(0, child_process_1.execSync)(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, { encoding: 'utf-8' });
|
|
257
|
-
console.log(chalk_1.default.green(` ✓ Committed`));
|
|
258
|
-
}
|
|
259
|
-
break;
|
|
260
|
-
case 'push':
|
|
261
|
-
(0, child_process_1.execSync)('git push', { encoding: 'utf-8', stdio: 'pipe' });
|
|
262
|
-
console.log(chalk_1.default.green(' ✓ Pushed to remote'));
|
|
263
|
-
break;
|
|
264
|
-
default:
|
|
265
|
-
if (action.command) {
|
|
266
|
-
(0, child_process_1.execSync)(action.command, { encoding: 'utf-8', stdio: 'pipe' });
|
|
267
|
-
console.log(chalk_1.default.green(` ✓ ${action.description}`));
|
|
268
|
-
}
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
async function tryAutoFix(error, action) {
|
|
273
|
-
const errorMsg = error.message?.toLowerCase() || '';
|
|
274
|
-
// Handle "no remote configured"
|
|
275
|
-
if (errorMsg.includes('no configured push destination')) {
|
|
276
|
-
console.log(chalk_1.default.yellow('\n⚠️ No remote repository configured'));
|
|
277
|
-
console.log(chalk_1.default.gray(' You need to add a remote first\n'));
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
// Handle merge conflicts
|
|
281
|
-
if (errorMsg.includes('conflict')) {
|
|
282
|
-
console.log(chalk_1.default.yellow('\n⚠️ Merge conflict detected'));
|
|
283
|
-
console.log(chalk_1.default.gray(' Use: "resolve conflicts" to fix\n'));
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
// Handle auth failures
|
|
287
|
-
if (errorMsg.includes('authentication') || errorMsg.includes('permission denied')) {
|
|
288
|
-
console.log(chalk_1.default.yellow('\n⚠️ Authentication failed'));
|
|
289
|
-
console.log(chalk_1.default.gray(' Check your Git credentials\n'));
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
function askQuestion(query) {
|
|
295
|
-
const rl = readline_1.default.createInterface({
|
|
296
|
-
input: process.stdin,
|
|
297
|
-
output: process.stdout,
|
|
298
|
-
terminal: false, // Don't process terminal escape sequences
|
|
299
|
-
});
|
|
300
|
-
return new Promise((resolve) => {
|
|
301
|
-
// Write prompt manually
|
|
302
|
-
process.stdout.write(query);
|
|
303
|
-
// Listen for ONE line of input
|
|
304
|
-
rl.once('line', (answer) => {
|
|
305
|
-
rl.close();
|
|
306
|
-
resolve(answer.trim());
|
|
307
|
-
});
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
async function editMessage(originalMessage) {
|
|
311
|
-
console.log(chalk_1.default.cyan('\n✏️ Edit commit message:\n'));
|
|
312
|
-
console.log(chalk_1.default.gray(' (Press Enter to keep, or type new message)\n'));
|
|
313
|
-
console.log(chalk_1.default.white(` Current: ${chalk_1.default.cyan(originalMessage)}\n`));
|
|
314
|
-
const newMessage = await askQuestion(chalk_1.default.yellow(' New message: '));
|
|
315
|
-
return newMessage.trim() || originalMessage;
|
|
316
|
-
}
|
|
108
|
+
// All complex logic removed - keeping it DEAD SIMPLE!
|