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