@snapcommit/cli 3.4.0 ā 3.6.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 +141 -23
- package/package.json +1 -1
|
@@ -384,47 +384,165 @@ async function executeCommitWithAI(intent) {
|
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
386
|
/**
|
|
387
|
-
*
|
|
387
|
+
* AI-POWERED conflict resolution - intelligently resolves merge conflicts!
|
|
388
388
|
*/
|
|
389
389
|
async function tryAdvancedConflictResolution() {
|
|
390
390
|
try {
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
391
|
+
// Get conflicted files
|
|
392
|
+
const conflictedFiles = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', { encoding: 'utf-8' })
|
|
393
|
+
.split('\n')
|
|
394
|
+
.filter(f => f.trim());
|
|
395
|
+
if (conflictedFiles.length === 0)
|
|
396
|
+
return false;
|
|
397
|
+
console.log(chalk_1.default.white(`\nš Analyzing ${conflictedFiles.length} conflicted file(s)...\n`));
|
|
398
|
+
// For each conflicted file, use AI to resolve
|
|
399
|
+
for (const file of conflictedFiles) {
|
|
400
|
+
try {
|
|
401
|
+
// Read the conflicted file
|
|
402
|
+
const conflictContent = (0, child_process_1.execSync)(`git show :1:${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
403
|
+
const oursContent = (0, child_process_1.execSync)(`git show :2:${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
404
|
+
const theirsContent = (0, child_process_1.execSync)(`git show :3:${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
405
|
+
// Ask AI to resolve the conflict
|
|
406
|
+
console.log(chalk_1.default.blue(`š¤ AI analyzing: ${file}...`));
|
|
407
|
+
const resolution = await resolveConflictWithAI(file, conflictContent, oursContent, theirsContent);
|
|
408
|
+
if (resolution) {
|
|
409
|
+
console.log(chalk_1.default.green(`ā AI resolved: ${file}`));
|
|
410
|
+
// Write the resolved content
|
|
411
|
+
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
412
|
+
fs.writeFileSync(file, resolution);
|
|
413
|
+
(0, child_process_1.execSync)(`git add ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
// Fallback: ask user which version to keep
|
|
417
|
+
console.log(chalk_1.default.yellow(`\nā ļø ${file} - Choose resolution:`));
|
|
418
|
+
console.log(chalk_1.default.gray(' 1. Keep your changes (ours)'));
|
|
419
|
+
console.log(chalk_1.default.gray(' 2. Keep their changes (theirs)'));
|
|
420
|
+
console.log(chalk_1.default.gray(' 3. Skip (resolve manually later)\n'));
|
|
421
|
+
const rlConflict = await Promise.resolve().then(() => __importStar(require('readline')));
|
|
422
|
+
const rlChoice = rlConflict.createInterface({
|
|
423
|
+
input: process.stdin,
|
|
424
|
+
output: process.stdout,
|
|
425
|
+
});
|
|
426
|
+
const choice = await new Promise((resolve) => {
|
|
427
|
+
rlChoice.question(chalk_1.default.cyan('Choice (1/2/3): '), (ans) => {
|
|
428
|
+
setImmediate(() => rlChoice.close());
|
|
429
|
+
resolve(ans.trim());
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
if (choice === '1') {
|
|
433
|
+
(0, child_process_1.execSync)(`git checkout --ours ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
434
|
+
(0, child_process_1.execSync)(`git add ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
435
|
+
console.log(chalk_1.default.green(`ā Kept your changes: ${file}`));
|
|
436
|
+
}
|
|
437
|
+
else if (choice === '2') {
|
|
438
|
+
(0, child_process_1.execSync)(`git checkout --theirs ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
439
|
+
(0, child_process_1.execSync)(`git add ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
440
|
+
console.log(chalk_1.default.green(`ā Kept their changes: ${file}`));
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
console.log(chalk_1.default.gray(`ā Skipped: ${file}`));
|
|
444
|
+
return false; // User wants to resolve manually
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
catch (fileError) {
|
|
449
|
+
console.log(chalk_1.default.yellow(`ā ļø Couldn't auto-resolve ${file}`));
|
|
450
|
+
// Fallback: ask user
|
|
451
|
+
const rlFallback = await Promise.resolve().then(() => __importStar(require('readline')));
|
|
452
|
+
const rlFallbackChoice = rlFallback.createInterface({
|
|
453
|
+
input: process.stdin,
|
|
454
|
+
output: process.stdout,
|
|
455
|
+
});
|
|
456
|
+
const fallbackChoice = await new Promise((resolve) => {
|
|
457
|
+
rlFallbackChoice.question(chalk_1.default.cyan(`Keep (1) yours or (2) theirs? [1/2]: `), (ans) => {
|
|
458
|
+
setImmediate(() => rlFallbackChoice.close());
|
|
459
|
+
resolve(ans.trim());
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
if (fallbackChoice === '1') {
|
|
463
|
+
(0, child_process_1.execSync)(`git checkout --ours ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
464
|
+
(0, child_process_1.execSync)(`git add ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
465
|
+
}
|
|
466
|
+
else if (fallbackChoice === '2') {
|
|
467
|
+
(0, child_process_1.execSync)(`git checkout --theirs ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
468
|
+
(0, child_process_1.execSync)(`git add ${file}`, { encoding: 'utf-8', stdio: 'pipe' });
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
400
474
|
}
|
|
401
|
-
//
|
|
475
|
+
// Continue the rebase
|
|
402
476
|
try {
|
|
403
|
-
(0, child_process_1.execSync)('git rebase --abort', { encoding: 'utf-8', stdio: 'pipe' });
|
|
404
|
-
(0, child_process_1.execSync)('git pull --rebase', { encoding: 'utf-8', stdio: 'pipe' });
|
|
405
|
-
(0, child_process_1.execSync)('git checkout --theirs .', { encoding: 'utf-8', stdio: 'pipe' });
|
|
406
|
-
(0, child_process_1.execSync)('git add .', { encoding: 'utf-8', stdio: 'pipe' });
|
|
407
477
|
(0, child_process_1.execSync)('git rebase --continue', { encoding: 'utf-8', stdio: 'pipe' });
|
|
408
478
|
return true;
|
|
409
479
|
}
|
|
410
|
-
catch {
|
|
411
|
-
//
|
|
480
|
+
catch (continueError) {
|
|
481
|
+
// If rebase fails, might need to commit first
|
|
482
|
+
try {
|
|
483
|
+
(0, child_process_1.execSync)('git commit --no-edit', { encoding: 'utf-8', stdio: 'pipe' });
|
|
484
|
+
(0, child_process_1.execSync)('git rebase --continue', { encoding: 'utf-8', stdio: 'pipe' });
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
412
490
|
}
|
|
413
|
-
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
console.log(chalk_1.default.red(`ā Conflict resolution failed: ${error.message}`));
|
|
414
494
|
try {
|
|
415
495
|
(0, child_process_1.execSync)('git rebase --abort', { encoding: 'utf-8', stdio: 'pipe' });
|
|
416
496
|
}
|
|
417
|
-
catch {
|
|
418
|
-
// Already aborted
|
|
419
|
-
}
|
|
497
|
+
catch { }
|
|
420
498
|
return false;
|
|
421
499
|
}
|
|
422
|
-
|
|
423
|
-
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Use AI to intelligently resolve merge conflicts
|
|
503
|
+
*/
|
|
504
|
+
async function resolveConflictWithAI(filename, base, ours, theirs) {
|
|
505
|
+
try {
|
|
506
|
+
const axios = (await Promise.resolve().then(() => __importStar(require('axios')))).default;
|
|
507
|
+
const { getAuthConfig } = await Promise.resolve().then(() => __importStar(require('../lib/auth')));
|
|
508
|
+
// Get auth token
|
|
509
|
+
const authConfig = getAuthConfig();
|
|
510
|
+
if (!authConfig || !authConfig.token) {
|
|
511
|
+
console.log(chalk_1.default.yellow('ā ļø Authentication required for AI conflict resolution'));
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
// Get the backend URL from env or default
|
|
515
|
+
const backendUrl = process.env.SNAPCOMMIT_BACKEND_URL || 'https://snapcommit.dev';
|
|
516
|
+
const response = await axios.post(`${backendUrl}/api/ai/resolve-conflict`, {
|
|
517
|
+
filename,
|
|
518
|
+
base,
|
|
519
|
+
ours,
|
|
520
|
+
theirs,
|
|
521
|
+
token: authConfig.token,
|
|
522
|
+
}, {
|
|
523
|
+
headers: {
|
|
524
|
+
'Content-Type': 'application/json',
|
|
525
|
+
},
|
|
526
|
+
timeout: 30000, // 30 second timeout
|
|
527
|
+
});
|
|
528
|
+
if (response.data?.resolution) {
|
|
529
|
+
return response.data.resolution;
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
// AI resolution failed - fall back to manual choice
|
|
535
|
+
if (error.response?.status === 403) {
|
|
536
|
+
console.log(chalk_1.default.red('\nā Subscription required for AI conflict resolution'));
|
|
537
|
+
console.log(chalk_1.default.cyan('Visit: https://snapcommit.dev/pricing\n'));
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
424
540
|
}
|
|
425
541
|
}
|
|
426
542
|
/**
|
|
427
543
|
* Execute Git commands - Cursor-style (clean, fast, auto-fix)
|
|
544
|
+
* NOW SUPPORTS: commits, pushes, pulls, merges, rebases, cherry-picks, stash,
|
|
545
|
+
* resets, reverts, blame, bisect, tags, reflog, and MORE!
|
|
428
546
|
*/
|
|
429
547
|
async function executeGitCommands(commands) {
|
|
430
548
|
for (const cmd of commands) {
|