contribute-now 0.4.1-dev.23d6614 → 0.4.1-dev.3325fdb

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.
Files changed (2) hide show
  1. package/dist/index.js +62 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1222,19 +1222,22 @@ function extractJson(raw) {
1222
1222
  }
1223
1223
  return text2;
1224
1224
  }
1225
- async function generateCommitMessage(diff, stagedFiles, model, convention = "clean-commit") {
1225
+ async function generateCommitMessage(diff, stagedFiles, model, convention = "clean-commit", context) {
1226
1226
  try {
1227
1227
  const isLarge = stagedFiles.length >= BATCH_CONFIG.LARGE_CHANGESET_THRESHOLD;
1228
1228
  const multiFileHint = stagedFiles.length > 1 ? `
1229
1229
 
1230
1230
  IMPORTANT: Multiple files are staged. Generate ONE commit message that captures the high-level purpose of ALL changes together. Focus on the overall intent, not individual file changes. Be specific but concise — do not list every file.` : "";
1231
+ const squashHint = context === "squash-merge" ? `
1232
+
1233
+ CONTEXT: This is a squash merge of an entire feature branch into the base branch. All commits are being combined into ONE single commit. Generate a single high-level summary that describes the overall feature or change — NOT a list of individual commits. Think: what capability was added or what problem was solved? Be specific but concise.` : "";
1231
1234
  const diffContent = isLarge ? createCompactDiff(stagedFiles, diff) : diff.slice(0, 4000);
1232
1235
  const userMessage = `Generate a commit message for these staged changes:
1233
1236
 
1234
1237
  Files (${stagedFiles.length}): ${stagedFiles.join(", ")}
1235
1238
 
1236
1239
  Diff:
1237
- ${diffContent}${multiFileHint}`;
1240
+ ${diffContent}${multiFileHint}${squashHint}`;
1238
1241
  const result = await callCopilot(getCommitSystemPrompt(convention), userMessage, model, isLarge ? COPILOT_LONG_TIMEOUT_MS : COPILOT_TIMEOUT_MS);
1239
1242
  return result?.trim() ?? null;
1240
1243
  } catch {
@@ -1966,6 +1969,27 @@ ${pc6.bold("Changed files:")}`);
1966
1969
  }
1967
1970
  }
1968
1971
  info(`Staged files: ${stagedFiles.join(", ")}`);
1972
+ const LARGE_COMMIT_THRESHOLD = 10;
1973
+ if (stagedFiles.length >= LARGE_COMMIT_THRESHOLD && !args.group) {
1974
+ const dirs = new Set(stagedFiles.map((f) => f.split("/")[0]));
1975
+ if (dirs.size > 1) {
1976
+ console.log();
1977
+ warn(`You're staging ${pc6.bold(String(stagedFiles.length))} files across ${pc6.bold(String(dirs.size))} directories in a single commit.`);
1978
+ info(pc6.dim("Large commits mixing different topics make history harder to read and bisect. " + "For cleaner history, consider splitting into atomic commits."));
1979
+ const choice = await selectPrompt("How would you like to proceed?", [
1980
+ "Continue as single commit",
1981
+ "Switch to group mode (AI splits into atomic commits)",
1982
+ "Cancel"
1983
+ ]);
1984
+ if (choice === "Cancel") {
1985
+ process.exit(0);
1986
+ }
1987
+ if (choice === "Switch to group mode (AI splits into atomic commits)") {
1988
+ await runGroupCommit(args.model, config);
1989
+ return;
1990
+ }
1991
+ }
1992
+ }
1969
1993
  let commitMessage = null;
1970
1994
  const useAI = !args["no-ai"];
