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.
- package/dist/index.js +62 -12
- 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.
|
|
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
|
|
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
|
|
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
|
-
|
|
3631
|
-
let finalMsg;
|
|
3656
|
+
let finalMsg = null;
|
|
3632
3657
|
if (message) {
|
|
3633
|
-
|
|
3634
|
-
|
|
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",
|
|
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.
|
|
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": {
|