contribute-now 0.6.2-dev.3d69403 → 0.6.2-dev.967437a
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/README.md +8 -3
- package/dist/index.js +588 -579
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7059,6 +7059,9 @@ function configExists(cwd = process.cwd()) {
|
|
|
7059
7059
|
var VALID_WORKFLOWS = ["clean-flow", "github-flow", "git-flow"];
|
|
7060
7060
|
var VALID_ROLES = ["maintainer", "contributor"];
|
|
7061
7061
|
var VALID_CONVENTIONS = ["conventional", "clean-commit", "none"];
|
|
7062
|
+
function isAIEnabled(config, cliNoAI = false) {
|
|
7063
|
+
return config.aiEnabled !== false && !cliNoAI;
|
|
7064
|
+
}
|
|
7062
7065
|
function readConfig(cwd = process.cwd()) {
|
|
7063
7066
|
const path = getConfigPath(cwd);
|
|
7064
7067
|
if (!existsSync(path))
|
|
@@ -7101,7 +7104,10 @@ function readConfig(cwd = process.cwd()) {
|
|
|
7101
7104
|
console.error("Invalid .contributerc.json: all branchPrefixes must be non-empty strings.");
|
|
7102
7105
|
return null;
|
|
7103
7106
|
}
|
|
7104
|
-
return
|
|
7107
|
+
return {
|
|
7108
|
+
...parsed,
|
|
7109
|
+
aiEnabled: parsed.aiEnabled !== false
|
|
7110
|
+
};
|
|
7105
7111
|
} catch {
|
|
7106
7112
|
return null;
|
|
7107
7113
|
}
|
|
@@ -7149,7 +7155,8 @@ function getDefaultConfig() {
|
|
|
7149
7155
|
upstream: "upstream",
|
|
7150
7156
|
origin: "origin",
|
|
7151
7157
|
branchPrefixes: ["feature", "fix", "docs", "chore", "test", "refactor"],
|
|
7152
|
-
commitConvention: "clean-commit"
|
|
7158
|
+
commitConvention: "clean-commit",
|
|
7159
|
+
aiEnabled: true
|
|
7153
7160
|
};
|
|
7154
7161
|
}
|
|
7155
7162
|
|
|
@@ -8756,6 +8763,7 @@ var LogEngine = {
|
|
|
8756
8763
|
|
|
8757
8764
|
// src/utils/logger.ts
|
|
8758
8765
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
8766
|
+
var PROJECT_DISPLAY_NAME = "Contribute Now";
|
|
8759
8767
|
LogEngine.configure({
|
|
8760
8768
|
mode: LogMode.INFO,
|
|
8761
8769
|
format: {
|
|
@@ -8776,9 +8784,10 @@ function warn(msg, emoji = "⚠️") {
|
|
|
8776
8784
|
function info(msg, emoji = "ℹ️") {
|
|
8777
8785
|
LogEngine.info(msg, undefined, { emoji });
|
|
8778
8786
|
}
|
|
8779
|
-
function
|
|
8787
|
+
function projectHeading(command, emoji) {
|
|
8788
|
+
const prefix = emoji ? `${import_picocolors.default.bold(emoji)} ` : "";
|
|
8780
8789
|
console.log(`
|
|
8781
|
-
${import_picocolors.default.bold(
|
|
8790
|
+
${prefix}${import_picocolors.default.bold(import_picocolors.default.cyan(PROJECT_DISPLAY_NAME))} ${import_picocolors.default.dim("—")} ${import_picocolors.default.bold(command)}`);
|
|
8782
8791
|
}
|
|
8783
8792
|
|
|
8784
8793
|
// src/utils/workflow.ts
|
|
@@ -8871,7 +8880,7 @@ var branch_default = defineCommand({
|
|
|
8871
8880
|
const currentBranch = await getCurrentBranch();
|
|
8872
8881
|
const showRemoteOnly = args.remote;
|
|
8873
8882
|
const showAll = args.all;
|
|
8874
|
-
|
|
8883
|
+
projectHeading("branch", "\uD83C\uDF3F");
|
|
8875
8884
|
console.log();
|
|
8876
8885
|
if (!showRemoteOnly) {
|
|
8877
8886
|
const localBranches = await getLocalBranches();
|
|
@@ -8981,6 +8990,9 @@ function groupByRemote(branches) {
|
|
|
8981
8990
|
}
|
|
8982
8991
|
|
|
8983
8992
|
// src/commands/clean.ts
|
|
8993
|
+
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
8994
|
+
|
|
8995
|
+
// src/utils/branchPrompt.ts
|
|
8984
8996
|
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
8985
8997
|
|
|
8986
8998
|
// src/utils/branch.ts
|
|
@@ -10254,7 +10266,7 @@ ${truncated}
|
|
|
10254
10266
|
return result.length > maxTotalChars ? `${result.slice(0, maxTotalChars - 15)}
|
|
10255
10267
|
...(truncated)` : result;
|
|
10256
10268
|
}
|
|
10257
|
-
async function
|
|
10269
|
+
async function checkCopilotAvailable2() {
|
|
10258
10270
|
try {
|
|
10259
10271
|
const client = await getManagedClient();
|
|
10260
10272
|
try {
|
|
@@ -10601,6 +10613,154 @@ ${diffContent}`;
|
|
|
10601
10613
|
}
|
|
10602
10614
|
}
|
|
10603
10615
|
|
|
10616
|
+
// src/utils/spinner.ts
|
|
10617
|
+
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
10618
|
+
var FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
10619
|
+
function createSpinner(text) {
|
|
10620
|
+
let frameIdx = 0;
|
|
10621
|
+
let currentText = text;
|
|
10622
|
+
let stopped = false;
|
|
10623
|
+
const clearLine = () => {
|
|
10624
|
+
process.stderr.write("\r\x1B[K");
|
|
10625
|
+
};
|
|
10626
|
+
const render = () => {
|
|
10627
|
+
if (stopped)
|
|
10628
|
+
return;
|
|
10629
|
+
const frame = import_picocolors6.default.cyan(FRAMES[frameIdx % FRAMES.length]);
|
|
10630
|
+
clearLine();
|
|
10631
|
+
process.stderr.write(`${frame} ${currentText}`);
|
|
10632
|
+
frameIdx++;
|
|
10633
|
+
};
|
|
10634
|
+
const timer = setInterval(render, 80);
|
|
10635
|
+
render();
|
|
10636
|
+
const stop = () => {
|
|
10637
|
+
if (stopped)
|
|
10638
|
+
return;
|
|
10639
|
+
stopped = true;
|
|
10640
|
+
clearInterval(timer);
|
|
10641
|
+
clearLine();
|
|
10642
|
+
};
|
|
10643
|
+
return {
|
|
10644
|
+
update(newText) {
|
|
10645
|
+
currentText = newText;
|
|
10646
|
+
},
|
|
10647
|
+
success(msg) {
|
|
10648
|
+
stop();
|
|
10649
|
+
process.stderr.write(`${import_picocolors6.default.green("✔")} ${msg}
|
|
10650
|
+
`);
|
|
10651
|
+
},
|
|
10652
|
+
fail(msg) {
|
|
10653
|
+
stop();
|
|
10654
|
+
process.stderr.write(`${import_picocolors6.default.red("✖")} ${msg}
|
|
10655
|
+
`);
|
|
10656
|
+
},
|
|
10657
|
+
stop() {
|
|
10658
|
+
stop();
|
|
10659
|
+
}
|
|
10660
|
+
};
|
|
10661
|
+
}
|
|
10662
|
+
|
|
10663
|
+
// src/utils/branchPrompt.ts
|
|
10664
|
+
async function promptForBranchName(options) {
|
|
10665
|
+
const promptMessage = options.promptMessage ?? "What are you going to work on?";
|
|
10666
|
+
let branchInput = options.initialValue?.trim() ?? "";
|
|
10667
|
+
while (!branchInput) {
|
|
10668
|
+
branchInput = (await inputPrompt(promptMessage)).trim();
|
|
10669
|
+
if (branchInput)
|
|
10670
|
+
break;
|
|
10671
|
+
warn("A branch name or description is required.");
|
|
10672
|
+
const action = await selectPrompt("What would you like to do?", ["Try again", "Cancel"]);
|
|
10673
|
+
if (action === "Cancel")
|
|
10674
|
+
return null;
|
|
10675
|
+
}
|
|
10676
|
+
let branchName = branchInput;
|
|
10677
|
+
const useAI = options.useAI !== false && looksLikeNaturalLanguage(branchInput);
|
|
10678
|
+
if (useAI) {
|
|
10679
|
+
const copilotError = await checkCopilotAvailable2();
|
|
10680
|
+
if (copilotError) {
|
|
10681
|
+
warn(`AI unavailable: ${copilotError}`);
|
|
10682
|
+
} else {
|
|
10683
|
+
while (true) {
|
|
10684
|
+
const spinner = createSpinner("Generating branch name suggestion...");
|
|
10685
|
+
const suggested = await suggestBranchName(branchInput, options.model);
|
|
10686
|
+
if (suggested) {
|
|
10687
|
+
spinner.success("Branch name suggestion ready.");
|
|
10688
|
+
console.log(`
|
|
10689
|
+
${import_picocolors7.default.dim("AI suggestion:")} ${import_picocolors7.default.bold(import_picocolors7.default.cyan(suggested))}`);
|
|
10690
|
+
const action2 = await selectPrompt("What would you like to do with this branch name?", [
|
|
10691
|
+
"Use this suggestion",
|
|
10692
|
+
"Try again with AI",
|
|
10693
|
+
"Enter branch name manually",
|
|
10694
|
+
"Use my original description",
|
|
10695
|
+
"Cancel"
|
|
10696
|
+
]);
|
|
10697
|
+
if (action2 === "Use this suggestion") {
|
|
10698
|
+
branchName = suggested;
|
|
10699
|
+
break;
|
|
10700
|
+
}
|
|
10701
|
+
if (action2 === "Try again with AI") {
|
|
10702
|
+
continue;
|
|
10703
|
+
}
|
|
10704
|
+
if (action2 === "Enter branch name manually") {
|
|
10705
|
+
branchName = (await inputPrompt("Enter branch name", branchInput)).trim();
|
|
10706
|
+
break;
|
|
10707
|
+
}
|
|
10708
|
+
if (action2 === "Use my original description") {
|
|
10709
|
+
branchName = branchInput;
|
|
10710
|
+
break;
|
|
10711
|
+
}
|
|
10712
|
+
return null;
|
|
10713
|
+
}
|
|
10714
|
+
spinner.fail("AI did not return a branch name suggestion.");
|
|
10715
|
+
const action = await selectPrompt("AI could not generate a branch name. What would you like to do?", [
|
|
10716
|
+
"Try again with AI",
|
|
10717
|
+
"Enter branch name manually",
|
|
10718
|
+
"Use my original description",
|
|
10719
|
+
"Cancel"
|
|
10720
|
+
]);
|
|
10721
|
+
if (action === "Try again with AI") {
|
|
10722
|
+
continue;
|
|
10723
|
+
}
|
|
10724
|
+
if (action === "Enter branch name manually") {
|
|
10725
|
+
branchName = (await inputPrompt("Enter branch name", branchInput)).trim();
|
|
10726
|
+
break;
|
|
10727
|
+
}
|
|
10728
|
+
if (action === "Use my original description") {
|
|
10729
|
+
branchName = branchInput;
|
|
10730
|
+
break;
|
|
10731
|
+
}
|
|
10732
|
+
return null;
|
|
10733
|
+
}
|
|
10734
|
+
}
|
|
10735
|
+
}
|
|
10736
|
+
while (true) {
|
|
10737
|
+
if (!branchName) {
|
|
10738
|
+
branchName = (await inputPrompt("Enter branch name", branchInput)).trim();
|
|
10739
|
+
if (!branchName) {
|
|
10740
|
+
const action = await selectPrompt("What would you like to do?", ["Try again", "Cancel"]);
|
|
10741
|
+
if (action === "Cancel")
|
|
10742
|
+
return null;
|
|
10743
|
+
continue;
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
if (!hasPrefix(branchName, options.branchPrefixes)) {
|
|
10747
|
+
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors7.default.bold(branchName)}:`, options.branchPrefixes);
|
|
10748
|
+
branchName = formatBranchName(prefix, branchName);
|
|
10749
|
+
}
|
|
10750
|
+
if (!isValidBranchName(branchName)) {
|
|
10751
|
+
warn("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
10752
|
+
branchName = (await inputPrompt("Enter branch name", branchName)).trim();
|
|
10753
|
+
continue;
|
|
10754
|
+
}
|
|
10755
|
+
if (await branchExists(branchName)) {
|
|
10756
|
+
warn(`Branch ${import_picocolors7.default.bold(branchName)} already exists. Choose a different name.`);
|
|
10757
|
+
branchName = (await inputPrompt("Enter branch name", branchName)).trim();
|
|
10758
|
+
continue;
|
|
10759
|
+
}
|
|
10760
|
+
return branchName;
|
|
10761
|
+
}
|
|
10762
|
+
}
|
|
10763
|
+
|
|
10604
10764
|
// src/utils/gh.ts
|
|
10605
10765
|
import { execFile as execFileCb2 } from "node:child_process";
|
|
10606
10766
|
function run2(args) {
|
|
@@ -10739,53 +10899,6 @@ async function getMergedPRForBranch(headBranch) {
|
|
|
10739
10899
|
}
|
|
10740
10900
|
}
|
|
10741
10901
|
|
|
10742
|
-
// src/utils/spinner.ts
|
|
10743
|
-
var import_picocolors6 = __toESM(require_picocolors(), 1);
|
|
10744
|
-
var FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
10745
|
-
function createSpinner(text) {
|
|
10746
|
-
let frameIdx = 0;
|
|
10747
|
-
let currentText = text;
|
|
10748
|
-
let stopped = false;
|
|
10749
|
-
const clearLine = () => {
|
|
10750
|
-
process.stderr.write("\r\x1B[K");
|
|
10751
|
-
};
|
|
10752
|
-
const render = () => {
|
|
10753
|
-
if (stopped)
|
|
10754
|
-
return;
|
|
10755
|
-
const frame = import_picocolors6.default.cyan(FRAMES[frameIdx % FRAMES.length]);
|
|
10756
|
-
clearLine();
|
|
10757
|
-
process.stderr.write(`${frame} ${currentText}`);
|
|
10758
|
-
frameIdx++;
|
|
10759
|
-
};
|
|
10760
|
-
const timer = setInterval(render, 80);
|
|
10761
|
-
render();
|
|
10762
|
-
const stop = () => {
|
|
10763
|
-
if (stopped)
|
|
10764
|
-
return;
|
|
10765
|
-
stopped = true;
|
|
10766
|
-
clearInterval(timer);
|
|
10767
|
-
clearLine();
|
|
10768
|
-
};
|
|
10769
|
-
return {
|
|
10770
|
-
update(newText) {
|
|
10771
|
-
currentText = newText;
|
|
10772
|
-
},
|
|
10773
|
-
success(msg) {
|
|
10774
|
-
stop();
|
|
10775
|
-
process.stderr.write(`${import_picocolors6.default.green("✔")} ${msg}
|
|
10776
|
-
`);
|
|
10777
|
-
},
|
|
10778
|
-
fail(msg) {
|
|
10779
|
-
stop();
|
|
10780
|
-
process.stderr.write(`${import_picocolors6.default.red("✖")} ${msg}
|
|
10781
|
-
`);
|
|
10782
|
-
},
|
|
10783
|
-
stop() {
|
|
10784
|
-
stop();
|
|
10785
|
-
}
|
|
10786
|
-
};
|
|
10787
|
-
}
|
|
10788
|
-
|
|
10789
10902
|
// src/commands/clean.ts
|
|
10790
10903
|
async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
10791
10904
|
if (!config)
|
|
@@ -10798,44 +10911,22 @@ async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
|
10798
10911
|
warn("You have uncommitted changes in your working tree.");
|
|
10799
10912
|
}
|
|
10800
10913
|
if (localWork.unpushedCommits > 0) {
|
|
10801
|
-
warn(`You have ${
|
|
10914
|
+
warn(`You have ${import_picocolors8.default.bold(String(localWork.unpushedCommits))} local commit${localWork.unpushedCommits !== 1 ? "s" : ""} not pushed.`);
|
|
10802
10915
|
}
|
|
10803
10916
|
const SAVE_NEW_BRANCH = "Save changes to a new branch";
|
|
10804
10917
|
const DISCARD = "Discard all changes and clean up";
|
|
10805
10918
|
const CANCEL = "Skip this branch";
|
|
10806
|
-
const action = await selectPrompt(`${
|
|
10919
|
+
const action = await selectPrompt(`${import_picocolors8.default.bold(currentBranch)} has local changes. What would you like to do?`, [SAVE_NEW_BRANCH, DISCARD, CANCEL]);
|
|
10807
10920
|
if (action === CANCEL)
|
|
10808
10921
|
return "skipped";
|
|
10809
10922
|
if (action === SAVE_NEW_BRANCH) {
|
|
10810
10923
|
if (!config)
|
|
10811
10924
|
return "skipped";
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
const suggested = await suggestBranchName(description);
|
|
10818
|
-
if (suggested) {
|
|
10819
|
-
spinner.success("Branch name suggestion ready.");
|
|
10820
|
-
console.log(`
|
|
10821
|
-
${import_picocolors7.default.dim("AI suggestion:")} ${import_picocolors7.default.bold(import_picocolors7.default.cyan(suggested))}`);
|
|
10822
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors7.default.bold(suggested)} as your branch name?`);
|
|
10823
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
10824
|
-
} else {
|
|
10825
|
-
spinner.fail("AI did not return a suggestion.");
|
|
10826
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
10827
|
-
}
|
|
10828
|
-
}
|
|
10829
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
10830
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors7.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
10831
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
10832
|
-
}
|
|
10833
|
-
if (!isValidBranchName(newBranchName)) {
|
|
10834
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
10835
|
-
return "skipped";
|
|
10836
|
-
}
|
|
10837
|
-
if (await branchExists(newBranchName)) {
|
|
10838
|
-
error(`Branch ${import_picocolors7.default.bold(newBranchName)} already exists. Choose a different name.`);
|
|
10925
|
+
const newBranchName = await promptForBranchName({
|
|
10926
|
+
branchPrefixes: config.branchPrefixes,
|
|
10927
|
+
useAI: isAIEnabled(config)
|
|
10928
|
+
});
|
|
10929
|
+
if (!newBranchName) {
|
|
10839
10930
|
return "skipped";
|
|
10840
10931
|
}
|
|
10841
10932
|
const renameResult = await renameBranch(currentBranch, newBranchName);
|
|
@@ -10843,7 +10934,7 @@ async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
|
10843
10934
|
error(`Failed to rename branch: ${renameResult.stderr}`);
|
|
10844
10935
|
return "skipped";
|
|
10845
10936
|
}
|
|
10846
|
-
success(`Renamed ${
|
|
10937
|
+
success(`Renamed ${import_picocolors8.default.bold(currentBranch)} → ${import_picocolors8.default.bold(newBranchName)}`);
|
|
10847
10938
|
const syncSource2 = getSyncSource(config);
|
|
10848
10939
|
await fetchRemote(syncSource2.remote);
|
|
10849
10940
|
const savedUpstreamRef = await getUpstreamRef();
|
|
@@ -10851,10 +10942,10 @@ async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
|
10851
10942
|
if (rebaseResult.exitCode !== 0) {
|
|
10852
10943
|
await rebaseAbort();
|
|
10853
10944
|
warn("Rebase had conflicts — aborted to keep the repo in a clean state.");
|
|
10854
|
-
info(`Your work is saved on ${
|
|
10855
|
-
info(` ${
|
|
10945
|
+
info(`Your work is saved on ${import_picocolors8.default.bold(newBranchName)}. After cleanup, rebase manually:`, "");
|
|
10946
|
+
info(` ${import_picocolors8.default.bold(`git checkout ${newBranchName} && git rebase ${syncSource2.ref}`)}`, "");
|
|
10856
10947
|
} else {
|
|
10857
|
-
success(`Rebased ${
|
|
10948
|
+
success(`Rebased ${import_picocolors8.default.bold(newBranchName)} onto ${import_picocolors8.default.bold(syncSource2.ref)}.`);
|
|
10858
10949
|
}
|
|
10859
10950
|
const coResult2 = await checkoutBranch(baseBranch);
|
|
10860
10951
|
if (coResult2.exitCode !== 0) {
|
|
@@ -10862,12 +10953,12 @@ async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
|
10862
10953
|
return "saved";
|
|
10863
10954
|
}
|
|
10864
10955
|
await updateLocalBranch(baseBranch, syncSource2.ref);
|
|
10865
|
-
success(`Synced ${
|
|
10956
|
+
success(`Synced ${import_picocolors8.default.bold(baseBranch)} with ${import_picocolors8.default.bold(syncSource2.ref)}.`);
|
|
10866
10957
|
return "saved";
|
|
10867
10958
|
}
|
|
10868
10959
|
}
|
|
10869
10960
|
const syncSource = getSyncSource(config);
|
|
10870
|
-
info(`Switching to ${
|
|
10961
|
+
info(`Switching to ${import_picocolors8.default.bold(baseBranch)} and syncing...`);
|
|
10871
10962
|
await fetchRemote(syncSource.remote);
|
|
10872
10963
|
await resetHard("HEAD");
|
|
10873
10964
|
const coResult = await checkoutBranch(baseBranch);
|
|
@@ -10876,7 +10967,7 @@ async function handleCurrentBranchDeletion(currentBranch, baseBranch, config) {
|
|
|
10876
10967
|
return "skipped";
|
|
10877
10968
|
}
|
|
10878
10969
|
await updateLocalBranch(baseBranch, syncSource.ref);
|
|
10879
|
-
success(`Synced ${
|
|
10970
|
+
success(`Synced ${import_picocolors8.default.bold(baseBranch)} with ${import_picocolors8.default.bold(syncSource.ref)}.`);
|
|
10880
10971
|
return "switched";
|
|
10881
10972
|
}
|
|
10882
10973
|
var clean_default = defineCommand({
|
|
@@ -10906,7 +10997,7 @@ var clean_default = defineCommand({
|
|
|
10906
10997
|
const { origin } = config;
|
|
10907
10998
|
const baseBranch = getBaseBranch(config);
|
|
10908
10999
|
let currentBranch = await getCurrentBranch();
|
|
10909
|
-
|
|
11000
|
+
projectHeading("clean", "\uD83E\uDDF9");
|
|
10910
11001
|
info(`Pruning ${origin} remote refs...`);
|
|
10911
11002
|
const pruneResult = await pruneRemote(origin);
|
|
10912
11003
|
if (pruneResult.exitCode === 0) {
|
|
@@ -10926,21 +11017,21 @@ var clean_default = defineCommand({
|
|
|
10926
11017
|
if (ghInstalled && ghAuthed) {
|
|
10927
11018
|
const mergedPR = await getMergedPRForBranch(currentBranch);
|
|
10928
11019
|
if (mergedPR) {
|
|
10929
|
-
warn(`PR #${mergedPR.number} (${
|
|
10930
|
-
info(`Link: ${
|
|
11020
|
+
warn(`PR #${mergedPR.number} (${import_picocolors8.default.bold(mergedPR.title)}) has already been merged.`);
|
|
11021
|
+
info(`Link: ${import_picocolors8.default.underline(mergedPR.url)}`, "");
|
|
10931
11022
|
goneCandidates.push(currentBranch);
|
|
10932
11023
|
}
|
|
10933
11024
|
}
|
|
10934
11025
|
}
|
|
10935
11026
|
if (mergedCandidates.length > 0) {
|
|
10936
11027
|
console.log(`
|
|
10937
|
-
${
|
|
11028
|
+
${import_picocolors8.default.bold("Merged branches to delete:")}`);
|
|
10938
11029
|
for (const b2 of mergedCandidates) {
|
|
10939
|
-
const marker = b2 === currentBranch ?
|
|
10940
|
-
console.log(` ${
|
|
11030
|
+
const marker = b2 === currentBranch ? import_picocolors8.default.yellow(" (current)") : "";
|
|
11031
|
+
console.log(` ${import_picocolors8.default.dim("•")} ${b2}${marker}`);
|
|
10941
11032
|
}
|
|
10942
11033
|
console.log();
|
|
10943
|
-
const ok = args.yes || await confirmPrompt(`Delete ${
|
|
11034
|
+
const ok = args.yes || await confirmPrompt(`Delete ${import_picocolors8.default.bold(String(mergedCandidates.length))} merged branch${mergedCandidates.length !== 1 ? "es" : ""}?`);
|
|
10944
11035
|
if (ok) {
|
|
10945
11036
|
for (const branch of mergedCandidates) {
|
|
10946
11037
|
if (branch === currentBranch) {
|
|
@@ -10957,7 +11048,7 @@ ${import_picocolors7.default.bold("Merged branches to delete:")}`);
|
|
|
10957
11048
|
}
|
|
10958
11049
|
const result = await deleteBranch(branch);
|
|
10959
11050
|
if (result.exitCode === 0) {
|
|
10960
|
-
success(` Deleted ${
|
|
11051
|
+
success(` Deleted ${import_picocolors8.default.bold(branch)}`);
|
|
10961
11052
|
} else {
|
|
10962
11053
|
warn(` Failed to delete ${branch}: ${result.stderr.trim()}`);
|
|
10963
11054
|
}
|
|
@@ -10968,13 +11059,13 @@ ${import_picocolors7.default.bold("Merged branches to delete:")}`);
|
|
|
10968
11059
|
}
|
|
10969
11060
|
if (goneCandidates.length > 0) {
|
|
10970
11061
|
console.log(`
|
|
10971
|
-
${
|
|
11062
|
+
${import_picocolors8.default.bold("Stale branches (remote deleted, likely squash-merged):")}`);
|
|
10972
11063
|
for (const b2 of goneCandidates) {
|
|
10973
|
-
const marker = b2 === currentBranch ?
|
|
10974
|
-
console.log(` ${
|
|
11064
|
+
const marker = b2 === currentBranch ? import_picocolors8.default.yellow(" (current)") : "";
|
|
11065
|
+
console.log(` ${import_picocolors8.default.dim("•")} ${b2}${marker}`);
|
|
10975
11066
|
}
|
|
10976
11067
|
console.log();
|
|
10977
|
-
const ok = args.yes || await confirmPrompt(`Delete ${
|
|
11068
|
+
const ok = args.yes || await confirmPrompt(`Delete ${import_picocolors8.default.bold(String(goneCandidates.length))} stale branch${goneCandidates.length !== 1 ? "es" : ""}?`);
|
|
10978
11069
|
if (ok) {
|
|
10979
11070
|
for (const branch of goneCandidates) {
|
|
10980
11071
|
if (branch === currentBranch) {
|
|
@@ -10991,7 +11082,7 @@ ${import_picocolors7.default.bold("Stale branches (remote deleted, likely squash
|
|
|
10991
11082
|
}
|
|
10992
11083
|
const result = await forceDeleteBranch(branch);
|
|
10993
11084
|
if (result.exitCode === 0) {
|
|
10994
|
-
success(` Deleted ${
|
|
11085
|
+
success(` Deleted ${import_picocolors8.default.bold(branch)}`);
|
|
10995
11086
|
} else {
|
|
10996
11087
|
warn(` Failed to delete ${branch}: ${result.stderr.trim()}`);
|
|
10997
11088
|
}
|
|
@@ -11006,13 +11097,13 @@ ${import_picocolors7.default.bold("Stale branches (remote deleted, likely squash
|
|
|
11006
11097
|
const finalBranch = await getCurrentBranch();
|
|
11007
11098
|
if (finalBranch && protectedBranches.has(finalBranch)) {
|
|
11008
11099
|
console.log();
|
|
11009
|
-
info(`You're on ${
|
|
11100
|
+
info(`You're on ${import_picocolors8.default.bold(finalBranch)}. Run ${import_picocolors8.default.bold("contrib start")} to begin a new feature.`);
|
|
11010
11101
|
}
|
|
11011
11102
|
}
|
|
11012
11103
|
});
|
|
11013
11104
|
|
|
11014
11105
|
// src/commands/commit.ts
|
|
11015
|
-
var
|
|
11106
|
+
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
11016
11107
|
|
|
11017
11108
|
// src/utils/convention.ts
|
|
11018
11109
|
var CLEAN_COMMIT_PATTERN = /^(📦|🔧|🗑\uFE0F?|🔒|⚙\uFE0F?|☕|🧪|📖|🚀) (new|update|remove|security|setup|chore|test|docs|release)(!?)( \([a-zA-Z0-9][a-zA-Z0-9-]*\))?: .{1,72}$/u;
|
|
@@ -11098,8 +11189,13 @@ var commit_default = defineCommand({
|
|
|
11098
11189
|
error("No .contributerc.json found. Run `contrib setup` first.");
|
|
11099
11190
|
process.exit(1);
|
|
11100
11191
|
}
|
|
11101
|
-
|
|
11192
|
+
projectHeading("commit", "\uD83D\uDCBE");
|
|
11193
|
+
const aiEnabled = isAIEnabled(config, args["no-ai"]);
|
|
11102
11194
|
if (args.group) {
|
|
11195
|
+
if (!aiEnabled) {
|
|
11196
|
+
error("AI group commit is unavailable because AI is disabled. Re-run without --group or enable AI in .contributerc.json.");
|
|
11197
|
+
process.exit(1);
|
|
11198
|
+
}
|
|
11103
11199
|
await runGroupCommit(args.model, config);
|
|
11104
11200
|
return;
|
|
11105
11201
|
}
|
|
@@ -11111,9 +11207,9 @@ var commit_default = defineCommand({
|
|
|
11111
11207
|
process.exit(1);
|
|
11112
11208
|
}
|
|
11113
11209
|
console.log(`
|
|
11114
|
-
${
|
|
11210
|
+
${import_picocolors9.default.bold("Changed files:")}`);
|
|
11115
11211
|
for (const f3 of changedFiles) {
|
|
11116
|
-
console.log(` ${
|
|
11212
|
+
console.log(` ${import_picocolors9.default.dim("•")} ${f3}`);
|
|
11117
11213
|
}
|
|
11118
11214
|
const stageAction = await selectPrompt("No staged changes. How would you like to stage?", [
|
|
11119
11215
|
"Stage all changes",
|
|
@@ -11155,8 +11251,8 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11155
11251
|
const dirs = new Set(stagedFiles.map((f3) => f3.split("/")[0]));
|
|
11156
11252
|
if (dirs.size > 1) {
|
|
11157
11253
|
console.log();
|
|
11158
|
-
warn(`You're staging ${
|
|
11159
|
-
info(
|
|
11254
|
+
warn(`You're staging ${import_picocolors9.default.bold(String(stagedFiles.length))} files across ${import_picocolors9.default.bold(String(dirs.size))} directories in a single commit.`);
|
|
11255
|
+
info(import_picocolors9.default.dim("Large commits mixing different topics make history harder to read and bisect. " + "For cleaner history, consider splitting into atomic commits."));
|
|
11160
11256
|
const choice = await selectPrompt("How would you like to proceed?", [
|
|
11161
11257
|
"Continue as single commit",
|
|
11162
11258
|
"Switch to group mode (AI splits into atomic commits)",
|
|
@@ -11172,9 +11268,9 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11172
11268
|
}
|
|
11173
11269
|
}
|
|
11174
11270
|
let commitMessage = null;
|
|
11175
|
-
const useAI =
|
|
11271
|
+
const useAI = aiEnabled;
|
|
11176
11272
|
if (useAI) {
|
|
11177
|
-
const [copilotError, diff] = await Promise.all([
|
|
11273
|
+
const [copilotError, diff] = await Promise.all([checkCopilotAvailable2(), getStagedDiff()]);
|
|
11178
11274
|
if (copilotError) {
|
|
11179
11275
|
warn(`AI unavailable: ${copilotError}`);
|
|
11180
11276
|
warn("Falling back to manual commit message entry.");
|
|
@@ -11185,7 +11281,7 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11185
11281
|
if (commitMessage) {
|
|
11186
11282
|
spinner.success("AI commit message generated.");
|
|
11187
11283
|
console.log(`
|
|
11188
|
-
${
|
|
11284
|
+
${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(commitMessage))}`);
|
|
11189
11285
|
} else {
|
|
11190
11286
|
spinner.fail("AI did not return a commit message.");
|
|
11191
11287
|
warn("Falling back to manual entry.");
|
|
@@ -11211,7 +11307,7 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11211
11307
|
if (regen) {
|
|
11212
11308
|
spinner.success("Commit message regenerated.");
|
|
11213
11309
|
console.log(`
|
|
11214
|
-
${
|
|
11310
|
+
${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(regen))}`);
|
|
11215
11311
|
const ok = await confirmPrompt("Use this message?");
|
|
11216
11312
|
finalMessage = ok ? regen : await inputPrompt("Enter commit message manually");
|
|
11217
11313
|
} else {
|
|
@@ -11226,7 +11322,7 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11226
11322
|
if (convention2 !== "none") {
|
|
11227
11323
|
console.log();
|
|
11228
11324
|
for (const hint of CONVENTION_FORMAT_HINTS[convention2]) {
|
|
11229
|
-
console.log(
|
|
11325
|
+
console.log(import_picocolors9.default.dim(hint));
|
|
11230
11326
|
}
|
|
11231
11327
|
console.log();
|
|
11232
11328
|
}
|
|
@@ -11250,7 +11346,7 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11250
11346
|
error(`Failed to commit: ${result.stderr}`);
|
|
11251
11347
|
process.exit(1);
|
|
11252
11348
|
}
|
|
11253
|
-
success(`Committed: ${
|
|
11349
|
+
success(`Committed: ${import_picocolors9.default.bold(finalMessage)}`);
|
|
11254
11350
|
}
|
|
11255
11351
|
});
|
|
11256
11352
|
function getFallbackGroupMessage(convention) {
|
|
@@ -11264,7 +11360,7 @@ function getFallbackGroupMessage(convention) {
|
|
|
11264
11360
|
}
|
|
11265
11361
|
async function runGroupCommit(model, config) {
|
|
11266
11362
|
const [copilotError, changedFiles] = await Promise.all([
|
|
11267
|
-
|
|
11363
|
+
checkCopilotAvailable2(),
|
|
11268
11364
|
getChangedFiles()
|
|
11269
11365
|
]);
|
|
11270
11366
|
if (copilotError) {
|
|
@@ -11276,9 +11372,9 @@ async function runGroupCommit(model, config) {
|
|
|
11276
11372
|
process.exit(1);
|
|
11277
11373
|
}
|
|
11278
11374
|
console.log(`
|
|
11279
|
-
${
|
|
11375
|
+
${import_picocolors9.default.bold("Changed files:")}`);
|
|
11280
11376
|
for (const f3 of changedFiles) {
|
|
11281
|
-
console.log(` ${
|
|
11377
|
+
console.log(` ${import_picocolors9.default.dim("•")} ${f3}`);
|
|
11282
11378
|
}
|
|
11283
11379
|
const spinner = createSpinner(changedFiles.length >= BATCH_CONFIG.LARGE_CHANGESET_THRESHOLD ? `Asking AI to group ${changedFiles.length} file(s) into logical commits (using optimized batching)...` : `Asking AI to group ${changedFiles.length} file(s) into logical commits...`);
|
|
11284
11380
|
const diffs = await getFullDiffForFiles(changedFiles);
|
|
@@ -11326,13 +11422,13 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11326
11422
|
let commitAll = false;
|
|
11327
11423
|
while (!proceedToCommit) {
|
|
11328
11424
|
console.log(`
|
|
11329
|
-
${
|
|
11425
|
+
${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit group(s):`)}
|
|
11330
11426
|
`);
|
|
11331
11427
|
for (let i2 = 0;i2 < validGroups.length; i2++) {
|
|
11332
11428
|
const g3 = validGroups[i2];
|
|
11333
|
-
console.log(` ${
|
|
11429
|
+
console.log(` ${import_picocolors9.default.cyan(`Group ${i2 + 1}:`)} ${import_picocolors9.default.bold(g3.message)}`);
|
|
11334
11430
|
for (const f3 of g3.files) {
|
|
11335
|
-
console.log(` ${
|
|
11431
|
+
console.log(` ${import_picocolors9.default.dim("•")} ${f3}`);
|
|
11336
11432
|
}
|
|
11337
11433
|
console.log();
|
|
11338
11434
|
}
|
|
@@ -11386,16 +11482,16 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11386
11482
|
continue;
|
|
11387
11483
|
}
|
|
11388
11484
|
committed++;
|
|
11389
|
-
success(`Committed group ${i2 + 1}: ${
|
|
11485
|
+
success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(group.message)}`);
|
|
11390
11486
|
}
|
|
11391
11487
|
} else {
|
|
11392
11488
|
for (let i2 = 0;i2 < validGroups.length; i2++) {
|
|
11393
11489
|
const group = validGroups[i2];
|
|
11394
|
-
console.log(
|
|
11490
|
+
console.log(import_picocolors9.default.bold(`
|
|
11395
11491
|
── Group ${i2 + 1}/${validGroups.length} ──`));
|
|
11396
|
-
console.log(` ${
|
|
11492
|
+
console.log(` ${import_picocolors9.default.cyan(group.message)}`);
|
|
11397
11493
|
for (const f3 of group.files) {
|
|
11398
|
-
console.log(` ${
|
|
11494
|
+
console.log(` ${import_picocolors9.default.dim("•")} ${f3}`);
|
|
11399
11495
|
}
|
|
11400
11496
|
let message = group.message;
|
|
11401
11497
|
let actionDone = false;
|
|
@@ -11417,7 +11513,7 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11417
11513
|
if (newMsg) {
|
|
11418
11514
|
message = newMsg;
|
|
11419
11515
|
group.message = newMsg;
|
|
11420
|
-
regenSpinner.success(`New message: ${
|
|
11516
|
+
regenSpinner.success(`New message: ${import_picocolors9.default.bold(message)}`);
|
|
11421
11517
|
} else {
|
|
11422
11518
|
regenSpinner.fail("AI could not generate a new message. Keeping current one.");
|
|
11423
11519
|
}
|
|
@@ -11468,7 +11564,7 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11468
11564
|
continue;
|
|
11469
11565
|
}
|
|
11470
11566
|
committed++;
|
|
11471
|
-
success(`Committed group ${i2 + 1}: ${
|
|
11567
|
+
success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(message)}`);
|
|
11472
11568
|
actionDone = true;
|
|
11473
11569
|
}
|
|
11474
11570
|
}
|
|
@@ -11484,11 +11580,11 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11484
11580
|
|
|
11485
11581
|
// src/commands/doctor.ts
|
|
11486
11582
|
import { execFile as execFileCb3 } from "node:child_process";
|
|
11487
|
-
var
|
|
11583
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
11488
11584
|
// package.json
|
|
11489
11585
|
var package_default = {
|
|
11490
11586
|
name: "contribute-now",
|
|
11491
|
-
version: "0.6.2-dev.
|
|
11587
|
+
version: "0.6.2-dev.967437a",
|
|
11492
11588
|
description: "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
|
|
11493
11589
|
type: "module",
|
|
11494
11590
|
bin: {
|
|
@@ -11579,16 +11675,16 @@ async function getRepoInfoFromRemote(remote = "origin") {
|
|
|
11579
11675
|
}
|
|
11580
11676
|
|
|
11581
11677
|
// src/commands/doctor.ts
|
|
11582
|
-
var PASS = ` ${
|
|
11583
|
-
var FAIL = ` ${
|
|
11584
|
-
var WARN = ` ${
|
|
11678
|
+
var PASS = ` ${import_picocolors10.default.green("✔")} `;
|
|
11679
|
+
var FAIL = ` ${import_picocolors10.default.red("✗")} `;
|
|
11680
|
+
var WARN = ` ${import_picocolors10.default.yellow("⚠")} `;
|
|
11585
11681
|
function printReport(report) {
|
|
11586
11682
|
for (const section of report.sections) {
|
|
11587
11683
|
console.log(`
|
|
11588
|
-
${
|
|
11684
|
+
${import_picocolors10.default.bold(import_picocolors10.default.underline(section.title))}`);
|
|
11589
11685
|
for (const check of section.checks) {
|
|
11590
11686
|
const prefix = check.ok ? check.warning ? WARN : PASS : FAIL;
|
|
11591
|
-
const text = check.detail ? `${check.label} ${
|
|
11687
|
+
const text = check.detail ? `${check.label} ${import_picocolors10.default.dim(`— ${check.detail}`)}` : check.label;
|
|
11592
11688
|
console.log(`${prefix}${text}`);
|
|
11593
11689
|
}
|
|
11594
11690
|
}
|
|
@@ -11851,20 +11947,20 @@ var doctor_default = defineCommand({
|
|
|
11851
11947
|
console.log(toJson(report));
|
|
11852
11948
|
return;
|
|
11853
11949
|
}
|
|
11854
|
-
|
|
11950
|
+
projectHeading("doctor", "\uD83E\uDE7A");
|
|
11855
11951
|
printReport(report);
|
|
11856
11952
|
const total = report.sections.flatMap((s2) => s2.checks);
|
|
11857
11953
|
const failures = total.filter((c3) => !c3.ok);
|
|
11858
11954
|
const warnings = total.filter((c3) => c3.ok && c3.warning);
|
|
11859
11955
|
if (failures.length === 0 && warnings.length === 0) {
|
|
11860
|
-
console.log(` ${
|
|
11956
|
+
console.log(` ${import_picocolors10.default.green("All checks passed!")} No issues detected.
|
|
11861
11957
|
`);
|
|
11862
11958
|
} else {
|
|
11863
11959
|
if (failures.length > 0) {
|
|
11864
|
-
console.log(` ${
|
|
11960
|
+
console.log(` ${import_picocolors10.default.red(`${failures.length} issue${failures.length !== 1 ? "s" : ""} found.`)}`);
|
|
11865
11961
|
}
|
|
11866
11962
|
if (warnings.length > 0) {
|
|
11867
|
-
console.log(` ${
|
|
11963
|
+
console.log(` ${import_picocolors10.default.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}.`)}`);
|
|
11868
11964
|
}
|
|
11869
11965
|
console.log();
|
|
11870
11966
|
}
|
|
@@ -11874,7 +11970,7 @@ var doctor_default = defineCommand({
|
|
|
11874
11970
|
// src/commands/hook.ts
|
|
11875
11971
|
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
11876
11972
|
import { join as join4 } from "node:path";
|
|
11877
|
-
var
|
|
11973
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
11878
11974
|
var HOOK_MARKER = "# managed by contribute-now";
|
|
11879
11975
|
function getHooksDir(cwd = process.cwd()) {
|
|
11880
11976
|
return join4(cwd, ".git", "hooks");
|
|
@@ -11942,7 +12038,7 @@ var hook_default = defineCommand({
|
|
|
11942
12038
|
}
|
|
11943
12039
|
});
|
|
11944
12040
|
async function installHook() {
|
|
11945
|
-
|
|
12041
|
+
projectHeading("hook install", "\uD83E\uDE9D");
|
|
11946
12042
|
const config = readConfig();
|
|
11947
12043
|
if (!config) {
|
|
11948
12044
|
error("No .contributerc.json found. Run `contrib setup` first.");
|
|
@@ -11970,12 +12066,12 @@ async function installHook() {
|
|
|
11970
12066
|
}
|
|
11971
12067
|
writeFileSync3(hookPath, generateHookScript(), { mode: 493 });
|
|
11972
12068
|
success(`commit-msg hook installed.`);
|
|
11973
|
-
info(`Convention: ${
|
|
11974
|
-
info(`Path: ${
|
|
12069
|
+
info(`Convention: ${import_picocolors11.default.bold(CONVENTION_LABELS[config.commitConvention])}`, "");
|
|
12070
|
+
info(`Path: ${import_picocolors11.default.dim(hookPath)}`, "");
|
|
11975
12071
|
warn("Note: hooks can be bypassed with `git commit --no-verify`.");
|
|
11976
12072
|
}
|
|
11977
12073
|
async function uninstallHook() {
|
|
11978
|
-
|
|
12074
|
+
projectHeading("hook uninstall", "\uD83E\uDE9D");
|
|
11979
12075
|
const hookPath = getHookPath();
|
|
11980
12076
|
if (!existsSync4(hookPath)) {
|
|
11981
12077
|
info("No commit-msg hook found. Nothing to uninstall.");
|
|
@@ -11991,7 +12087,7 @@ async function uninstallHook() {
|
|
|
11991
12087
|
}
|
|
11992
12088
|
|
|
11993
12089
|
// src/commands/log.ts
|
|
11994
|
-
var
|
|
12090
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
11995
12091
|
var log_default = defineCommand({
|
|
11996
12092
|
meta: {
|
|
11997
12093
|
name: "log",
|
|
@@ -12061,14 +12157,14 @@ var log_default = defineCommand({
|
|
|
12061
12157
|
usingFallback = true;
|
|
12062
12158
|
}
|
|
12063
12159
|
}
|
|
12064
|
-
|
|
12160
|
+
projectHeading("log", "\uD83D\uDCDC");
|
|
12065
12161
|
printModeHeader(mode, currentBranch, compareRef, usingFallback);
|
|
12066
12162
|
if (mode === "local" || mode === "remote") {
|
|
12067
12163
|
if (!compareRef) {
|
|
12068
12164
|
console.log();
|
|
12069
|
-
console.log(
|
|
12070
|
-
console.log(
|
|
12071
|
-
console.log(
|
|
12165
|
+
console.log(import_picocolors12.default.yellow(" ⚠ Could not determine a comparison branch."));
|
|
12166
|
+
console.log(import_picocolors12.default.dim(" No upstream tracking set and no remote base branch found."));
|
|
12167
|
+
console.log(import_picocolors12.default.dim(` Use ${import_picocolors12.default.bold("contrib log --full")} to see the full commit history instead.`));
|
|
12072
12168
|
console.log();
|
|
12073
12169
|
printGuidance();
|
|
12074
12170
|
return;
|
|
@@ -12110,26 +12206,26 @@ async function resolveBaseBranchRef(config) {
|
|
|
12110
12206
|
}
|
|
12111
12207
|
function printModeHeader(mode, currentBranch, compareRef, usingFallback = false) {
|
|
12112
12208
|
const branch = currentBranch ?? "HEAD";
|
|
12113
|
-
const fallbackNote = usingFallback ?
|
|
12209
|
+
const fallbackNote = usingFallback ? import_picocolors12.default.yellow(" (no upstream — comparing against base branch)") : "";
|
|
12114
12210
|
console.log();
|
|
12115
12211
|
switch (mode) {
|
|
12116
12212
|
case "local":
|
|
12117
|
-
console.log(
|
|
12213
|
+
console.log(import_picocolors12.default.dim(` mode: ${import_picocolors12.default.bold("local")} — unpushed commits on ${import_picocolors12.default.bold(branch)}`) + fallbackNote);
|
|
12118
12214
|
if (compareRef) {
|
|
12119
|
-
console.log(
|
|
12215
|
+
console.log(import_picocolors12.default.dim(` comparing: ${import_picocolors12.default.bold(compareRef)} ➜ ${import_picocolors12.default.bold("HEAD")}`));
|
|
12120
12216
|
}
|
|
12121
12217
|
break;
|
|
12122
12218
|
case "remote":
|
|
12123
|
-
console.log(
|
|
12219
|
+
console.log(import_picocolors12.default.dim(` mode: ${import_picocolors12.default.bold("remote")} — commits on remote not yet pulled into ${import_picocolors12.default.bold(branch)}`) + fallbackNote);
|
|
12124
12220
|
if (compareRef) {
|
|
12125
|
-
console.log(
|
|
12221
|
+
console.log(import_picocolors12.default.dim(` comparing: ${import_picocolors12.default.bold("HEAD")} ➜ ${import_picocolors12.default.bold(compareRef)}`));
|
|
12126
12222
|
}
|
|
12127
12223
|
break;
|
|
12128
12224
|
case "full":
|
|
12129
|
-
console.log(
|
|
12225
|
+
console.log(import_picocolors12.default.dim(` mode: ${import_picocolors12.default.bold("full")} — complete commit history for ${import_picocolors12.default.bold(branch)}`));
|
|
12130
12226
|
break;
|
|
12131
12227
|
case "all":
|
|
12132
|
-
console.log(
|
|
12228
|
+
console.log(import_picocolors12.default.dim(` mode: ${import_picocolors12.default.bold("all")} — commits across all branches`));
|
|
12133
12229
|
break;
|
|
12134
12230
|
}
|
|
12135
12231
|
}
|
|
@@ -12155,7 +12251,7 @@ async function renderScopedLog(options) {
|
|
|
12155
12251
|
}
|
|
12156
12252
|
console.log();
|
|
12157
12253
|
for (const entry of entries) {
|
|
12158
|
-
const hashStr =
|
|
12254
|
+
const hashStr = import_picocolors12.default.yellow(entry.hash);
|
|
12159
12255
|
const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
|
|
12160
12256
|
const subjectStr = colorizeSubject(entry.subject);
|
|
12161
12257
|
console.log(` ${hashStr}${refsStr} ${subjectStr}`);
|
|
@@ -12166,9 +12262,9 @@ async function renderScopedLog(options) {
|
|
|
12166
12262
|
function printEmptyState(mode) {
|
|
12167
12263
|
console.log();
|
|
12168
12264
|
if (mode === "local") {
|
|
12169
|
-
console.log(
|
|
12265
|
+
console.log(import_picocolors12.default.dim(" No local unpushed commits — you're up to date with remote!"));
|
|
12170
12266
|
} else {
|
|
12171
|
-
console.log(
|
|
12267
|
+
console.log(import_picocolors12.default.dim(" No remote-only commits — your local branch is up to date!"));
|
|
12172
12268
|
}
|
|
12173
12269
|
console.log();
|
|
12174
12270
|
}
|
|
@@ -12177,7 +12273,7 @@ async function renderFullLog(options) {
|
|
|
12177
12273
|
if (showGraph) {
|
|
12178
12274
|
const lines = await getLogGraph({ count, all, branch: targetBranch });
|
|
12179
12275
|
if (lines.length === 0) {
|
|
12180
|
-
console.log(
|
|
12276
|
+
console.log(import_picocolors12.default.dim(" No commits found."));
|
|
12181
12277
|
console.log();
|
|
12182
12278
|
return false;
|
|
12183
12279
|
}
|
|
@@ -12188,13 +12284,13 @@ async function renderFullLog(options) {
|
|
|
12188
12284
|
} else {
|
|
12189
12285
|
const entries = await getLogEntries({ count, all, branch: targetBranch });
|
|
12190
12286
|
if (entries.length === 0) {
|
|
12191
|
-
console.log(
|
|
12287
|
+
console.log(import_picocolors12.default.dim(" No commits found."));
|
|
12192
12288
|
console.log();
|
|
12193
12289
|
return false;
|
|
12194
12290
|
}
|
|
12195
12291
|
console.log();
|
|
12196
12292
|
for (const entry of entries) {
|
|
12197
|
-
const hashStr =
|
|
12293
|
+
const hashStr = import_picocolors12.default.yellow(entry.hash);
|
|
12198
12294
|
const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
|
|
12199
12295
|
const subjectStr = colorizeSubject(entry.subject);
|
|
12200
12296
|
console.log(` ${hashStr}${refsStr} ${subjectStr}`);
|
|
@@ -12206,42 +12302,42 @@ function printFooter(mode, count, targetBranch) {
|
|
|
12206
12302
|
console.log();
|
|
12207
12303
|
switch (mode) {
|
|
12208
12304
|
case "local":
|
|
12209
|
-
console.log(
|
|
12305
|
+
console.log(import_picocolors12.default.dim(` Showing up to ${count} unpushed commits`));
|
|
12210
12306
|
break;
|
|
12211
12307
|
case "remote":
|
|
12212
|
-
console.log(
|
|
12308
|
+
console.log(import_picocolors12.default.dim(` Showing up to ${count} remote-only commits`));
|
|
12213
12309
|
break;
|
|
12214
12310
|
case "full":
|
|
12215
|
-
console.log(
|
|
12311
|
+
console.log(import_picocolors12.default.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
|
|
12216
12312
|
break;
|
|
12217
12313
|
case "all":
|
|
12218
|
-
console.log(
|
|
12314
|
+
console.log(import_picocolors12.default.dim(` Showing ${count} most recent commits (all branches)`));
|
|
12219
12315
|
break;
|
|
12220
12316
|
}
|
|
12221
12317
|
}
|
|
12222
12318
|
function printGuidance() {
|
|
12223
12319
|
console.log();
|
|
12224
|
-
console.log(
|
|
12225
|
-
console.log(
|
|
12226
|
-
console.log(
|
|
12227
|
-
console.log(
|
|
12228
|
-
console.log(
|
|
12229
|
-
console.log(
|
|
12230
|
-
console.log(
|
|
12231
|
-
console.log(
|
|
12320
|
+
console.log(import_picocolors12.default.dim(" ─── quick guide ───"));
|
|
12321
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log")} local unpushed commits (default)`));
|
|
12322
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log --remote")} commits on remote not yet pulled`));
|
|
12323
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log --full")} full history for the current branch`));
|
|
12324
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log --all")} commits across all branches`));
|
|
12325
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log -n 50")} change the commit limit (default: 20)`));
|
|
12326
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log -b dev")} view log for a specific branch`));
|
|
12327
|
+
console.log(import_picocolors12.default.dim(` ${import_picocolors12.default.bold("contrib log --no-graph")} flat list without graph lines`));
|
|
12232
12328
|
console.log();
|
|
12233
12329
|
}
|
|
12234
12330
|
function colorizeGraphLine(line, protectedBranches, currentBranch) {
|
|
12235
12331
|
const match = line.match(/^([|/\\*\s_.-]*)([a-f0-9]{7,12})(\s+\(([^)]+)\))?\s*(.*)/);
|
|
12236
12332
|
if (!match) {
|
|
12237
|
-
return
|
|
12333
|
+
return import_picocolors12.default.cyan(line);
|
|
12238
12334
|
}
|
|
12239
12335
|
const [, graphPart = "", hash, , refs, subject = ""] = match;
|
|
12240
12336
|
const parts = [];
|
|
12241
12337
|
if (graphPart) {
|
|
12242
12338
|
parts.push(colorizeGraphChars(graphPart));
|
|
12243
12339
|
}
|
|
12244
|
-
parts.push(
|
|
12340
|
+
parts.push(import_picocolors12.default.yellow(hash));
|
|
12245
12341
|
if (refs) {
|
|
12246
12342
|
parts.push(` (${colorizeRefs(refs, protectedBranches, currentBranch)})`);
|
|
12247
12343
|
}
|
|
@@ -12252,15 +12348,15 @@ function colorizeGraphChars(graphPart) {
|
|
|
12252
12348
|
return graphPart.split("").map((ch) => {
|
|
12253
12349
|
switch (ch) {
|
|
12254
12350
|
case "*":
|
|
12255
|
-
return
|
|
12351
|
+
return import_picocolors12.default.green(ch);
|
|
12256
12352
|
case "|":
|
|
12257
|
-
return
|
|
12353
|
+
return import_picocolors12.default.cyan(ch);
|
|
12258
12354
|
case "/":
|
|
12259
12355
|
case "\\":
|
|
12260
|
-
return
|
|
12356
|
+
return import_picocolors12.default.cyan(ch);
|
|
12261
12357
|
case "-":
|
|
12262
12358
|
case "_":
|
|
12263
|
-
return
|
|
12359
|
+
return import_picocolors12.default.cyan(ch);
|
|
12264
12360
|
default:
|
|
12265
12361
|
return ch;
|
|
12266
12362
|
}
|
|
@@ -12272,45 +12368,45 @@ function colorizeRefs(refs, protectedBranches, currentBranch) {
|
|
|
12272
12368
|
if (trimmed.startsWith("HEAD ->") || trimmed === "HEAD") {
|
|
12273
12369
|
const branchName = trimmed.replace("HEAD -> ", "");
|
|
12274
12370
|
if (trimmed === "HEAD") {
|
|
12275
|
-
return
|
|
12371
|
+
return import_picocolors12.default.bold(import_picocolors12.default.cyan("HEAD"));
|
|
12276
12372
|
}
|
|
12277
|
-
return `${
|
|
12373
|
+
return `${import_picocolors12.default.bold(import_picocolors12.default.cyan("HEAD"))} ${import_picocolors12.default.dim("->")} ${colorizeRefName(branchName, protectedBranches, currentBranch)}`;
|
|
12278
12374
|
}
|
|
12279
12375
|
if (trimmed.startsWith("tag:")) {
|
|
12280
|
-
return
|
|
12376
|
+
return import_picocolors12.default.bold(import_picocolors12.default.magenta(trimmed));
|
|
12281
12377
|
}
|
|
12282
12378
|
return colorizeRefName(trimmed, protectedBranches, currentBranch);
|
|
12283
|
-
}).join(
|
|
12379
|
+
}).join(import_picocolors12.default.dim(", "));
|
|
12284
12380
|
}
|
|
12285
12381
|
function colorizeRefName(name, protectedBranches, currentBranch) {
|
|
12286
12382
|
const isRemote = name.includes("/");
|
|
12287
12383
|
const localName = isRemote ? name.split("/").slice(1).join("/") : name;
|
|
12288
12384
|
if (protectedBranches.includes(localName)) {
|
|
12289
|
-
return isRemote ?
|
|
12385
|
+
return isRemote ? import_picocolors12.default.bold(import_picocolors12.default.red(name)) : import_picocolors12.default.bold(import_picocolors12.default.red(name));
|
|
12290
12386
|
}
|
|
12291
12387
|
if (localName === currentBranch) {
|
|
12292
|
-
return
|
|
12388
|
+
return import_picocolors12.default.bold(import_picocolors12.default.green(name));
|
|
12293
12389
|
}
|
|
12294
12390
|
if (isRemote) {
|
|
12295
|
-
return
|
|
12391
|
+
return import_picocolors12.default.blue(name);
|
|
12296
12392
|
}
|
|
12297
|
-
return
|
|
12393
|
+
return import_picocolors12.default.green(name);
|
|
12298
12394
|
}
|
|
12299
12395
|
function colorizeSubject(subject) {
|
|
12300
12396
|
const emojiMatch = subject.match(/^((?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)+\s*)/u);
|
|
12301
12397
|
if (emojiMatch) {
|
|
12302
12398
|
const emoji = emojiMatch[1];
|
|
12303
12399
|
const rest = subject.slice(emoji.length);
|
|
12304
|
-
return `${emoji}${
|
|
12400
|
+
return `${emoji}${import_picocolors12.default.white(rest)}`;
|
|
12305
12401
|
}
|
|
12306
12402
|
if (subject.startsWith("Merge ")) {
|
|
12307
|
-
return
|
|
12403
|
+
return import_picocolors12.default.dim(subject);
|
|
12308
12404
|
}
|
|
12309
|
-
return
|
|
12405
|
+
return import_picocolors12.default.white(subject);
|
|
12310
12406
|
}
|
|
12311
12407
|
|
|
12312
12408
|
// src/commands/save.ts
|
|
12313
|
-
var
|
|
12409
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
12314
12410
|
import { execFile as execFileCb4 } from "node:child_process";
|
|
12315
12411
|
function gitRun(args) {
|
|
12316
12412
|
return new Promise((resolve2) => {
|
|
@@ -12372,7 +12468,7 @@ var save_default = defineCommand({
|
|
|
12372
12468
|
}
|
|
12373
12469
|
});
|
|
12374
12470
|
async function handleSave(message) {
|
|
12375
|
-
|
|
12471
|
+
projectHeading("save", "\uD83D\uDCBE");
|
|
12376
12472
|
const currentBranch = await getCurrentBranch();
|
|
12377
12473
|
const label = message ?? `work-in-progress on ${currentBranch ?? "unknown"}`;
|
|
12378
12474
|
const stashMsg = `contrib-save: ${label}`;
|
|
@@ -12385,11 +12481,11 @@ async function handleSave(message) {
|
|
|
12385
12481
|
info("No uncommitted changes to save.");
|
|
12386
12482
|
return;
|
|
12387
12483
|
}
|
|
12388
|
-
success(`Saved: ${
|
|
12389
|
-
info(`Use ${
|
|
12484
|
+
success(`Saved: ${import_picocolors13.default.dim(label)}`);
|
|
12485
|
+
info(`Use ${import_picocolors13.default.bold("contrib save --restore")} to bring them back.`, "");
|
|
12390
12486
|
}
|
|
12391
12487
|
async function handleRestore() {
|
|
12392
|
-
|
|
12488
|
+
projectHeading("save --restore", "\uD83D\uDCBE");
|
|
12393
12489
|
const stashes = await getStashList();
|
|
12394
12490
|
if (stashes.length === 0) {
|
|
12395
12491
|
info("No saved changes found.");
|
|
@@ -12402,7 +12498,7 @@ async function handleRestore() {
|
|
|
12402
12498
|
warn("You may have conflicts. Resolve them and run `git stash drop` when done.");
|
|
12403
12499
|
process.exit(1);
|
|
12404
12500
|
}
|
|
12405
|
-
success(`Restored: ${
|
|
12501
|
+
success(`Restored: ${import_picocolors13.default.dim(stashes[0].message)}`);
|
|
12406
12502
|
return;
|
|
12407
12503
|
}
|
|
12408
12504
|
const choices = stashes.map((s2) => `${s2.index} ${s2.message}`);
|
|
@@ -12415,10 +12511,10 @@ async function handleRestore() {
|
|
|
12415
12511
|
process.exit(1);
|
|
12416
12512
|
}
|
|
12417
12513
|
const match = stashes.find((s2) => String(s2.index) === idx);
|
|
12418
|
-
success(`Restored: ${
|
|
12514
|
+
success(`Restored: ${import_picocolors13.default.dim(match?.message ?? "saved changes")}`);
|
|
12419
12515
|
}
|
|
12420
12516
|
async function handleList() {
|
|
12421
|
-
|
|
12517
|
+
projectHeading("save --list", "\uD83D\uDCBE");
|
|
12422
12518
|
const stashes = await getStashList();
|
|
12423
12519
|
if (stashes.length === 0) {
|
|
12424
12520
|
info("No saved changes.");
|
|
@@ -12426,16 +12522,16 @@ async function handleList() {
|
|
|
12426
12522
|
}
|
|
12427
12523
|
console.log();
|
|
12428
12524
|
for (const s2 of stashes) {
|
|
12429
|
-
const idx =
|
|
12525
|
+
const idx = import_picocolors13.default.dim(`[${s2.index}]`);
|
|
12430
12526
|
const msg = s2.message;
|
|
12431
12527
|
console.log(` ${idx} ${msg}`);
|
|
12432
12528
|
}
|
|
12433
12529
|
console.log();
|
|
12434
|
-
info(`Use ${
|
|
12435
|
-
info(`Use ${
|
|
12530
|
+
info(`Use ${import_picocolors13.default.bold("contrib save --restore")} to bring changes back.`, "");
|
|
12531
|
+
info(`Use ${import_picocolors13.default.bold("contrib save --drop")} to discard saved changes.`, "");
|
|
12436
12532
|
}
|
|
12437
12533
|
async function handleDrop() {
|
|
12438
|
-
|
|
12534
|
+
projectHeading("save --drop", "\uD83D\uDCBE");
|
|
12439
12535
|
const stashes = await getStashList();
|
|
12440
12536
|
if (stashes.length === 0) {
|
|
12441
12537
|
info("No saved changes to drop.");
|
|
@@ -12450,7 +12546,7 @@ async function handleDrop() {
|
|
|
12450
12546
|
process.exit(1);
|
|
12451
12547
|
}
|
|
12452
12548
|
const match = stashes.find((s2) => String(s2.index) === idx);
|
|
12453
|
-
success(`Dropped: ${
|
|
12549
|
+
success(`Dropped: ${import_picocolors13.default.dim(match?.message ?? "saved changes")}`);
|
|
12454
12550
|
}
|
|
12455
12551
|
async function getStashList() {
|
|
12456
12552
|
const result = await gitRun(["stash", "list"]);
|
|
@@ -12467,7 +12563,7 @@ async function getStashList() {
|
|
|
12467
12563
|
}
|
|
12468
12564
|
|
|
12469
12565
|
// src/commands/setup.ts
|
|
12470
|
-
var
|
|
12566
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
12471
12567
|
async function shouldContinueSetupWithExistingConfig(options) {
|
|
12472
12568
|
const {
|
|
12473
12569
|
existingConfig,
|
|
@@ -12515,7 +12611,7 @@ var setup_default = defineCommand({
|
|
|
12515
12611
|
error("Not inside a git repository. Run this command from within a git repo.");
|
|
12516
12612
|
process.exit(1);
|
|
12517
12613
|
}
|
|
12518
|
-
|
|
12614
|
+
projectHeading("setup", "\uD83D\uDD27");
|
|
12519
12615
|
const existingConfig = readConfig();
|
|
12520
12616
|
const shouldContinue = await shouldContinueSetupWithExistingConfig({
|
|
12521
12617
|
existingConfig,
|
|
@@ -12540,7 +12636,7 @@ var setup_default = defineCommand({
|
|
|
12540
12636
|
workflow = "github-flow";
|
|
12541
12637
|
else if (workflowChoice.startsWith("Git Flow"))
|
|
12542
12638
|
workflow = "git-flow";
|
|
12543
|
-
info(`Workflow: ${
|
|
12639
|
+
info(`Workflow: ${import_picocolors14.default.bold(WORKFLOW_DESCRIPTIONS[workflow])}`);
|
|
12544
12640
|
const conventionChoice = await selectPrompt("Which commit convention should this project use?", [
|
|
12545
12641
|
`${CONVENTION_DESCRIPTIONS["clean-commit"]} (recommended)`,
|
|
12546
12642
|
CONVENTION_DESCRIPTIONS.conventional,
|
|
@@ -12551,6 +12647,7 @@ var setup_default = defineCommand({
|
|
|
12551
12647
|
commitConvention = "conventional";
|
|
12552
12648
|
else if (conventionChoice.includes("No commit"))
|
|
12553
12649
|
commitConvention = "none";
|
|
12650
|
+
const enableAI = await confirmPrompt("Enable AI-assisted features like commit messages, branch naming, PR text, and conflict guidance?");
|
|
12554
12651
|
const remotes = await getRemotes();
|
|
12555
12652
|
if (remotes.length === 0) {
|
|
12556
12653
|
error("No git remotes found. Add a remote first (e.g., git remote add origin <url>).");
|
|
@@ -12604,15 +12701,15 @@ var setup_default = defineCommand({
|
|
|
12604
12701
|
detectedRole = roleChoice;
|
|
12605
12702
|
detectionSource = "user selection";
|
|
12606
12703
|
} else {
|
|
12607
|
-
info(`Detected role: ${
|
|
12608
|
-
const confirmed = await confirmPrompt(`Role detected as ${
|
|
12704
|
+
info(`Detected role: ${import_picocolors14.default.bold(detectedRole)} (via ${detectionSource})`);
|
|
12705
|
+
const confirmed = await confirmPrompt(`Role detected as ${import_picocolors14.default.bold(detectedRole)}. Is this correct?`);
|
|
12609
12706
|
if (!confirmed) {
|
|
12610
12707
|
const roleChoice = await selectPrompt("Select your role:", ["maintainer", "contributor"]);
|
|
12611
12708
|
detectedRole = roleChoice;
|
|
12612
12709
|
}
|
|
12613
12710
|
}
|
|
12614
12711
|
const defaultConfig = getDefaultConfig();
|
|
12615
|
-
info(
|
|
12712
|
+
info(import_picocolors14.default.dim("Tip: press Enter to keep the default branch name shown in each prompt."));
|
|
12616
12713
|
const mainBranchDefault = defaultConfig.mainBranch;
|
|
12617
12714
|
const mainBranch = await inputPrompt(`Main branch name (default: ${mainBranchDefault} — press Enter to keep)`, mainBranchDefault);
|
|
12618
12715
|
let devBranch;
|
|
@@ -12638,7 +12735,7 @@ var setup_default = defineCommand({
|
|
|
12638
12735
|
error("Setup cannot continue without the upstream remote for contributors.");
|
|
12639
12736
|
process.exit(1);
|
|
12640
12737
|
}
|
|
12641
|
-
success(`Added remote ${
|
|
12738
|
+
success(`Added remote ${import_picocolors14.default.bold(upstreamRemote)} → ${upstreamUrl}`);
|
|
12642
12739
|
} else {
|
|
12643
12740
|
error("An upstream remote URL is required for contributors.");
|
|
12644
12741
|
info("Add it manually: git remote add upstream <url>", "");
|
|
@@ -12654,22 +12751,23 @@ var setup_default = defineCommand({
|
|
|
12654
12751
|
upstream: upstreamRemote,
|
|
12655
12752
|
origin: originRemote,
|
|
12656
12753
|
branchPrefixes: defaultConfig.branchPrefixes,
|
|
12657
|
-
commitConvention
|
|
12754
|
+
commitConvention,
|
|
12755
|
+
aiEnabled: enableAI
|
|
12658
12756
|
};
|
|
12659
12757
|
writeConfig(config);
|
|
12660
12758
|
success(`Config written to .contributerc.json`);
|
|
12661
12759
|
const syncRemote = config.role === "contributor" ? config.upstream : config.origin;
|
|
12662
|
-
info(`Fetching ${
|
|
12760
|
+
info(`Fetching ${import_picocolors14.default.bold(syncRemote)} to verify branch configuration...`, "");
|
|
12663
12761
|
await fetchRemote(syncRemote);
|
|
12664
12762
|
const mainRef = `${syncRemote}/${config.mainBranch}`;
|
|
12665
12763
|
if (!await refExists(mainRef)) {
|
|
12666
|
-
warn(`Main branch ref ${
|
|
12764
|
+
warn(`Main branch ref ${import_picocolors14.default.bold(mainRef)} not found on remote.`);
|
|
12667
12765
|
warn("Config was saved — verify the branch name and re-run setup if needed.");
|
|
12668
12766
|
}
|
|
12669
12767
|
if (config.devBranch) {
|
|
12670
12768
|
const devRef = `${syncRemote}/${config.devBranch}`;
|
|
12671
12769
|
if (!await refExists(devRef)) {
|
|
12672
|
-
warn(`Dev branch ref ${
|
|
12770
|
+
warn(`Dev branch ref ${import_picocolors14.default.bold(devRef)} not found on remote.`);
|
|
12673
12771
|
warn("Config was saved — verify the branch name and re-run setup if needed.");
|
|
12674
12772
|
}
|
|
12675
12773
|
}
|
|
@@ -12677,31 +12775,33 @@ var setup_default = defineCommand({
|
|
|
12677
12775
|
info("Added .contributerc.json to .gitignore to avoid committing personal config.");
|
|
12678
12776
|
}
|
|
12679
12777
|
console.log();
|
|
12680
|
-
info(`Workflow: ${
|
|
12681
|
-
info(`Convention: ${
|
|
12682
|
-
info(`
|
|
12778
|
+
info(`Workflow: ${import_picocolors14.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
|
|
12779
|
+
info(`Convention: ${import_picocolors14.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
|
|
12780
|
+
info(`AI: ${import_picocolors14.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
|
|
12781
|
+
info(`Role: ${import_picocolors14.default.bold(config.role)}`);
|
|
12683
12782
|
if (config.devBranch) {
|
|
12684
|
-
info(`Main: ${
|
|
12783
|
+
info(`Main: ${import_picocolors14.default.bold(config.mainBranch)} | Dev: ${import_picocolors14.default.bold(config.devBranch)}`);
|
|
12685
12784
|
} else {
|
|
12686
|
-
info(`Main: ${
|
|
12785
|
+
info(`Main: ${import_picocolors14.default.bold(config.mainBranch)}`);
|
|
12687
12786
|
}
|
|
12688
|
-
info(`Origin: ${
|
|
12787
|
+
info(`Origin: ${import_picocolors14.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors14.default.bold(config.upstream)}` : ""}`);
|
|
12689
12788
|
}
|
|
12690
12789
|
});
|
|
12691
12790
|
function logConfigSummary(config) {
|
|
12692
|
-
info(`Workflow: ${
|
|
12693
|
-
info(`Convention: ${
|
|
12694
|
-
info(`
|
|
12791
|
+
info(`Workflow: ${import_picocolors14.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
|
|
12792
|
+
info(`Convention: ${import_picocolors14.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
|
|
12793
|
+
info(`AI: ${import_picocolors14.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
|
|
12794
|
+
info(`Role: ${import_picocolors14.default.bold(config.role)}`);
|
|
12695
12795
|
if (config.devBranch) {
|
|
12696
|
-
info(`Main: ${
|
|
12796
|
+
info(`Main: ${import_picocolors14.default.bold(config.mainBranch)} | Dev: ${import_picocolors14.default.bold(config.devBranch)}`);
|
|
12697
12797
|
} else {
|
|
12698
|
-
info(`Main: ${
|
|
12798
|
+
info(`Main: ${import_picocolors14.default.bold(config.mainBranch)}`);
|
|
12699
12799
|
}
|
|
12700
|
-
info(`Origin: ${
|
|
12800
|
+
info(`Origin: ${import_picocolors14.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors14.default.bold(config.upstream)}` : ""}`);
|
|
12701
12801
|
}
|
|
12702
12802
|
|
|
12703
12803
|
// src/commands/start.ts
|
|
12704
|
-
var
|
|
12804
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
12705
12805
|
var start_default = defineCommand({
|
|
12706
12806
|
meta: {
|
|
12707
12807
|
name: "start",
|
|
@@ -12741,57 +12841,28 @@ var start_default = defineCommand({
|
|
|
12741
12841
|
const { branchPrefixes } = config;
|
|
12742
12842
|
const baseBranch = getBaseBranch(config);
|
|
12743
12843
|
const syncSource = getSyncSource(config);
|
|
12744
|
-
let branchName = args.name;
|
|
12745
|
-
|
|
12844
|
+
let branchName = args.name?.trim();
|
|
12845
|
+
projectHeading("start", "\uD83C\uDF3F");
|
|
12846
|
+
branchName = await promptForBranchName({
|
|
12847
|
+
initialValue: branchName,
|
|
12848
|
+
branchPrefixes,
|
|
12849
|
+
useAI: isAIEnabled(config, args["no-ai"]),
|
|
12850
|
+
model: args.model
|
|
12851
|
+
});
|
|
12746
12852
|
if (!branchName) {
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
error("A branch name or description is required.");
|
|
12750
|
-
process.exit(1);
|
|
12751
|
-
}
|
|
12752
|
-
branchName = branchName.trim();
|
|
12753
|
-
}
|
|
12754
|
-
const useAI = !args["no-ai"] && looksLikeNaturalLanguage(branchName);
|
|
12755
|
-
if (useAI) {
|
|
12756
|
-
const spinner = createSpinner("Generating branch name suggestion...");
|
|
12757
|
-
const suggested = await suggestBranchName(branchName, args.model);
|
|
12758
|
-
if (suggested) {
|
|
12759
|
-
spinner.success("Branch name suggestion ready.");
|
|
12760
|
-
console.log(`
|
|
12761
|
-
${import_picocolors14.default.dim("AI suggestion:")} ${import_picocolors14.default.bold(import_picocolors14.default.cyan(suggested))}`);
|
|
12762
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors14.default.bold(suggested)} as your branch name?`);
|
|
12763
|
-
if (accepted) {
|
|
12764
|
-
branchName = suggested;
|
|
12765
|
-
} else {
|
|
12766
|
-
branchName = await inputPrompt("Enter branch name", branchName);
|
|
12767
|
-
}
|
|
12768
|
-
} else {
|
|
12769
|
-
spinner.fail("AI did not return a branch name suggestion.");
|
|
12770
|
-
}
|
|
12771
|
-
}
|
|
12772
|
-
if (!hasPrefix(branchName, branchPrefixes)) {
|
|
12773
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors14.default.bold(branchName)}:`, branchPrefixes);
|
|
12774
|
-
branchName = formatBranchName(prefix, branchName);
|
|
12775
|
-
}
|
|
12776
|
-
if (!isValidBranchName(branchName)) {
|
|
12777
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
12778
|
-
process.exit(1);
|
|
12779
|
-
}
|
|
12780
|
-
info(`Creating branch: ${import_picocolors14.default.bold(branchName)}`);
|
|
12781
|
-
if (await branchExists(branchName)) {
|
|
12782
|
-
error(`Branch ${import_picocolors14.default.bold(branchName)} already exists.`);
|
|
12783
|
-
info(` Use ${import_picocolors14.default.bold(`git checkout ${branchName}`)} to switch to it, or choose a different name.`, "");
|
|
12784
|
-
process.exit(1);
|
|
12853
|
+
warn("Start cancelled.");
|
|
12854
|
+
process.exit(0);
|
|
12785
12855
|
}
|
|
12856
|
+
info(`Creating branch: ${import_picocolors15.default.bold(branchName)}`);
|
|
12786
12857
|
await fetchRemote(syncSource.remote);
|
|
12787
12858
|
if (!await refExists(syncSource.ref)) {
|
|
12788
|
-
warn(`Remote ref ${
|
|
12859
|
+
warn(`Remote ref ${import_picocolors15.default.bold(syncSource.ref)} not found. Creating branch from local ${import_picocolors15.default.bold(baseBranch)}.`);
|
|
12789
12860
|
}
|
|
12790
12861
|
const currentBranch = await getCurrentBranch();
|
|
12791
12862
|
if (currentBranch === baseBranch && await refExists(syncSource.ref)) {
|
|
12792
12863
|
const ahead = await countCommitsAhead(baseBranch, syncSource.ref);
|
|
12793
12864
|
if (ahead > 0) {
|
|
12794
|
-
warn(`You are on ${
|
|
12865
|
+
warn(`You are on ${import_picocolors15.default.bold(baseBranch)} with ${import_picocolors15.default.bold(String(ahead))} local commit${ahead > 1 ? "s" : ""} not in ${import_picocolors15.default.bold(syncSource.ref)}.`);
|
|
12795
12866
|
info(" Syncing will discard those commits. Consider backing them up first (e.g. create a branch).");
|
|
12796
12867
|
const proceed = await confirmPrompt("Discard local commits and sync to remote?");
|
|
12797
12868
|
if (!proceed) {
|
|
@@ -12808,10 +12879,10 @@ var start_default = defineCommand({
|
|
|
12808
12879
|
error(`Failed to create branch: ${result2.stderr}`);
|
|
12809
12880
|
process.exit(1);
|
|
12810
12881
|
}
|
|
12811
|
-
success(`Created ${
|
|
12882
|
+
success(`Created ${import_picocolors15.default.bold(branchName)} from ${import_picocolors15.default.bold(syncSource.ref)}`);
|
|
12812
12883
|
return;
|
|
12813
12884
|
}
|
|
12814
|
-
error(`Failed to update ${
|
|
12885
|
+
error(`Failed to update ${import_picocolors15.default.bold(baseBranch)}: ${updateResult.stderr}`);
|
|
12815
12886
|
info("Make sure your base branch exists locally or the remote ref is available.", "");
|
|
12816
12887
|
process.exit(1);
|
|
12817
12888
|
}
|
|
@@ -12820,12 +12891,12 @@ var start_default = defineCommand({
|
|
|
12820
12891
|
error(`Failed to create branch: ${result.stderr}`);
|
|
12821
12892
|
process.exit(1);
|
|
12822
12893
|
}
|
|
12823
|
-
success(`Created ${
|
|
12894
|
+
success(`Created ${import_picocolors15.default.bold(branchName)} from latest ${import_picocolors15.default.bold(baseBranch)}`);
|
|
12824
12895
|
}
|
|
12825
12896
|
});
|
|
12826
12897
|
|
|
12827
12898
|
// src/commands/status.ts
|
|
12828
|
-
var
|
|
12899
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
12829
12900
|
var status_default = defineCommand({
|
|
12830
12901
|
meta: {
|
|
12831
12902
|
name: "status",
|
|
@@ -12841,9 +12912,9 @@ var status_default = defineCommand({
|
|
|
12841
12912
|
error("No .contributerc.json found. Run `contrib setup` first.");
|
|
12842
12913
|
process.exit(1);
|
|
12843
12914
|
}
|
|
12844
|
-
|
|
12845
|
-
console.log(` ${
|
|
12846
|
-
console.log(` ${
|
|
12915
|
+
projectHeading("status", "\uD83D\uDCCA");
|
|
12916
|
+
console.log(` ${import_picocolors16.default.dim("Workflow:")} ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
|
|
12917
|
+
console.log(` ${import_picocolors16.default.dim("Role:")} ${import_picocolors16.default.bold(config.role)}`);
|
|
12847
12918
|
console.log();
|
|
12848
12919
|
await fetchAll();
|
|
12849
12920
|
const currentBranch = await getCurrentBranch();
|
|
@@ -12852,7 +12923,7 @@ var status_default = defineCommand({
|
|
|
12852
12923
|
const isContributor = config.role === "contributor";
|
|
12853
12924
|
const [dirty, fileStatus] = await Promise.all([hasUncommittedChanges(), getFileStatus()]);
|
|
12854
12925
|
if (dirty) {
|
|
12855
|
-
console.log(` ${
|
|
12926
|
+
console.log(` ${import_picocolors16.default.yellow("⚠")} ${import_picocolors16.default.yellow("Uncommitted changes in working tree")}`);
|
|
12856
12927
|
console.log();
|
|
12857
12928
|
}
|
|
12858
12929
|
const mainRemote = `${origin}/${mainBranch}`;
|
|
@@ -12871,16 +12942,16 @@ var status_default = defineCommand({
|
|
|
12871
12942
|
if (isFeatureBranch) {
|
|
12872
12943
|
const branchDiv = await getDivergence(currentBranch, baseBranch);
|
|
12873
12944
|
const branchLine = formatStatus(currentBranch, baseBranch, branchDiv.ahead, branchDiv.behind);
|
|
12874
|
-
console.log(branchLine +
|
|
12945
|
+
console.log(branchLine + import_picocolors16.default.dim(` (current ${import_picocolors16.default.green("*")})`));
|
|
12875
12946
|
branchStatus = await detectBranchStatus(currentBranch, baseBranch);
|
|
12876
12947
|
if (branchStatus.merged) {
|
|
12877
|
-
console.log(` ${
|
|
12948
|
+
console.log(` ${import_picocolors16.default.green("✓")} ${import_picocolors16.default.green("Branch merged")} — ${import_picocolors16.default.dim(branchStatus.mergedReason ?? "all commits reachable from base")}`);
|
|
12878
12949
|
}
|
|
12879
12950
|
if (branchStatus.stale) {
|
|
12880
|
-
console.log(` ${
|
|
12951
|
+
console.log(` ${import_picocolors16.default.yellow("⏳")} ${import_picocolors16.default.yellow("Branch is stale")} — ${import_picocolors16.default.dim(`last commit ${branchStatus.staleDaysAgo} days ago`)}`);
|
|
12881
12952
|
}
|
|
12882
12953
|
} else if (currentBranch) {
|
|
12883
|
-
console.log(
|
|
12954
|
+
console.log(import_picocolors16.default.dim(` (on ${import_picocolors16.default.bold(currentBranch)} branch)`));
|
|
12884
12955
|
}
|
|
12885
12956
|
let branchesAligned = true;
|
|
12886
12957
|
{
|
|
@@ -12910,20 +12981,20 @@ var status_default = defineCommand({
|
|
|
12910
12981
|
}
|
|
12911
12982
|
branchesAligned = groups.size === 1;
|
|
12912
12983
|
console.log();
|
|
12913
|
-
console.log(` ${
|
|
12984
|
+
console.log(` ${import_picocolors16.default.bold("\uD83D\uDD17 Branch Alignment")}`);
|
|
12914
12985
|
for (const [hash, names] of groups) {
|
|
12915
12986
|
const short = hash.slice(0, 7);
|
|
12916
|
-
const nameStr = names.map((n2) =>
|
|
12917
|
-
console.log(` ${
|
|
12987
|
+
const nameStr = names.map((n2) => import_picocolors16.default.bold(n2)).join(import_picocolors16.default.dim(" · "));
|
|
12988
|
+
console.log(` ${import_picocolors16.default.yellow(short)} ${import_picocolors16.default.dim("──")} ${nameStr}`);
|
|
12918
12989
|
const subject = await getCommitSubject(hash);
|
|
12919
12990
|
if (subject) {
|
|
12920
|
-
console.log(` ${
|
|
12991
|
+
console.log(` ${import_picocolors16.default.dim(subject)}`);
|
|
12921
12992
|
}
|
|
12922
12993
|
}
|
|
12923
12994
|
if (branchesAligned) {
|
|
12924
|
-
console.log(` ${
|
|
12995
|
+
console.log(` ${import_picocolors16.default.green("✓")} ${import_picocolors16.default.green("All branches aligned")} ${import_picocolors16.default.dim("— ready to start")}`);
|
|
12925
12996
|
} else {
|
|
12926
|
-
console.log(` ${
|
|
12997
|
+
console.log(` ${import_picocolors16.default.yellow("⚠")} ${import_picocolors16.default.yellow("Branches are not fully aligned")}`);
|
|
12927
12998
|
}
|
|
12928
12999
|
}
|
|
12929
13000
|
}
|
|
@@ -12931,70 +13002,70 @@ var status_default = defineCommand({
|
|
|
12931
13002
|
if (hasFiles) {
|
|
12932
13003
|
console.log();
|
|
12933
13004
|
if (fileStatus.staged.length > 0) {
|
|
12934
|
-
console.log(` ${
|
|
13005
|
+
console.log(` ${import_picocolors16.default.green("Staged for commit:")}`);
|
|
12935
13006
|
for (const { file, status } of fileStatus.staged) {
|
|
12936
|
-
console.log(` ${
|
|
13007
|
+
console.log(` ${import_picocolors16.default.green("+")} ${import_picocolors16.default.dim(`${status}:`)} ${file}`);
|
|
12937
13008
|
}
|
|
12938
13009
|
}
|
|
12939
13010
|
if (fileStatus.modified.length > 0) {
|
|
12940
|
-
console.log(` ${
|
|
13011
|
+
console.log(` ${import_picocolors16.default.yellow("Unstaged changes:")}`);
|
|
12941
13012
|
for (const { file, status } of fileStatus.modified) {
|
|
12942
|
-
console.log(` ${
|
|
13013
|
+
console.log(` ${import_picocolors16.default.yellow("~")} ${import_picocolors16.default.dim(`${status}:`)} ${file}`);
|
|
12943
13014
|
}
|
|
12944
13015
|
}
|
|
12945
13016
|
if (fileStatus.untracked.length > 0) {
|
|
12946
|
-
console.log(` ${
|
|
13017
|
+
console.log(` ${import_picocolors16.default.red("Untracked files:")}`);
|
|
12947
13018
|
for (const file of fileStatus.untracked) {
|
|
12948
|
-
console.log(` ${
|
|
13019
|
+
console.log(` ${import_picocolors16.default.red("?")} ${file}`);
|
|
12949
13020
|
}
|
|
12950
13021
|
}
|
|
12951
13022
|
} else if (!dirty) {
|
|
12952
|
-
console.log(` ${
|
|
13023
|
+
console.log(` ${import_picocolors16.default.green("✓")} ${import_picocolors16.default.dim("Working tree clean")}`);
|
|
12953
13024
|
}
|
|
12954
13025
|
const tips = [];
|
|
12955
13026
|
if (!branchesAligned) {
|
|
12956
|
-
tips.push(`Run ${
|
|
13027
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib sync")} to align your local branches with the remote`);
|
|
12957
13028
|
}
|
|
12958
13029
|
if (fileStatus.staged.length > 0) {
|
|
12959
|
-
tips.push(`Run ${
|
|
13030
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib commit")} to commit staged changes`);
|
|
12960
13031
|
}
|
|
12961
13032
|
if (fileStatus.modified.length > 0 || fileStatus.untracked.length > 0) {
|
|
12962
|
-
tips.push(`Run ${
|
|
13033
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib commit")} to stage and commit changes`);
|
|
12963
13034
|
}
|
|
12964
13035
|
if (isFeatureBranch && branchStatus) {
|
|
12965
13036
|
if (branchStatus.merged) {
|
|
12966
|
-
tips.push(`Run ${
|
|
13037
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib clean")} to delete this merged branch`);
|
|
12967
13038
|
} else if (branchStatus.stale) {
|
|
12968
|
-
tips.push(`Run ${
|
|
13039
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib sync")} to rebase on latest changes, or ${import_picocolors16.default.bold("contrib clean")} if no longer needed`);
|
|
12969
13040
|
} else if (fileStatus.staged.length === 0 && fileStatus.modified.length === 0 && fileStatus.untracked.length === 0) {
|
|
12970
13041
|
const branchDiv = await getDivergence(currentBranch, `${origin}/${currentBranch}`);
|
|
12971
13042
|
if (branchDiv.ahead > 0) {
|
|
12972
|
-
tips.push(`Run ${
|
|
13043
|
+
tips.push(`Run ${import_picocolors16.default.bold("contrib submit")} to push and create/update your PR`);
|
|
12973
13044
|
}
|
|
12974
13045
|
}
|
|
12975
13046
|
}
|
|
12976
13047
|
if (tips.length > 0) {
|
|
12977
13048
|
console.log();
|
|
12978
|
-
console.log(` ${
|
|
13049
|
+
console.log(` ${import_picocolors16.default.dim("\uD83D\uDCA1 Tip:")}`);
|
|
12979
13050
|
for (const tip of tips) {
|
|
12980
|
-
console.log(` ${
|
|
13051
|
+
console.log(` ${import_picocolors16.default.dim(tip)}`);
|
|
12981
13052
|
}
|
|
12982
13053
|
}
|
|
12983
13054
|
console.log();
|
|
12984
13055
|
}
|
|
12985
13056
|
});
|
|
12986
13057
|
function formatStatus(branch, base, ahead, behind) {
|
|
12987
|
-
const label =
|
|
13058
|
+
const label = import_picocolors16.default.bold(branch.padEnd(20));
|
|
12988
13059
|
if (ahead === 0 && behind === 0) {
|
|
12989
|
-
return ` ${
|
|
13060
|
+
return ` ${import_picocolors16.default.green("✓")} ${label} ${import_picocolors16.default.dim(`in sync with ${base}`)}`;
|
|
12990
13061
|
}
|
|
12991
13062
|
if (ahead > 0 && behind === 0) {
|
|
12992
|
-
return ` ${
|
|
13063
|
+
return ` ${import_picocolors16.default.yellow("↑")} ${label} ${import_picocolors16.default.yellow(`${ahead} commit${ahead !== 1 ? "s" : ""} ahead of ${base}`)}`;
|
|
12993
13064
|
}
|
|
12994
13065
|
if (behind > 0 && ahead === 0) {
|
|
12995
|
-
return ` ${
|
|
13066
|
+
return ` ${import_picocolors16.default.red("↓")} ${label} ${import_picocolors16.default.red(`${behind} commit${behind !== 1 ? "s" : ""} behind ${base}`)}`;
|
|
12996
13067
|
}
|
|
12997
|
-
return ` ${
|
|
13068
|
+
return ` ${import_picocolors16.default.red("⚡")} ${label} ${import_picocolors16.default.yellow(`${ahead} ahead`)}${import_picocolors16.default.dim(", ")}${import_picocolors16.default.red(`${behind} behind`)} ${import_picocolors16.default.dim(base)}`;
|
|
12998
13069
|
}
|
|
12999
13070
|
var STALE_THRESHOLD_DAYS = 14;
|
|
13000
13071
|
async function detectBranchStatus(branch, baseBranch) {
|
|
@@ -13040,23 +13111,23 @@ async function detectBranchStatus(branch, baseBranch) {
|
|
|
13040
13111
|
}
|
|
13041
13112
|
|
|
13042
13113
|
// src/commands/submit.ts
|
|
13043
|
-
var
|
|
13114
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
13044
13115
|
async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
13045
|
-
info(`Checking out ${
|
|
13116
|
+
info(`Checking out ${import_picocolors17.default.bold(baseBranch)}...`);
|
|
13046
13117
|
const coResult = await checkoutBranch(baseBranch);
|
|
13047
13118
|
if (coResult.exitCode !== 0) {
|
|
13048
13119
|
error(`Failed to checkout ${baseBranch}: ${coResult.stderr}`);
|
|
13049
13120
|
process.exit(1);
|
|
13050
13121
|
}
|
|
13051
|
-
info(`Squash merging ${
|
|
13122
|
+
info(`Squash merging ${import_picocolors17.default.bold(featureBranch)} into ${import_picocolors17.default.bold(baseBranch)}...`);
|
|
13052
13123
|
const mergeResult = await mergeSquash(featureBranch);
|
|
13053
13124
|
if (mergeResult.exitCode !== 0) {
|
|
13054
13125
|
error(`Squash merge failed: ${mergeResult.stderr}`);
|
|
13055
13126
|
process.exit(1);
|
|
13056
13127
|
}
|
|
13057
13128
|
let message = options?.defaultMsg;
|
|
13058
|
-
if (!message) {
|
|
13059
|
-
const copilotError = await
|
|
13129
|
+
if (!message && options?.useAI !== false) {
|
|
13130
|
+
const copilotError = await checkCopilotAvailable2();
|
|
13060
13131
|
if (!copilotError) {
|
|
13061
13132
|
while (!message) {
|
|
13062
13133
|
const spinner = createSpinner("Generating AI commit message for squash merge...");
|
|
@@ -13066,7 +13137,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13066
13137
|
message = aiMsg;
|
|
13067
13138
|
spinner.success("AI commit message generated.");
|
|
13068
13139
|
console.log(`
|
|
13069
|
-
${
|
|
13140
|
+
${import_picocolors17.default.dim("AI suggestion:")} ${import_picocolors17.default.bold(import_picocolors17.default.cyan(message))}`);
|
|
13070
13141
|
break;
|
|
13071
13142
|
}
|
|
13072
13143
|
spinner.fail("AI did not return a commit message.");
|
|
@@ -13087,12 +13158,11 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13087
13158
|
let finalMsg = null;
|
|
13088
13159
|
if (message) {
|
|
13089
13160
|
while (!finalMsg) {
|
|
13090
|
-
const
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
]);
|
|
13161
|
+
const actions = ["Accept this message", "Edit this message", "Write manually"];
|
|
13162
|
+
if (options?.useAI !== false) {
|
|
13163
|
+
actions.splice(2, 0, "Regenerate");
|
|
13164
|
+
}
|
|
13165
|
+
const action = await selectPrompt("What would you like to do?", actions);
|
|
13096
13166
|
if (action === "Accept this message") {
|
|
13097
13167
|
finalMsg = message;
|
|
13098
13168
|
} else if (action === "Edit this message") {
|
|
@@ -13105,7 +13175,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13105
13175
|
message = regen;
|
|
13106
13176
|
spinner.success("Commit message regenerated.");
|
|
13107
13177
|
console.log(`
|
|
13108
|
-
${
|
|
13178
|
+
${import_picocolors17.default.dim("AI suggestion:")} ${import_picocolors17.default.bold(import_picocolors17.default.cyan(regen))}`);
|
|
13109
13179
|
} else {
|
|
13110
13180
|
spinner.fail("Regeneration failed.");
|
|
13111
13181
|
continue;
|
|
@@ -13122,13 +13192,13 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13122
13192
|
error(`Commit failed: ${commitResult.stderr}`);
|
|
13123
13193
|
process.exit(1);
|
|
13124
13194
|
}
|
|
13125
|
-
info(`Pushing ${
|
|
13195
|
+
info(`Pushing ${import_picocolors17.default.bold(baseBranch)} to ${origin}...`);
|
|
13126
13196
|
const pushResult = await pushBranch(origin, baseBranch);
|
|
13127
13197
|
if (pushResult.exitCode !== 0) {
|
|
13128
13198
|
error(`Failed to push ${baseBranch}: ${pushResult.stderr}`);
|
|
13129
13199
|
process.exit(1);
|
|
13130
13200
|
}
|
|
13131
|
-
info(`Deleting local branch ${
|
|
13201
|
+
info(`Deleting local branch ${import_picocolors17.default.bold(featureBranch)}...`);
|
|
13132
13202
|
const delLocal = await forceDeleteBranch(featureBranch);
|
|
13133
13203
|
if (delLocal.exitCode !== 0) {
|
|
13134
13204
|
warn(`Could not delete local branch: ${delLocal.stderr.trim()}`);
|
|
@@ -13136,14 +13206,14 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13136
13206
|
const remoteBranchRef = `${origin}/${featureBranch}`;
|
|
13137
13207
|
const remoteExists = await branchExists(remoteBranchRef);
|
|
13138
13208
|
if (remoteExists) {
|
|
13139
|
-
info(`Deleting remote branch ${
|
|
13209
|
+
info(`Deleting remote branch ${import_picocolors17.default.bold(featureBranch)}...`);
|
|
13140
13210
|
const delRemote = await deleteRemoteBranch(origin, featureBranch);
|
|
13141
13211
|
if (delRemote.exitCode !== 0) {
|
|
13142
13212
|
warn(`Could not delete remote branch: ${delRemote.stderr.trim()}`);
|
|
13143
13213
|
}
|
|
13144
13214
|
}
|
|
13145
|
-
success(`Squash merged ${
|
|
13146
|
-
info(`Run ${
|
|
13215
|
+
success(`Squash merged ${import_picocolors17.default.bold(featureBranch)} into ${import_picocolors17.default.bold(baseBranch)} and pushed.`);
|
|
13216
|
+
info(`Run ${import_picocolors17.default.bold("contrib start")} to begin a new feature.`, "");
|
|
13147
13217
|
}
|
|
13148
13218
|
var submit_default = defineCommand({
|
|
13149
13219
|
meta: {
|
|
@@ -13156,6 +13226,18 @@ var submit_default = defineCommand({
|
|
|
13156
13226
|
description: "Create PR as draft",
|
|
13157
13227
|
default: false
|
|
13158
13228
|
},
|
|
13229
|
+
pullrequest: {
|
|
13230
|
+
type: "boolean",
|
|
13231
|
+
alias: "pr",
|
|
13232
|
+
description: "Submit directly to PR flow without prompting for mode",
|
|
13233
|
+
default: false
|
|
13234
|
+
},
|
|
13235
|
+
local: {
|
|
13236
|
+
type: "boolean",
|
|
13237
|
+
alias: "l",
|
|
13238
|
+
description: "Squash merge locally without PR (maintainers only)",
|
|
13239
|
+
default: false
|
|
13240
|
+
},
|
|
13159
13241
|
"no-ai": {
|
|
13160
13242
|
type: "boolean",
|
|
13161
13243
|
description: "Skip AI PR description generation",
|
|
@@ -13178,6 +13260,7 @@ var submit_default = defineCommand({
|
|
|
13178
13260
|
process.exit(1);
|
|
13179
13261
|
}
|
|
13180
13262
|
const { origin } = config;
|
|
13263
|
+
const aiEnabled = isAIEnabled(config, args["no-ai"]);
|
|
13181
13264
|
const baseBranch = getBaseBranch(config);
|
|
13182
13265
|
const protectedBranches = getProtectedBranches(config);
|
|
13183
13266
|
const currentBranch = await getCurrentBranch();
|
|
@@ -13186,8 +13269,8 @@ var submit_default = defineCommand({
|
|
|
13186
13269
|
process.exit(1);
|
|
13187
13270
|
}
|
|
13188
13271
|
if (protectedBranches.includes(currentBranch)) {
|
|
13189
|
-
|
|
13190
|
-
warn(`You're on ${
|
|
13272
|
+
projectHeading("submit", "\uD83D\uDE80");
|
|
13273
|
+
warn(`You're on ${import_picocolors17.default.bold(currentBranch)}, which is a protected branch. PRs should come from feature branches.`);
|
|
13191
13274
|
await fetchAll();
|
|
13192
13275
|
const remoteRef = `${origin}/${currentBranch}`;
|
|
13193
13276
|
const localWork = await hasLocalWork(origin, currentBranch);
|
|
@@ -13196,11 +13279,11 @@ var submit_default = defineCommand({
|
|
|
13196
13279
|
const hasAnything = hasCommits || dirty;
|
|
13197
13280
|
if (!hasAnything) {
|
|
13198
13281
|
error("No local changes or commits to move. Switch to a feature branch first.");
|
|
13199
|
-
info(` Run ${
|
|
13282
|
+
info(` Run ${import_picocolors17.default.bold("contrib start")} to create a new feature branch.`, "");
|
|
13200
13283
|
process.exit(1);
|
|
13201
13284
|
}
|
|
13202
13285
|
if (hasCommits) {
|
|
13203
|
-
info(`Found ${
|
|
13286
|
+
info(`Found ${import_picocolors17.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors17.default.bold(currentBranch)}.`);
|
|
13204
13287
|
}
|
|
13205
13288
|
if (dirty) {
|
|
13206
13289
|
info("You also have uncommitted changes in the working tree.");
|
|
@@ -13216,58 +13299,35 @@ var submit_default = defineCommand({
|
|
|
13216
13299
|
info("No changes made. You are still on your current branch.");
|
|
13217
13300
|
return;
|
|
13218
13301
|
}
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13225
|
-
|
|
13226
|
-
|
|
13227
|
-
if (suggested) {
|
|
13228
|
-
spinner.success("Branch name suggestion ready.");
|
|
13229
|
-
console.log(`
|
|
13230
|
-
${import_picocolors16.default.dim("AI suggestion:")} ${import_picocolors16.default.bold(import_picocolors16.default.cyan(suggested))}`);
|
|
13231
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors16.default.bold(suggested)} as your branch name?`);
|
|
13232
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
13233
|
-
} else {
|
|
13234
|
-
spinner.fail("AI did not return a suggestion.");
|
|
13235
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
13236
|
-
}
|
|
13237
|
-
}
|
|
13238
|
-
}
|
|
13239
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
13240
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors16.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
13241
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
13242
|
-
}
|
|
13243
|
-
if (!isValidBranchName(newBranchName)) {
|
|
13244
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
13245
|
-
process.exit(1);
|
|
13246
|
-
}
|
|
13247
|
-
if (await branchExists(newBranchName)) {
|
|
13248
|
-
error(`Branch ${import_picocolors16.default.bold(newBranchName)} already exists. Choose a different name.`);
|
|
13249
|
-
process.exit(1);
|
|
13302
|
+
const newBranchName = await promptForBranchName({
|
|
13303
|
+
branchPrefixes: config.branchPrefixes,
|
|
13304
|
+
useAI: aiEnabled,
|
|
13305
|
+
model: args.model
|
|
13306
|
+
});
|
|
13307
|
+
if (!newBranchName) {
|
|
13308
|
+
info("No changes made. You are still on your current branch.");
|
|
13309
|
+
return;
|
|
13250
13310
|
}
|
|
13251
13311
|
const branchResult = await createBranch(newBranchName);
|
|
13252
13312
|
if (branchResult.exitCode !== 0) {
|
|
13253
13313
|
error(`Failed to create branch: ${branchResult.stderr}`);
|
|
13254
13314
|
process.exit(1);
|
|
13255
13315
|
}
|
|
13256
|
-
success(`Created ${
|
|
13316
|
+
success(`Created ${import_picocolors17.default.bold(newBranchName)} with your changes.`);
|
|
13257
13317
|
await updateLocalBranch(currentBranch, remoteRef);
|
|
13258
|
-
info(`Reset ${
|
|
13318
|
+
info(`Reset ${import_picocolors17.default.bold(currentBranch)} back to ${import_picocolors17.default.bold(remoteRef)} — no damage done.`, "");
|
|
13259
13319
|
console.log();
|
|
13260
|
-
success(`You're now on ${
|
|
13261
|
-
info(`Run ${
|
|
13320
|
+
success(`You're now on ${import_picocolors17.default.bold(newBranchName)} with all your work intact.`);
|
|
13321
|
+
info(`Run ${import_picocolors17.default.bold("contrib submit")} again to push and create your PR.`, "");
|
|
13262
13322
|
return;
|
|
13263
13323
|
}
|
|
13264
|
-
|
|
13324
|
+
projectHeading("submit", "\uD83D\uDE80");
|
|
13265
13325
|
const ghInstalled = await checkGhInstalled();
|
|
13266
13326
|
const ghAuthed = ghInstalled && await checkGhAuth();
|
|
13267
13327
|
if (ghInstalled && ghAuthed) {
|
|
13268
13328
|
const mergedPR = await getMergedPRForBranch(currentBranch);
|
|
13269
13329
|
if (mergedPR) {
|
|
13270
|
-
warn(`PR #${mergedPR.number} (${
|
|
13330
|
+
warn(`PR #${mergedPR.number} (${import_picocolors17.default.bold(mergedPR.title)}) was already merged.`);
|
|
13271
13331
|
const localWork = await hasLocalWork(origin, currentBranch);
|
|
13272
13332
|
const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
|
|
13273
13333
|
if (hasWork) {
|
|
@@ -13275,7 +13335,7 @@ var submit_default = defineCommand({
|
|
|
13275
13335
|
warn("You have uncommitted changes in your working tree.");
|
|
13276
13336
|
}
|
|
13277
13337
|
if (localWork.unpushedCommits > 0) {
|
|
13278
|
-
warn(`You have ${
|
|
13338
|
+
warn(`You have ${import_picocolors17.default.bold(String(localWork.unpushedCommits))} local commit${localWork.unpushedCommits !== 1 ? "s" : ""} not in the merged PR.`);
|
|
13279
13339
|
}
|
|
13280
13340
|
const SAVE_NEW_BRANCH = "Save changes to a new branch";
|
|
13281
13341
|
const DISCARD = "Discard all changes and clean up";
|
|
@@ -13286,46 +13346,26 @@ var submit_default = defineCommand({
|
|
|
13286
13346
|
return;
|
|
13287
13347
|
}
|
|
13288
13348
|
if (action === SAVE_NEW_BRANCH) {
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
|
|
13297
|
-
console.log(`
|
|
13298
|
-
${import_picocolors16.default.dim("AI suggestion:")} ${import_picocolors16.default.bold(import_picocolors16.default.cyan(suggested))}`);
|
|
13299
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors16.default.bold(suggested)} as your branch name?`);
|
|
13300
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
13301
|
-
} else {
|
|
13302
|
-
spinner.fail("AI did not return a suggestion.");
|
|
13303
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
13304
|
-
}
|
|
13305
|
-
}
|
|
13306
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
13307
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors16.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
13308
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
13309
|
-
}
|
|
13310
|
-
if (!isValidBranchName(newBranchName)) {
|
|
13311
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
13312
|
-
process.exit(1);
|
|
13349
|
+
const newBranchName = await promptForBranchName({
|
|
13350
|
+
branchPrefixes: config.branchPrefixes,
|
|
13351
|
+
useAI: aiEnabled,
|
|
13352
|
+
model: args.model
|
|
13353
|
+
});
|
|
13354
|
+
if (!newBranchName) {
|
|
13355
|
+
info("No changes made. You are still on your current branch.");
|
|
13356
|
+
return;
|
|
13313
13357
|
}
|
|
13314
13358
|
const staleUpstream = await getUpstreamRef();
|
|
13315
13359
|
const staleUpstreamHash = staleUpstream ? await getCommitHash(staleUpstream) : null;
|
|
13316
|
-
if (await branchExists(newBranchName)) {
|
|
13317
|
-
error(`Branch ${import_picocolors16.default.bold(newBranchName)} already exists. Choose a different name.`);
|
|
13318
|
-
process.exit(1);
|
|
13319
|
-
}
|
|
13320
13360
|
const renameResult = await renameBranch(currentBranch, newBranchName);
|
|
13321
13361
|
if (renameResult.exitCode !== 0) {
|
|
13322
13362
|
error(`Failed to rename branch: ${renameResult.stderr}`);
|
|
13323
13363
|
process.exit(1);
|
|
13324
13364
|
}
|
|
13325
|
-
success(`Renamed ${
|
|
13365
|
+
success(`Renamed ${import_picocolors17.default.bold(currentBranch)} → ${import_picocolors17.default.bold(newBranchName)}`);
|
|
13326
13366
|
await unsetUpstream();
|
|
13327
13367
|
const syncSource2 = getSyncSource(config);
|
|
13328
|
-
info(`Syncing ${
|
|
13368
|
+
info(`Syncing ${import_picocolors17.default.bold(newBranchName)} with latest ${import_picocolors17.default.bold(baseBranch)}...`);
|
|
13329
13369
|
await fetchRemote(syncSource2.remote);
|
|
13330
13370
|
let rebaseResult;
|
|
13331
13371
|
if (staleUpstreamHash) {
|
|
@@ -13336,17 +13376,17 @@ var submit_default = defineCommand({
|
|
|
13336
13376
|
}
|
|
13337
13377
|
if (rebaseResult.exitCode !== 0) {
|
|
13338
13378
|
warn("Rebase encountered conflicts. Resolve them manually, then run:");
|
|
13339
|
-
info(` ${
|
|
13379
|
+
info(` ${import_picocolors17.default.bold("git rebase --continue")}`, "");
|
|
13340
13380
|
} else {
|
|
13341
|
-
success(`Rebased ${
|
|
13381
|
+
success(`Rebased ${import_picocolors17.default.bold(newBranchName)} onto ${import_picocolors17.default.bold(syncSource2.ref)}.`);
|
|
13342
13382
|
}
|
|
13343
|
-
info(`All your changes are preserved. Run ${
|
|
13383
|
+
info(`All your changes are preserved. Run ${import_picocolors17.default.bold("contrib submit")} when ready to create a new PR.`, "");
|
|
13344
13384
|
return;
|
|
13345
13385
|
}
|
|
13346
13386
|
warn("Discarding local changes...");
|
|
13347
13387
|
}
|
|
13348
13388
|
const syncSource = getSyncSource(config);
|
|
13349
|
-
info(`Switching to ${
|
|
13389
|
+
info(`Switching to ${import_picocolors17.default.bold(baseBranch)} and syncing...`);
|
|
13350
13390
|
await fetchRemote(syncSource.remote);
|
|
13351
13391
|
await resetHard("HEAD");
|
|
13352
13392
|
const coResult = await checkoutBranch(baseBranch);
|
|
@@ -13355,23 +13395,23 @@ var submit_default = defineCommand({
|
|
|
13355
13395
|
process.exit(1);
|
|
13356
13396
|
}
|
|
13357
13397
|
await updateLocalBranch(baseBranch, syncSource.ref);
|
|
13358
|
-
success(`Synced ${
|
|
13359
|
-
info(`Deleting stale branch ${
|
|
13398
|
+
success(`Synced ${import_picocolors17.default.bold(baseBranch)} with ${import_picocolors17.default.bold(syncSource.ref)}.`);
|
|
13399
|
+
info(`Deleting stale branch ${import_picocolors17.default.bold(currentBranch)}...`);
|
|
13360
13400
|
const delResult = await forceDeleteBranch(currentBranch);
|
|
13361
13401
|
if (delResult.exitCode === 0) {
|
|
13362
|
-
success(`Deleted ${
|
|
13402
|
+
success(`Deleted ${import_picocolors17.default.bold(currentBranch)}.`);
|
|
13363
13403
|
} else {
|
|
13364
13404
|
warn(`Could not delete branch: ${delResult.stderr.trim()}`);
|
|
13365
13405
|
}
|
|
13366
13406
|
console.log();
|
|
13367
|
-
info(`You're now on ${
|
|
13407
|
+
info(`You're now on ${import_picocolors17.default.bold(baseBranch)}. Run ${import_picocolors17.default.bold("contrib start")} to begin a new feature.`);
|
|
13368
13408
|
return;
|
|
13369
13409
|
}
|
|
13370
13410
|
}
|
|
13371
13411
|
if (ghInstalled && ghAuthed) {
|
|
13372
13412
|
const existingPR = await getPRForBranch(currentBranch);
|
|
13373
13413
|
if (existingPR) {
|
|
13374
|
-
info(`Pushing ${
|
|
13414
|
+
info(`Pushing ${import_picocolors17.default.bold(currentBranch)} to ${origin}...`);
|
|
13375
13415
|
const pushResult2 = await pushSetUpstream(origin, currentBranch);
|
|
13376
13416
|
if (pushResult2.exitCode !== 0) {
|
|
13377
13417
|
error(`Failed to push: ${pushResult2.stderr}`);
|
|
@@ -13382,8 +13422,8 @@ var submit_default = defineCommand({
|
|
|
13382
13422
|
}
|
|
13383
13423
|
process.exit(1);
|
|
13384
13424
|
}
|
|
13385
|
-
success(`Pushed changes to existing PR #${existingPR.number}: ${
|
|
13386
|
-
console.log(` ${
|
|
13425
|
+
success(`Pushed changes to existing PR #${existingPR.number}: ${import_picocolors17.default.bold(existingPR.title)}`);
|
|
13426
|
+
console.log(` ${import_picocolors17.default.cyan(existingPR.url)}`);
|
|
13387
13427
|
return;
|
|
13388
13428
|
}
|
|
13389
13429
|
}
|
|
@@ -13391,7 +13431,7 @@ var submit_default = defineCommand({
|
|
|
13391
13431
|
let prBody = null;
|
|
13392
13432
|
async function tryGenerateAI() {
|
|
13393
13433
|
const [copilotError, commits, diff] = await Promise.all([
|
|
13394
|
-
|
|
13434
|
+
checkCopilotAvailable2(),
|
|
13395
13435
|
getLog(baseBranch, "HEAD"),
|
|
13396
13436
|
getLogDiff(baseBranch, "HEAD")
|
|
13397
13437
|
]);
|
|
@@ -13403,10 +13443,10 @@ var submit_default = defineCommand({
|
|
|
13403
13443
|
prBody = result.body;
|
|
13404
13444
|
spinner.success("PR description generated.");
|
|
13405
13445
|
console.log(`
|
|
13406
|
-
${
|
|
13446
|
+
${import_picocolors17.default.dim("AI title:")} ${import_picocolors17.default.bold(import_picocolors17.default.cyan(prTitle))}`);
|
|
13407
13447
|
console.log(`
|
|
13408
|
-
${
|
|
13409
|
-
console.log(
|
|
13448
|
+
${import_picocolors17.default.dim("AI body preview:")}`);
|
|
13449
|
+
console.log(import_picocolors17.default.dim(prBody.slice(0, 300) + (prBody.length > 300 ? "..." : "")));
|
|
13410
13450
|
} else {
|
|
13411
13451
|
spinner.fail("AI did not return a PR description.");
|
|
13412
13452
|
}
|
|
@@ -13419,7 +13459,23 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13419
13459
|
const REGENERATE = "Regenerate AI description";
|
|
13420
13460
|
let submitAction = "cancel";
|
|
13421
13461
|
const isMaintainer = config.role === "maintainer";
|
|
13422
|
-
if (
|
|
13462
|
+
if (args.pullrequest && args.local) {
|
|
13463
|
+
error("Use only one submit mode flag at a time: --pullrequest/--pr/-pr or -l for local squash merge.");
|
|
13464
|
+
process.exit(1);
|
|
13465
|
+
}
|
|
13466
|
+
if (args.local && !isMaintainer) {
|
|
13467
|
+
error("The -l flag is only available for maintainers. Contributors must submit via PR.");
|
|
13468
|
+
process.exit(1);
|
|
13469
|
+
}
|
|
13470
|
+
if (args.local) {
|
|
13471
|
+
await performSquashMerge(origin, baseBranch, currentBranch, {
|
|
13472
|
+
model: args.model,
|
|
13473
|
+
convention: config.commitConvention,
|
|
13474
|
+
useAI: aiEnabled
|
|
13475
|
+
});
|
|
13476
|
+
return;
|
|
13477
|
+
}
|
|
13478
|
+
if (isMaintainer && !args.pullrequest) {
|
|
13423
13479
|
const maintainerChoice = await selectPrompt("How would you like to submit your changes?", ["Create a PR", SQUASH_LOCAL, CANCEL]);
|
|
13424
13480
|
if (maintainerChoice === CANCEL) {
|
|
13425
13481
|
warn("Submit cancelled.");
|
|
@@ -13428,12 +13484,13 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13428
13484
|
if (maintainerChoice === SQUASH_LOCAL) {
|
|
13429
13485
|
await performSquashMerge(origin, baseBranch, currentBranch, {
|
|
13430
13486
|
model: args.model,
|
|
13431
|
-
convention: config.commitConvention
|
|
13487
|
+
convention: config.commitConvention,
|
|
13488
|
+
useAI: aiEnabled
|
|
13432
13489
|
});
|
|
13433
13490
|
return;
|
|
13434
13491
|
}
|
|
13435
13492
|
}
|
|
13436
|
-
if (
|
|
13493
|
+
if (aiEnabled) {
|
|
13437
13494
|
await tryGenerateAI();
|
|
13438
13495
|
}
|
|
13439
13496
|
let actionResolved = false;
|
|
@@ -13472,7 +13529,7 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13472
13529
|
}
|
|
13473
13530
|
} else {
|
|
13474
13531
|
const choices = [];
|
|
13475
|
-
if (
|
|
13532
|
+
if (aiEnabled)
|
|
13476
13533
|
choices.push(REGENERATE);
|
|
13477
13534
|
choices.push("Write title & body manually", "Use gh --fill (auto-fill from commits)", CANCEL);
|
|
13478
13535
|
const action = await selectPrompt("How would you like to create the PR?", choices);
|
|
@@ -13496,7 +13553,7 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13496
13553
|
warn("Submit cancelled.");
|
|
13497
13554
|
return;
|
|
13498
13555
|
}
|
|
13499
|
-
info(`Pushing ${
|
|
13556
|
+
info(`Pushing ${import_picocolors17.default.bold(currentBranch)} to ${origin}...`);
|
|
13500
13557
|
const pushResult = await pushSetUpstream(origin, currentBranch);
|
|
13501
13558
|
if (pushResult.exitCode !== 0) {
|
|
13502
13559
|
error(`Failed to push: ${pushResult.stderr}`);
|
|
@@ -13515,7 +13572,7 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13515
13572
|
const prUrl = `https://github.com/${repoInfo.owner}/${repoInfo.repo}/compare/${baseBranch}...${currentBranch}?expand=1`;
|
|
13516
13573
|
console.log();
|
|
13517
13574
|
info("Create your PR manually:", "");
|
|
13518
|
-
console.log(` ${
|
|
13575
|
+
console.log(` ${import_picocolors17.default.cyan(prUrl)}`);
|
|
13519
13576
|
} else {
|
|
13520
13577
|
info("gh CLI not available. Create your PR manually on GitHub.", "");
|
|
13521
13578
|
}
|
|
@@ -13549,7 +13606,7 @@ ${import_picocolors16.default.dim("AI body preview:")}`);
|
|
|
13549
13606
|
});
|
|
13550
13607
|
|
|
13551
13608
|
// src/commands/switch.ts
|
|
13552
|
-
var
|
|
13609
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
13553
13610
|
var switch_default = defineCommand({
|
|
13554
13611
|
meta: {
|
|
13555
13612
|
name: "switch",
|
|
@@ -13570,7 +13627,7 @@ var switch_default = defineCommand({
|
|
|
13570
13627
|
const config = readConfig();
|
|
13571
13628
|
const protectedBranches = config ? getProtectedBranches(config) : ["main", "master"];
|
|
13572
13629
|
const currentBranch = await getCurrentBranch();
|
|
13573
|
-
|
|
13630
|
+
projectHeading("switch", "\uD83D\uDD00");
|
|
13574
13631
|
let targetBranch = args.name;
|
|
13575
13632
|
if (!targetBranch) {
|
|
13576
13633
|
const localBranches = await getLocalBranches();
|
|
@@ -13581,11 +13638,11 @@ var switch_default = defineCommand({
|
|
|
13581
13638
|
const choices = localBranches.filter((b2) => b2.name !== currentBranch).map((b2) => {
|
|
13582
13639
|
const labels = [];
|
|
13583
13640
|
if (protectedBranches.includes(b2.name))
|
|
13584
|
-
labels.push(
|
|
13641
|
+
labels.push(import_picocolors18.default.red("protected"));
|
|
13585
13642
|
if (b2.upstream)
|
|
13586
|
-
labels.push(
|
|
13643
|
+
labels.push(import_picocolors18.default.dim(`→ ${b2.upstream}`));
|
|
13587
13644
|
if (b2.gone)
|
|
13588
|
-
labels.push(
|
|
13645
|
+
labels.push(import_picocolors18.default.red("remote gone"));
|
|
13589
13646
|
const suffix = labels.length > 0 ? ` ${labels.join(" · ")}` : "";
|
|
13590
13647
|
return `${b2.name}${suffix}`;
|
|
13591
13648
|
});
|
|
@@ -13597,7 +13654,7 @@ var switch_default = defineCommand({
|
|
|
13597
13654
|
targetBranch = selected.split(/\s{2,}/)[0].trim();
|
|
13598
13655
|
}
|
|
13599
13656
|
if (targetBranch === currentBranch) {
|
|
13600
|
-
info(`Already on ${
|
|
13657
|
+
info(`Already on ${import_picocolors18.default.bold(targetBranch)}.`);
|
|
13601
13658
|
return;
|
|
13602
13659
|
}
|
|
13603
13660
|
if (await hasUncommittedChanges()) {
|
|
@@ -13616,7 +13673,7 @@ var switch_default = defineCommand({
|
|
|
13616
13673
|
const stashMsg = `contrib-save: auto-save from ${currentBranch}`;
|
|
13617
13674
|
try {
|
|
13618
13675
|
await exec("git", ["stash", "push", "-m", stashMsg]);
|
|
13619
|
-
info(`Saved changes: ${
|
|
13676
|
+
info(`Saved changes: ${import_picocolors18.default.dim(stashMsg)}`);
|
|
13620
13677
|
} catch {
|
|
13621
13678
|
error("Failed to save changes. Please commit or save manually.");
|
|
13622
13679
|
process.exit(1);
|
|
@@ -13632,9 +13689,9 @@ var switch_default = defineCommand({
|
|
|
13632
13689
|
}
|
|
13633
13690
|
process.exit(1);
|
|
13634
13691
|
}
|
|
13635
|
-
success(`Switched to ${
|
|
13636
|
-
info(`Your changes from ${
|
|
13637
|
-
info(`Use ${
|
|
13692
|
+
success(`Switched to ${import_picocolors18.default.bold(targetBranch)}`);
|
|
13693
|
+
info(`Your changes from ${import_picocolors18.default.bold(currentBranch ?? "previous branch")} are saved.`, "");
|
|
13694
|
+
info(`Use ${import_picocolors18.default.bold("contrib save --restore")} to bring them back.`, "");
|
|
13638
13695
|
return;
|
|
13639
13696
|
}
|
|
13640
13697
|
const result = await checkoutBranch(targetBranch);
|
|
@@ -13642,12 +13699,12 @@ var switch_default = defineCommand({
|
|
|
13642
13699
|
error(`Failed to switch to ${targetBranch}: ${result.stderr}`);
|
|
13643
13700
|
process.exit(1);
|
|
13644
13701
|
}
|
|
13645
|
-
success(`Switched to ${
|
|
13702
|
+
success(`Switched to ${import_picocolors18.default.bold(targetBranch)}`);
|
|
13646
13703
|
}
|
|
13647
13704
|
});
|
|
13648
13705
|
|
|
13649
13706
|
// src/commands/sync.ts
|
|
13650
|
-
var
|
|
13707
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
13651
13708
|
var sync_default = defineCommand({
|
|
13652
13709
|
meta: {
|
|
13653
13710
|
name: "sync",
|
|
@@ -13686,7 +13743,7 @@ var sync_default = defineCommand({
|
|
|
13686
13743
|
error("You have uncommitted changes. Please commit or stash them before syncing.");
|
|
13687
13744
|
process.exit(1);
|
|
13688
13745
|
}
|
|
13689
|
-
|
|
13746
|
+
projectHeading(`sync (${workflow}, ${role})`, "\uD83D\uDD04");
|
|
13690
13747
|
const baseBranch = getBaseBranch(config);
|
|
13691
13748
|
const syncSource = getSyncSource(config);
|
|
13692
13749
|
info(`Fetching ${syncSource.remote}...`);
|
|
@@ -13699,24 +13756,24 @@ var sync_default = defineCommand({
|
|
|
13699
13756
|
await fetchRemote(origin);
|
|
13700
13757
|
}
|
|
13701
13758
|
if (!await refExists(syncSource.ref)) {
|
|
13702
|
-
error(`Remote ref ${
|
|
13759
|
+
error(`Remote ref ${import_picocolors19.default.bold(syncSource.ref)} does not exist.`);
|
|
13703
13760
|
info("This can happen if the branch was renamed or deleted on the remote.", "");
|
|
13704
|
-
info(`Check your config: the base branch may need updating via ${
|
|
13761
|
+
info(`Check your config: the base branch may need updating via ${import_picocolors19.default.bold("contrib setup")}.`, "");
|
|
13705
13762
|
process.exit(1);
|
|
13706
13763
|
}
|
|
13707
13764
|
let allowMergeCommit = false;
|
|
13708
13765
|
const div = await getDivergence(baseBranch, syncSource.ref);
|
|
13709
13766
|
if (div.ahead > 0 || div.behind > 0) {
|
|
13710
|
-
info(`${
|
|
13767
|
+
info(`${import_picocolors19.default.bold(baseBranch)} is ${import_picocolors19.default.yellow(`${div.ahead} ahead`)} and ${import_picocolors19.default.red(`${div.behind} behind`)} ${syncSource.ref}`);
|
|
13711
13768
|
} else {
|
|
13712
|
-
info(`${
|
|
13769
|
+
info(`${import_picocolors19.default.bold(baseBranch)} is already in sync with ${syncSource.ref}`);
|
|
13713
13770
|
}
|
|
13714
13771
|
if (div.ahead > 0) {
|
|
13715
13772
|
const currentBranch = await getCurrentBranch();
|
|
13716
13773
|
const protectedBranches = getProtectedBranches(config);
|
|
13717
13774
|
const isOnProtected = currentBranch && protectedBranches.includes(currentBranch);
|
|
13718
13775
|
if (isOnProtected) {
|
|
13719
|
-
warn(`You have ${
|
|
13776
|
+
warn(`You have ${import_picocolors19.default.bold(String(div.ahead))} local commit${div.ahead !== 1 ? "s" : ""} on ${import_picocolors19.default.bold(baseBranch)} that aren't on the remote.`);
|
|
13720
13777
|
info("Pulling now could create a merge commit, which breaks clean history.");
|
|
13721
13778
|
console.log();
|
|
13722
13779
|
const MOVE_BRANCH = "Move my commits to a new feature branch, then sync";
|
|
@@ -13732,44 +13789,21 @@ var sync_default = defineCommand({
|
|
|
13732
13789
|
return;
|
|
13733
13790
|
}
|
|
13734
13791
|
if (action === MOVE_BRANCH) {
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
if (suggested) {
|
|
13744
|
-
spinner.success("Branch name suggestion ready.");
|
|
13745
|
-
console.log(`
|
|
13746
|
-
${import_picocolors18.default.dim("AI suggestion:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(suggested))}`);
|
|
13747
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors18.default.bold(suggested)} as your branch name?`);
|
|
13748
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
13749
|
-
} else {
|
|
13750
|
-
spinner.fail("AI did not return a suggestion.");
|
|
13751
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
13752
|
-
}
|
|
13753
|
-
}
|
|
13754
|
-
}
|
|
13755
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
13756
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors18.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
13757
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
13758
|
-
}
|
|
13759
|
-
if (!isValidBranchName(newBranchName)) {
|
|
13760
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
13761
|
-
process.exit(1);
|
|
13762
|
-
}
|
|
13763
|
-
if (await branchExists(newBranchName)) {
|
|
13764
|
-
error(`Branch ${import_picocolors18.default.bold(newBranchName)} already exists. Choose a different name.`);
|
|
13765
|
-
process.exit(1);
|
|
13792
|
+
const newBranchName = await promptForBranchName({
|
|
13793
|
+
branchPrefixes: config.branchPrefixes,
|
|
13794
|
+
useAI: isAIEnabled(config, args["no-ai"]),
|
|
13795
|
+
model: args.model
|
|
13796
|
+
});
|
|
13797
|
+
if (!newBranchName) {
|
|
13798
|
+
info("No changes made.");
|
|
13799
|
+
return;
|
|
13766
13800
|
}
|
|
13767
13801
|
const branchResult = await createBranch(newBranchName);
|
|
13768
13802
|
if (branchResult.exitCode !== 0) {
|
|
13769
13803
|
error(`Failed to create branch: ${branchResult.stderr}`);
|
|
13770
13804
|
process.exit(1);
|
|
13771
13805
|
}
|
|
13772
|
-
success(`Created ${
|
|
13806
|
+
success(`Created ${import_picocolors19.default.bold(newBranchName)} with your commits.`);
|
|
13773
13807
|
const coResult2 = await checkoutBranch(baseBranch);
|
|
13774
13808
|
if (coResult2.exitCode !== 0) {
|
|
13775
13809
|
error(`Failed to checkout ${baseBranch}: ${coResult2.stderr}`);
|
|
@@ -13777,11 +13811,11 @@ var sync_default = defineCommand({
|
|
|
13777
13811
|
}
|
|
13778
13812
|
const remoteRef = syncSource.ref;
|
|
13779
13813
|
await updateLocalBranch(baseBranch, remoteRef);
|
|
13780
|
-
success(`Reset ${
|
|
13781
|
-
success(`${
|
|
13814
|
+
success(`Reset ${import_picocolors19.default.bold(baseBranch)} to ${import_picocolors19.default.bold(remoteRef)}.`);
|
|
13815
|
+
success(`${import_picocolors19.default.bold(baseBranch)} is now in sync with ${syncSource.ref}`);
|
|
13782
13816
|
console.log();
|
|
13783
|
-
info(`Your commits are safe on ${
|
|
13784
|
-
info(`Run ${
|
|
13817
|
+
info(`Your commits are safe on ${import_picocolors19.default.bold(newBranchName)}.`, "");
|
|
13818
|
+
info(`Run ${import_picocolors19.default.bold(`git checkout ${newBranchName}`)} then ${import_picocolors19.default.bold("contrib update")} to rebase onto the synced ${import_picocolors19.default.bold(baseBranch)}.`, "");
|
|
13785
13819
|
return;
|
|
13786
13820
|
}
|
|
13787
13821
|
allowMergeCommit = true;
|
|
@@ -13789,7 +13823,7 @@ var sync_default = defineCommand({
|
|
|
13789
13823
|
}
|
|
13790
13824
|
}
|
|
13791
13825
|
if (!args.yes) {
|
|
13792
|
-
const ok = await confirmPrompt(`This will pull ${
|
|
13826
|
+
const ok = await confirmPrompt(`This will pull ${import_picocolors19.default.bold(syncSource.ref)} into local ${import_picocolors19.default.bold(baseBranch)}.`);
|
|
13793
13827
|
if (!ok)
|
|
13794
13828
|
process.exit(0);
|
|
13795
13829
|
}
|
|
@@ -13803,8 +13837,8 @@ var sync_default = defineCommand({
|
|
|
13803
13837
|
if (allowMergeCommit) {
|
|
13804
13838
|
error(`Pull failed: ${pullResult.stderr.trim()}`);
|
|
13805
13839
|
} else {
|
|
13806
|
-
error(`Fast-forward pull failed. Your local ${
|
|
13807
|
-
info(`Use ${
|
|
13840
|
+
error(`Fast-forward pull failed. Your local ${import_picocolors19.default.bold(baseBranch)} may have diverged.`);
|
|
13841
|
+
info(`Use ${import_picocolors19.default.bold("contrib sync")} again and choose "Move my commits to a new feature branch" to fix this.`, "");
|
|
13808
13842
|
}
|
|
13809
13843
|
process.exit(1);
|
|
13810
13844
|
}
|
|
@@ -13812,7 +13846,7 @@ var sync_default = defineCommand({
|
|
|
13812
13846
|
if (hasDevBranch(workflow) && role === "maintainer") {
|
|
13813
13847
|
const mainDiv = await getDivergence(config.mainBranch, `${origin}/${config.mainBranch}`);
|
|
13814
13848
|
if (mainDiv.behind > 0) {
|
|
13815
|
-
info(`Also syncing ${
|
|
13849
|
+
info(`Also syncing ${import_picocolors19.default.bold(config.mainBranch)}...`);
|
|
13816
13850
|
const mainCoResult = await checkoutBranch(config.mainBranch);
|
|
13817
13851
|
if (mainCoResult.exitCode === 0) {
|
|
13818
13852
|
const mainPullResult = await pullFastForwardOnly(origin, config.mainBranch);
|
|
@@ -13850,20 +13884,20 @@ var sync_default = defineCommand({
|
|
|
13850
13884
|
groups.get(hash).push(name);
|
|
13851
13885
|
}
|
|
13852
13886
|
console.log();
|
|
13853
|
-
console.log(` ${
|
|
13887
|
+
console.log(` ${import_picocolors19.default.bold("\uD83D\uDD17 Branch Alignment")}`);
|
|
13854
13888
|
for (const [hash, names] of groups) {
|
|
13855
13889
|
const short = hash.slice(0, 7);
|
|
13856
|
-
const nameStr = names.map((n2) =>
|
|
13857
|
-
console.log(` ${
|
|
13890
|
+
const nameStr = names.map((n2) => import_picocolors19.default.bold(n2)).join(import_picocolors19.default.dim(" · "));
|
|
13891
|
+
console.log(` ${import_picocolors19.default.yellow(short)} ${import_picocolors19.default.dim("──")} ${nameStr}`);
|
|
13858
13892
|
const subject = await getCommitSubject(hash);
|
|
13859
13893
|
if (subject) {
|
|
13860
|
-
console.log(` ${
|
|
13894
|
+
console.log(` ${import_picocolors19.default.dim(subject)}`);
|
|
13861
13895
|
}
|
|
13862
13896
|
}
|
|
13863
13897
|
if (groups.size === 1) {
|
|
13864
|
-
console.log(` ${
|
|
13898
|
+
console.log(` ${import_picocolors19.default.green("✓")} ${import_picocolors19.default.green("All branches aligned")} ${import_picocolors19.default.dim("— ready to start")}`);
|
|
13865
13899
|
} else {
|
|
13866
|
-
console.log(` ${
|
|
13900
|
+
console.log(` ${import_picocolors19.default.yellow("⚠")} ${import_picocolors19.default.yellow("Branches are not fully aligned")}`);
|
|
13867
13901
|
}
|
|
13868
13902
|
}
|
|
13869
13903
|
}
|
|
@@ -13872,7 +13906,7 @@ var sync_default = defineCommand({
|
|
|
13872
13906
|
|
|
13873
13907
|
// src/commands/update.ts
|
|
13874
13908
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
13875
|
-
var
|
|
13909
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
13876
13910
|
var update_default = defineCommand({
|
|
13877
13911
|
meta: {
|
|
13878
13912
|
name: "update",
|
|
@@ -13909,8 +13943,8 @@ var update_default = defineCommand({
|
|
|
13909
13943
|
process.exit(1);
|
|
13910
13944
|
}
|
|
13911
13945
|
if (protectedBranches.includes(currentBranch)) {
|
|
13912
|
-
|
|
13913
|
-
warn(`You're on ${
|
|
13946
|
+
projectHeading("update", "\uD83D\uDD03");
|
|
13947
|
+
warn(`You're on ${import_picocolors20.default.bold(currentBranch)}, which is a protected branch. Updates (rebase) apply to feature branches.`);
|
|
13914
13948
|
await fetchAll();
|
|
13915
13949
|
const { origin } = config;
|
|
13916
13950
|
const remoteRef = `${origin}/${currentBranch}`;
|
|
@@ -13919,12 +13953,12 @@ var update_default = defineCommand({
|
|
|
13919
13953
|
const hasCommits = localWork.unpushedCommits > 0;
|
|
13920
13954
|
const hasAnything = hasCommits || dirty;
|
|
13921
13955
|
if (!hasAnything) {
|
|
13922
|
-
info(`No local changes found on ${
|
|
13923
|
-
info(`Use ${
|
|
13956
|
+
info(`No local changes found on ${import_picocolors20.default.bold(currentBranch)}.`);
|
|
13957
|
+
info(`Use ${import_picocolors20.default.bold("contrib sync")} to sync protected branches, or ${import_picocolors20.default.bold("contrib start")} to create a feature branch.`);
|
|
13924
13958
|
process.exit(1);
|
|
13925
13959
|
}
|
|
13926
13960
|
if (hasCommits) {
|
|
13927
|
-
info(`Found ${
|
|
13961
|
+
info(`Found ${import_picocolors20.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors20.default.bold(currentBranch)}.`);
|
|
13928
13962
|
}
|
|
13929
13963
|
if (dirty) {
|
|
13930
13964
|
info("You also have uncommitted changes in the working tree.");
|
|
@@ -13940,56 +13974,37 @@ var update_default = defineCommand({
|
|
|
13940
13974
|
info("No changes made. You are still on your current branch.");
|
|
13941
13975
|
return;
|
|
13942
13976
|
}
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
if (suggested) {
|
|
13952
|
-
spinner.success("Branch name suggestion ready.");
|
|
13953
|
-
console.log(`
|
|
13954
|
-
${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(suggested))}`);
|
|
13955
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors19.default.bold(suggested)} as your branch name?`);
|
|
13956
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
13957
|
-
} else {
|
|
13958
|
-
spinner.fail("AI did not return a suggestion.");
|
|
13959
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
13960
|
-
}
|
|
13961
|
-
}
|
|
13962
|
-
}
|
|
13963
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
13964
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors19.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
13965
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
13966
|
-
}
|
|
13967
|
-
if (!isValidBranchName(newBranchName)) {
|
|
13968
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
13969
|
-
process.exit(1);
|
|
13977
|
+
const newBranchName = await promptForBranchName({
|
|
13978
|
+
branchPrefixes: config.branchPrefixes,
|
|
13979
|
+
useAI: isAIEnabled(config, args["no-ai"]),
|
|
13980
|
+
model: args.model
|
|
13981
|
+
});
|
|
13982
|
+
if (!newBranchName) {
|
|
13983
|
+
info("No changes made. You are still on your current branch.");
|
|
13984
|
+
return;
|
|
13970
13985
|
}
|
|
13971
13986
|
const branchResult = await createBranch(newBranchName);
|
|
13972
13987
|
if (branchResult.exitCode !== 0) {
|
|
13973
13988
|
error(`Failed to create branch: ${branchResult.stderr}`);
|
|
13974
13989
|
process.exit(1);
|
|
13975
13990
|
}
|
|
13976
|
-
success(`Created ${
|
|
13991
|
+
success(`Created ${import_picocolors20.default.bold(newBranchName)} with your changes.`);
|
|
13977
13992
|
await updateLocalBranch(currentBranch, remoteRef);
|
|
13978
|
-
info(`Reset ${
|
|
13993
|
+
info(`Reset ${import_picocolors20.default.bold(currentBranch)} back to ${import_picocolors20.default.bold(remoteRef)} — no damage done.`, "");
|
|
13979
13994
|
console.log();
|
|
13980
|
-
success(`You're now on ${
|
|
13981
|
-
info(`Run ${
|
|
13995
|
+
success(`You're now on ${import_picocolors20.default.bold(newBranchName)} with all your work intact.`);
|
|
13996
|
+
info(`Run ${import_picocolors20.default.bold("contrib update")} again to rebase onto latest ${import_picocolors20.default.bold(baseBranch)}.`, "");
|
|
13982
13997
|
return;
|
|
13983
13998
|
}
|
|
13984
13999
|
if (await hasUncommittedChanges()) {
|
|
13985
14000
|
error("You have uncommitted changes. Please commit or stash them first.");
|
|
13986
14001
|
process.exit(1);
|
|
13987
14002
|
}
|
|
13988
|
-
|
|
14003
|
+
projectHeading("update", "\uD83D\uDD03");
|
|
13989
14004
|
const mergedPR = await getMergedPRForBranch(currentBranch);
|
|
13990
14005
|
if (mergedPR) {
|
|
13991
|
-
warn(`PR #${mergedPR.number} (${
|
|
13992
|
-
info(`Link: ${
|
|
14006
|
+
warn(`PR #${mergedPR.number} (${import_picocolors20.default.bold(mergedPR.title)}) has already been merged.`);
|
|
14007
|
+
info(`Link: ${import_picocolors20.default.underline(mergedPR.url)}`, "");
|
|
13993
14008
|
const localWork = await hasLocalWork(syncSource.remote, currentBranch);
|
|
13994
14009
|
const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
|
|
13995
14010
|
if (hasWork) {
|
|
@@ -14002,49 +14017,29 @@ var update_default = defineCommand({
|
|
|
14002
14017
|
const SAVE_NEW_BRANCH = "Save changes to a new branch";
|
|
14003
14018
|
const DISCARD = "Discard all changes and clean up";
|
|
14004
14019
|
const CANCEL = "Cancel";
|
|
14005
|
-
const action = await selectPrompt(`${
|
|
14020
|
+
const action = await selectPrompt(`${import_picocolors20.default.bold(currentBranch)} is stale but has local work. What would you like to do?`, [SAVE_NEW_BRANCH, DISCARD, CANCEL]);
|
|
14006
14021
|
if (action === CANCEL) {
|
|
14007
14022
|
info("No changes made. You are still on your current branch.");
|
|
14008
14023
|
return;
|
|
14009
14024
|
}
|
|
14010
14025
|
if (action === SAVE_NEW_BRANCH) {
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
console.log(`
|
|
14020
|
-
${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(suggested))}`);
|
|
14021
|
-
const accepted = await confirmPrompt(`Use ${import_picocolors19.default.bold(suggested)} as your branch name?`);
|
|
14022
|
-
newBranchName = accepted ? suggested : await inputPrompt("Enter branch name", description);
|
|
14023
|
-
} else {
|
|
14024
|
-
spinner.fail("AI did not return a suggestion.");
|
|
14025
|
-
newBranchName = await inputPrompt("Enter branch name", description);
|
|
14026
|
-
}
|
|
14027
|
-
}
|
|
14028
|
-
if (!hasPrefix(newBranchName, config.branchPrefixes)) {
|
|
14029
|
-
const prefix = await selectPrompt(`Choose a branch type for ${import_picocolors19.default.bold(newBranchName)}:`, config.branchPrefixes);
|
|
14030
|
-
newBranchName = formatBranchName(prefix, newBranchName);
|
|
14031
|
-
}
|
|
14032
|
-
if (!isValidBranchName(newBranchName)) {
|
|
14033
|
-
error("Invalid branch name. Use only alphanumeric characters, dots, hyphens, underscores, and slashes.");
|
|
14034
|
-
process.exit(1);
|
|
14026
|
+
const newBranchName = await promptForBranchName({
|
|
14027
|
+
branchPrefixes: config.branchPrefixes,
|
|
14028
|
+
useAI: isAIEnabled(config, args["no-ai"]),
|
|
14029
|
+
model: args.model
|
|
14030
|
+
});
|
|
14031
|
+
if (!newBranchName) {
|
|
14032
|
+
info("No changes made. You are still on your current branch.");
|
|
14033
|
+
return;
|
|
14035
14034
|
}
|
|
14036
14035
|
const staleUpstream = await getUpstreamRef();
|
|
14037
14036
|
const staleUpstreamHash = staleUpstream ? await getCommitHash(staleUpstream) : null;
|
|
14038
|
-
if (await branchExists(newBranchName)) {
|
|
14039
|
-
error(`Branch ${import_picocolors19.default.bold(newBranchName)} already exists. Choose a different name.`);
|
|
14040
|
-
process.exit(1);
|
|
14041
|
-
}
|
|
14042
14037
|
const renameResult = await renameBranch(currentBranch, newBranchName);
|
|
14043
14038
|
if (renameResult.exitCode !== 0) {
|
|
14044
14039
|
error(`Failed to rename branch: ${renameResult.stderr}`);
|
|
14045
14040
|
process.exit(1);
|
|
14046
14041
|
}
|
|
14047
|
-
success(`Renamed ${
|
|
14042
|
+
success(`Renamed ${import_picocolors20.default.bold(currentBranch)} → ${import_picocolors20.default.bold(newBranchName)}`);
|
|
14048
14043
|
await unsetUpstream();
|
|
14049
14044
|
await fetchRemote(syncSource.remote);
|
|
14050
14045
|
let rebaseResult2;
|
|
@@ -14056,11 +14051,11 @@ var update_default = defineCommand({
|
|
|
14056
14051
|
}
|
|
14057
14052
|
if (rebaseResult2.exitCode !== 0) {
|
|
14058
14053
|
warn("Rebase encountered conflicts. Resolve them manually, then run:");
|
|
14059
|
-
info(` ${
|
|
14054
|
+
info(` ${import_picocolors20.default.bold("git rebase --continue")}`, "");
|
|
14060
14055
|
} else {
|
|
14061
|
-
success(`Rebased ${
|
|
14056
|
+
success(`Rebased ${import_picocolors20.default.bold(newBranchName)} onto ${import_picocolors20.default.bold(syncSource.ref)}.`);
|
|
14062
14057
|
}
|
|
14063
|
-
info(`All your changes are preserved. Run ${
|
|
14058
|
+
info(`All your changes are preserved. Run ${import_picocolors20.default.bold("contrib submit")} when ready to create a new PR.`, "");
|
|
14064
14059
|
return;
|
|
14065
14060
|
}
|
|
14066
14061
|
warn("Discarding local changes...");
|
|
@@ -14073,30 +14068,30 @@ var update_default = defineCommand({
|
|
|
14073
14068
|
process.exit(1);
|
|
14074
14069
|
}
|
|
14075
14070
|
await updateLocalBranch(baseBranch, syncSource.ref);
|
|
14076
|
-
success(`Synced ${
|
|
14077
|
-
info(`Deleting stale branch ${
|
|
14071
|
+
success(`Synced ${import_picocolors20.default.bold(baseBranch)} with ${import_picocolors20.default.bold(syncSource.ref)}.`);
|
|
14072
|
+
info(`Deleting stale branch ${import_picocolors20.default.bold(currentBranch)}...`);
|
|
14078
14073
|
await forceDeleteBranch(currentBranch);
|
|
14079
|
-
success(`Deleted ${
|
|
14080
|
-
info(`Run ${
|
|
14074
|
+
success(`Deleted ${import_picocolors20.default.bold(currentBranch)}.`);
|
|
14075
|
+
info(`Run ${import_picocolors20.default.bold("contrib start")} to begin a new feature branch.`, "");
|
|
14081
14076
|
return;
|
|
14082
14077
|
}
|
|
14083
|
-
info(`Updating ${
|
|
14078
|
+
info(`Updating ${import_picocolors20.default.bold(currentBranch)} with latest ${import_picocolors20.default.bold(baseBranch)}...`);
|
|
14084
14079
|
await fetchRemote(syncSource.remote);
|
|
14085
14080
|
if (!await refExists(syncSource.ref)) {
|
|
14086
|
-
error(`Remote ref ${
|
|
14081
|
+
error(`Remote ref ${import_picocolors20.default.bold(syncSource.ref)} does not exist.`);
|
|
14087
14082
|
error("Run `git fetch --all` and verify your remote configuration.");
|
|
14088
14083
|
process.exit(1);
|
|
14089
14084
|
}
|
|
14090
14085
|
await updateLocalBranch(baseBranch, syncSource.ref);
|
|
14091
14086
|
const rebaseStrategy = await determineRebaseStrategy(currentBranch, syncSource.ref);
|
|
14092
14087
|
if (rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase) {
|
|
14093
|
-
info(
|
|
14088
|
+
info(import_picocolors20.default.dim(`Using --onto rebase (branch was based on a different ref)`));
|
|
14094
14089
|
}
|
|
14095
14090
|
const rebaseResult = rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase ? await rebaseOnto(syncSource.ref, rebaseStrategy.ontoOldBase) : await rebase(syncSource.ref);
|
|
14096
14091
|
if (rebaseResult.exitCode !== 0) {
|
|
14097
14092
|
warn("Rebase hit conflicts. Resolve them manually.");
|
|
14098
14093
|
console.log();
|
|
14099
|
-
if (
|
|
14094
|
+
if (isAIEnabled(config, args["no-ai"])) {
|
|
14100
14095
|
const copilotError = await checkCopilotAvailable();
|
|
14101
14096
|
if (!copilotError) {
|
|
14102
14097
|
info("Fetching AI conflict resolution suggestions...");
|
|
@@ -14119,10 +14114,10 @@ ${content.slice(0, 2000)}
|
|
|
14119
14114
|
if (suggestion) {
|
|
14120
14115
|
spinner.success("AI conflict guidance ready.");
|
|
14121
14116
|
console.log(`
|
|
14122
|
-
${
|
|
14123
|
-
console.log(
|
|
14117
|
+
${import_picocolors20.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance:")}`);
|
|
14118
|
+
console.log(import_picocolors20.default.dim("─".repeat(60)));
|
|
14124
14119
|
console.log(suggestion);
|
|
14125
|
-
console.log(
|
|
14120
|
+
console.log(import_picocolors20.default.dim("─".repeat(60)));
|
|
14126
14121
|
console.log();
|
|
14127
14122
|
} else {
|
|
14128
14123
|
spinner.fail("AI could not analyze the conflicts.");
|
|
@@ -14130,20 +14125,20 @@ ${import_picocolors19.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance
|
|
|
14130
14125
|
}
|
|
14131
14126
|
}
|
|
14132
14127
|
}
|
|
14133
|
-
console.log(
|
|
14128
|
+
console.log(import_picocolors20.default.bold("To resolve:"));
|
|
14134
14129
|
console.log(` 1. Fix conflicts in the affected files`);
|
|
14135
|
-
console.log(` 2. ${
|
|
14136
|
-
console.log(` 3. ${
|
|
14130
|
+
console.log(` 2. ${import_picocolors20.default.cyan("git add <resolved-files>")}`);
|
|
14131
|
+
console.log(` 3. ${import_picocolors20.default.cyan("git rebase --continue")}`);
|
|
14137
14132
|
console.log();
|
|
14138
|
-
console.log(` Or abort: ${
|
|
14133
|
+
console.log(` Or abort: ${import_picocolors20.default.cyan("git rebase --abort")}`);
|
|
14139
14134
|
process.exit(1);
|
|
14140
14135
|
}
|
|
14141
|
-
success(`${
|
|
14136
|
+
success(`${import_picocolors20.default.bold(currentBranch)} has been rebased onto latest ${import_picocolors20.default.bold(baseBranch)}`);
|
|
14142
14137
|
}
|
|
14143
14138
|
});
|
|
14144
14139
|
|
|
14145
14140
|
// src/commands/validate.ts
|
|
14146
|
-
var
|
|
14141
|
+
var import_picocolors21 = __toESM(require_picocolors(), 1);
|
|
14147
14142
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
14148
14143
|
var validate_default = defineCommand({
|
|
14149
14144
|
meta: {
|
|
@@ -14183,7 +14178,7 @@ var validate_default = defineCommand({
|
|
|
14183
14178
|
}
|
|
14184
14179
|
const errors = getValidationError(convention);
|
|
14185
14180
|
for (const line of errors) {
|
|
14186
|
-
console.error(
|
|
14181
|
+
console.error(import_picocolors21.default.red(` ✗ ${line}`));
|
|
14187
14182
|
}
|
|
14188
14183
|
process.exit(1);
|
|
14189
14184
|
}
|
|
@@ -15578,7 +15573,7 @@ nodeFiglet.fontsSync = function() {
|
|
|
15578
15573
|
};
|
|
15579
15574
|
|
|
15580
15575
|
// src/ui/banner.ts
|
|
15581
|
-
var
|
|
15576
|
+
var import_picocolors22 = __toESM(require_picocolors(), 1);
|
|
15582
15577
|
var LOGO_BIG;
|
|
15583
15578
|
try {
|
|
15584
15579
|
LOGO_BIG = nodeFiglet.textSync(`Contribute
|
|
@@ -15600,19 +15595,33 @@ function getAuthor() {
|
|
|
15600
15595
|
}
|
|
15601
15596
|
function showBanner(variant = "small") {
|
|
15602
15597
|
const logo = variant === "big" ? LOGO_BIG : LOGO_SMALL;
|
|
15603
|
-
console.log(
|
|
15598
|
+
console.log(import_picocolors22.default.cyan(`
|
|
15604
15599
|
${logo}`));
|
|
15605
|
-
console.log(` ${
|
|
15600
|
+
console.log(` ${import_picocolors22.default.dim(`v${getVersion()}`)} ${import_picocolors22.default.dim("—")} ${import_picocolors22.default.dim(`Built by ${getAuthor()}`)}`);
|
|
15606
15601
|
if (variant === "big") {
|
|
15607
15602
|
console.log();
|
|
15608
|
-
console.log(` ${
|
|
15609
|
-
console.log(` ${
|
|
15610
|
-
console.log(` ${
|
|
15603
|
+
console.log(` ${import_picocolors22.default.yellow("Star")} ${import_picocolors22.default.cyan("https://github.com/warengonzaga/contribute-now")}`);
|
|
15604
|
+
console.log(` ${import_picocolors22.default.green("Contribute")} ${import_picocolors22.default.cyan("https://github.com/warengonzaga/contribute-now/blob/main/CONTRIBUTING.md")}`);
|
|
15605
|
+
console.log(` ${import_picocolors22.default.magenta("Sponsor")} ${import_picocolors22.default.cyan("https://warengonzaga.com/sponsor")}`);
|
|
15611
15606
|
}
|
|
15612
15607
|
console.log();
|
|
15613
15608
|
}
|
|
15614
15609
|
|
|
15615
15610
|
// src/index.ts
|
|
15611
|
+
function normalizeCliArgs(argv2) {
|
|
15612
|
+
return argv2.map((arg, index) => {
|
|
15613
|
+
const previous = argv2[index - 1];
|
|
15614
|
+
const isSubmitCommand = previous === "submit" || argv2.includes("submit");
|
|
15615
|
+
if (!isSubmitCommand) {
|
|
15616
|
+
return arg;
|
|
15617
|
+
}
|
|
15618
|
+
if (arg === "-pr" || arg === "--pr") {
|
|
15619
|
+
return "--pullrequest";
|
|
15620
|
+
}
|
|
15621
|
+
return arg;
|
|
15622
|
+
});
|
|
15623
|
+
}
|
|
15624
|
+
process.argv = normalizeCliArgs(process.argv);
|
|
15616
15625
|
var isVersion = process.argv.includes("--version") || process.argv.includes("-v");
|
|
15617
15626
|
if (!isVersion) {
|
|
15618
15627
|
const subCommands = [
|