1971
1995
  if (useAI) {
@@ -2244,7 +2268,7 @@ import pc7 from "picocolors";
2244
2268
  // package.json
2245
2269
  var package_default = {
2246
2270
  name: "contribute-now",
2247
- version: "0.4.1-dev.23d6614",
2271
+ version: "0.4.1-dev.3325fdb",
2248
2272
  description: "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
2249
2273
  type: "module",
2250
2274
  bin: {
@@ -3475,7 +3499,7 @@ var status_default = defineCommand9({
3475
3499
  const branchDiv = await getDivergence(currentBranch, baseBranch);
3476
3500
  const branchLine = formatStatus(currentBranch, baseBranch, branchDiv.ahead, branchDiv.behind);
3477
3501
  console.log(branchLine + pc12.dim(` (current ${pc12.green("*")})`));
3478
- branchStatus = await detectBranchStatus(currentBranch, baseBranch, config);
3502
+ branchStatus = await detectBranchStatus(currentBranch, baseBranch);
3479
3503
  if (branchStatus.merged) {
3480
3504
  console.log(` ${pc12.green("✓")} ${pc12.green("Branch merged")} — ${pc12.dim(branchStatus.mergedReason ?? "all commits reachable from base")}`);
3481
3505
  }
@@ -3552,7 +3576,7 @@ function formatStatus(branch, base, ahead, behind) {
3552
3576
  return ` ${pc12.red("⚡")} ${label} ${pc12.yellow(`${ahead} ahead`)}${pc12.dim(", ")}${pc12.red(`${behind} behind`)} ${pc12.dim(base)}`;
3553
3577
  }
3554
3578
  var STALE_THRESHOLD_DAYS = 14;
3555
- async function detectBranchStatus(branch, baseBranch, config) {
3579
+ async function detectBranchStatus(branch, baseBranch) {
3556
3580
  const result = { merged: false, mergedReason: null, stale: false, staleDaysAgo: null };
3557
3581
  const div = await getDivergence(branch, baseBranch);
3558
3582
  const hasWork = div.ahead > 0;
@@ -3616,10 +3640,12 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
3616
3640
  if (!copilotError) {
3617
3641
  const spinner = createSpinner("Generating AI commit message for squash merge...");
3618
3642
  const [stagedDiff, stagedFiles] = await Promise.all([getStagedDiff(), getStagedFiles()]);
3619
- const aiMsg = await generateCommitMessage(stagedDiff, stagedFiles, options?.model, options?.convention ?? "clean-commit");
3643
+ const aiMsg = await generateCommitMessage(stagedDiff, stagedFiles, options?.model, options?.convention ?? "clean-commit", "squash-merge");
3620
3644
  if (aiMsg) {
3621
3645
  message = aiMsg;
3622
3646
  spinner.success("AI commit message generated.");
3647
+ console.log(`
3648
+ ${pc13.dim("AI suggestion:")} ${pc13.bold(pc13.cyan(message))}`);
3623
3649
  } else {
3624
3650
  spinner.fail("AI did not return a commit message.");
3625
3651
  }
@@ -3627,13 +3653,38 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
3627
3653
  warn(`AI unavailable: ${copilotError}`);
3628
3654
  }
3629
3655
  }
3630
- const fallback = message || `squash merge ${featureBranch}`;
3631
- let finalMsg;
3656
+ let finalMsg = null;
3632
3657
  if (message) {
3633
- console.log(` ${pc13.dim("Commit message:")} ${pc13.bold(message)}`);
3634
- finalMsg = message;
3658
+ while (!finalMsg) {
3659
+ const action = await selectPrompt("What would you like to do?", [
3660
+ "Accept this message",
3661
+ "Edit this message",
3662
+ "Regenerate",
3663
+ "Write manually"
3664
+ ]);
3665
+ if (action === "Accept this message") {
3666
+ finalMsg = message;
3667
+ } else if (action === "Edit this message") {
3668
+ finalMsg = await inputPrompt("Edit commit message", message);
3669
+ } else if (action === "Regenerate") {
3670
+ const spinner = createSpinner("Regenerating commit message...");
3671
+ const [stagedDiff, stagedFiles] = await Promise.all([getStagedDiff(), getStagedFiles()]);
3672
+ const regen = await generateCommitMessage(stagedDiff, stagedFiles, options?.model, options?.convention ?? "clean-commit", "squash-merge");
3673
+ if (regen) {
3674
+ message = regen;
3675
+ spinner.success("Commit message regenerated.");
3676
+ console.log(`
3677
+ ${pc13.dim("AI suggestion:")} ${pc13.bold(pc13.cyan(regen))}`);
3678
+ } else {
3679
+ spinner.fail("Regeneration failed.");
3680
+ finalMsg = await inputPrompt("Enter commit message");
3681
+ }
3682
+ } else {
3683
+ finalMsg = await inputPrompt("Enter commit message");
3684
+ }
3685
+ }
3635
3686
  } else {
3636
- finalMsg = await inputPrompt("Commit message", fallback);
3687
+ finalMsg = await inputPrompt("Commit message", `squash merge ${featureBranch}`);
3637
3688
  }
3638
3689
  const commitResult = await commitWithMessage(finalMsg);
3639
3690
  if (commitResult.exitCode !== 0) {
@@ -4007,7 +4058,6 @@ ${pc13.dim("AI body preview:")}`);
4007
4058
  }
4008
4059
  if (submitAction === "squash") {
4009
4060
  await performSquashMerge(origin, baseBranch, currentBranch, {
4010
- defaultMsg: prTitle ?? undefined,
4011
4061
  model: args.model,
4012
4062
  convention: config.commitConvention
4013
4063
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contribute-now",
3
- "version": "0.4.1-dev.23d6614",
3
+ "version": "0.4.1-dev.3325fdb",
4
4
  "description": "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
5
5
  "type": "module",
6
6
  "bin": {