@snapcommit/cli 3.4.0 → 3.5.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.
@@ -384,47 +384,153 @@ async function executeCommitWithAI(intent) {
384
384
  }
385
385
  }
386
386
  /**
387
- * Advanced conflict resolution - try multiple strategies
387
+ * AI-POWERED conflict resolution - intelligently resolves merge conflicts!
388
388
  */
389
389
  async function tryAdvancedConflictResolution() {
390
390
  try {
391
- // Strategy 1: Try accepting ours (our changes)
392
- try {
393
- (0, child_process_1.execSync)('git checkout --ours .', { encoding: 'utf-8', stdio: 'pipe' });
394
- (0, child_process_1.execSync)('git add .', { encoding: 'utf-8', stdio: 'pipe' });
395
- (0, child_process_1.execSync)('git rebase --continue', { encoding: 'utf-8', stdio: 'pipe' });
396
- return true;
397
- }
398
- catch {
399
- // Strategy 1 failed
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
- // Strategy 2: Try accepting theirs (remote changes)
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
- // Strategy 2 failed
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
- // Strategy 3: Abort and let user handle
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
- catch {
423
- return false;
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
+ // Get the backend URL from env or default
508
+ const backendUrl = process.env.SNAPCOMMIT_BACKEND_URL || 'https://snapcommit.dev';
509
+ const response = await axios.post(`${backendUrl}/api/ai/resolve-conflict`, {
510
+ filename,
511
+ base,
512
+ ours,
513
+ theirs,
514
+ }, {
515
+ headers: {
516
+ 'Content-Type': 'application/json',
517
+ },
518
+ timeout: 30000, // 30 second timeout
519
+ });
520
+ if (response.data?.resolution) {
521
+ return response.data.resolution;
522
+ }
523
+ return null;
524
+ }
525
+ catch (error) {
526
+ // AI resolution failed - fall back to manual choice
527
+ return null;
424
528
  }
425
529
  }
426
530
  /**
427
531
  * Execute Git commands - Cursor-style (clean, fast, auto-fix)
532
+ * NOW SUPPORTS: commits, pushes, pulls, merges, rebases, cherry-picks, stash,
533
+ * resets, reverts, blame, bisect, tags, reflog, and MORE!
428
534
  */
429
535
  async function executeGitCommands(commands) {
430
536
  for (const cmd of commands) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snapcommit/cli",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "Instant AI commits. Beautiful progress tracking. Never write commit messages again.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {