@snapcommit/cli 3.8.24 → 3.9.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.
@@ -134,8 +134,31 @@ async function showStatus() {
134
134
  async function executeCommitWithAI(intent) {
135
135
  const status = (0, git_1.getGitStatus)();
136
136
  const hasChanges = status.staged > 0 || status.unstaged > 0 || status.untracked > 0;
137
- if (!hasChanges) {
138
- console.log(chalk_1.default.gray('\n✓ Branch clean\n'));
137
+ // Check if there are unpushed commits (even if working tree is clean)
138
+ let hasUnpushedCommits = false;
139
+ try {
140
+ const unpushed = (0, child_process_1.execSync)('git log @{u}.. --oneline 2>/dev/null || echo ""', { encoding: 'utf-8' }).trim();
141
+ hasUnpushedCommits = unpushed.length > 0;
142
+ }
143
+ catch {
144
+ // No upstream or other error - assume we need to push
145
+ hasUnpushedCommits = true;
146
+ }
147
+ // If no changes AND no unpushed commits, nothing to do
148
+ if (!hasChanges && !hasUnpushedCommits) {
149
+ console.log(chalk_1.default.gray('\n✓ Branch clean - nothing to commit or push\n'));
150
+ return;
151
+ }
152
+ // If no changes but there are unpushed commits, just push
153
+ if (!hasChanges && hasUnpushedCommits) {
154
+ console.log(chalk_1.default.blue('\n🔄 Pushing unpushed commits...\n'));
155
+ try {
156
+ (0, child_process_1.execSync)('git push', { encoding: 'utf-8', stdio: 'inherit' });
157
+ console.log(chalk_1.default.green('\n✓ Pushed successfully\n'));
158
+ }
159
+ catch (error) {
160
+ console.log(chalk_1.default.red(`\n❌ Push failed: ${error.message}\n`));
161
+ }
139
162
  return;
140
163
  }
141
164
  // Count files
@@ -977,6 +1000,102 @@ async function executeGitHubCommand(intent) {
977
1000
  await github.markPRReady(readyPrNum);
978
1001
  console.log(chalk_1.default.green(`✓ PR #${readyPrNum} is now ready for review\n`));
979
1002
  break;
1003
+ case 'merge_queue_add':
1004
+ case 'merge_queue_enable_auto':
1005
+ // GitHub native merge queue (requires branch protection rules)
1006
+ let queuePrNum = intent.target || intent.options?.number;
1007
+ // Auto-detect PR if not specified
1008
+ if (!queuePrNum) {
1009
+ queuePrNum = await github.findPRNumber('current');
1010
+ if (!queuePrNum) {
1011
+ console.log(chalk_1.default.red('\n❌ No PR found for current branch\n'));
1012
+ return;
1013
+ }
1014
+ }
1015
+ // GitHub merge queue = enable auto-merge
1016
+ console.log(chalk_1.default.blue(`\n🔄 Adding PR #${queuePrNum} to merge queue...\n`));
1017
+ console.log(chalk_1.default.gray(' ℹ️ This enables auto-merge (GitHub merge queue requires branch protection)\n'));
1018
+ try {
1019
+ await github.enableAutoMerge(queuePrNum, 'MERGE');
1020
+ console.log(chalk_1.default.green(`✓ PR #${queuePrNum} will auto-merge when:\n`));
1021
+ console.log(chalk_1.default.gray(' • All checks pass'));
1022
+ console.log(chalk_1.default.gray(' • Required reviews are approved'));
1023
+ console.log(chalk_1.default.gray(' • Branch is up to date\n'));
1024
+ }
1025
+ catch (error) {
1026
+ if (error.message.includes('not enabled')) {
1027
+ console.log(chalk_1.default.yellow('\n⚠️ Merge queue not enabled for this repository\n'));
1028
+ console.log(chalk_1.default.white('To enable:'));
1029
+ console.log(chalk_1.default.gray(' 1. Go to repo Settings → Branches'));
1030
+ console.log(chalk_1.default.gray(' 2. Edit branch protection rules'));
1031
+ console.log(chalk_1.default.gray(' 3. Enable "Require merge queue"\n'));
1032
+ }
1033
+ else {
1034
+ throw error;
1035
+ }
1036
+ }
1037
+ break;
1038
+ case 'merge_queue_status':
1039
+ // Show auto-merge status for current PR
1040
+ let statusPrNum = intent.target || intent.options?.number;
1041
+ if (!statusPrNum) {
1042
+ statusPrNum = await github.findPRNumber('current');
1043
+ if (!statusPrNum) {
1044
+ console.log(chalk_1.default.red('\n❌ No PR found for current branch\n'));
1045
+ return;
1046
+ }
1047
+ }
1048
+ console.log(chalk_1.default.blue(`\n🔍 Checking merge queue status for PR #${statusPrNum}...\n`));
1049
+ try {
1050
+ const prDetails = await github.getPullRequest(statusPrNum);
1051
+ const autoMergeEnabled = prDetails.auto_merge !== null;
1052
+ if (autoMergeEnabled) {
1053
+ console.log(chalk_1.default.green('✓ PR is in merge queue (auto-merge enabled)\n'));
1054
+ console.log(chalk_1.default.white('Status:'));
1055
+ console.log(chalk_1.default.gray(` • Merge method: ${prDetails.auto_merge.merge_method.toUpperCase()}`));
1056
+ console.log(chalk_1.default.gray(` • Waiting for: ${prDetails.mergeable_state}`));
1057
+ // Check CI status
1058
+ const ciStatus = await github.getCommitStatus();
1059
+ if (ciStatus.status.state === 'success') {
1060
+ console.log(chalk_1.default.green(' • CI: ✓ Passed'));
1061
+ }
1062
+ else if (ciStatus.status.state === 'pending') {
1063
+ console.log(chalk_1.default.yellow(' • CI: ⏳ Running'));
1064
+ }
1065
+ else {
1066
+ console.log(chalk_1.default.red(' • CI: ❌ Failed'));
1067
+ }
1068
+ console.log();
1069
+ }
1070
+ else {
1071
+ console.log(chalk_1.default.gray('✓ PR is not in merge queue\n'));
1072
+ console.log(chalk_1.default.white('To add to queue:'));
1073
+ console.log(chalk_1.default.cyan(' enable auto-merge when CI passes\n'));
1074
+ }
1075
+ }
1076
+ catch (error) {
1077
+ console.log(chalk_1.default.red(`\n❌ Failed to check status: ${error.message}\n`));
1078
+ }
1079
+ break;
1080
+ case 'merge_queue_remove':
1081
+ // Disable auto-merge
1082
+ let removePrNum = intent.target || intent.options?.number;
1083
+ if (!removePrNum) {
1084
+ removePrNum = await github.findPRNumber('current');
1085
+ if (!removePrNum) {
1086
+ console.log(chalk_1.default.red('\n❌ No PR found for current branch\n'));
1087
+ return;
1088
+ }
1089
+ }
1090
+ console.log(chalk_1.default.blue(`\n🔄 Removing PR #${removePrNum} from merge queue...\n`));
1091
+ try {
1092
+ await github.disableAutoMerge(removePrNum);
1093
+ console.log(chalk_1.default.green(`✓ PR #${removePrNum} removed from merge queue\n`));
1094
+ }
1095
+ catch (error) {
1096
+ console.log(chalk_1.default.red(`\n❌ Failed: ${error.message}\n`));
1097
+ }
1098
+ break;
980
1099
  default:
981
1100
  console.log(chalk_1.default.yellow(`\n⚠️ Action not supported: ${intent.action}\n`));
982
1101
  }
@@ -25,6 +25,7 @@ exports.rerunWorkflow = rerunWorkflow;
25
25
  exports.getPullRequestFiles = getPullRequestFiles;
26
26
  exports.addLabels = addLabels;
27
27
  exports.enableAutoMerge = enableAutoMerge;
28
+ exports.disableAutoMerge = disableAutoMerge;
28
29
  exports.createDraftPullRequest = createDraftPullRequest;
29
30
  exports.markPRReady = markPRReady;
30
31
  exports.getPRStack = getPRStack;
@@ -481,6 +482,49 @@ async function enableAutoMerge(prNumber, mergeMethod = 'MERGE') {
481
482
  }
482
483
  return await response.json();
483
484
  }
485
+ /**
486
+ * Disable auto-merge for a PR
487
+ */
488
+ async function disableAutoMerge(prNumber) {
489
+ const repo = getCurrentRepo();
490
+ if (!repo) {
491
+ throw new Error('Not a GitHub repository');
492
+ }
493
+ // GraphQL query for disabling auto-merge
494
+ const token = (0, github_connect_1.getGitHubToken)();
495
+ if (!token) {
496
+ throw new Error('GitHub not connected');
497
+ }
498
+ // First get PR node ID
499
+ const pr = await getPullRequest(prNumber);
500
+ const nodeId = pr.node_id;
501
+ const query = `
502
+ mutation {
503
+ disablePullRequestAutoMerge(input: {
504
+ pullRequestId: "${nodeId}"
505
+ }) {
506
+ pullRequest {
507
+ id
508
+ autoMergeRequest {
509
+ enabledAt
510
+ }
511
+ }
512
+ }
513
+ }
514
+ `;
515
+ const response = await fetch('https://api.github.com/graphql', {
516
+ method: 'POST',
517
+ headers: {
518
+ Authorization: `Bearer ${token}`,
519
+ 'Content-Type': 'application/json',
520
+ },
521
+ body: JSON.stringify({ query }),
522
+ });
523
+ if (!response.ok) {
524
+ throw new Error('Failed to disable auto-merge');
525
+ }
526
+ return await response.json();
527
+ }
484
528
  /**
485
529
  * Create a draft PR (for stacked PRs)
486
530
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snapcommit/cli",
3
- "version": "3.8.24",
3
+ "version": "3.9.0",
4
4
  "description": "Instant AI commits. Beautiful progress tracking. Never write commit messages again.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {