contribute-now 0.6.2-dev.38e14f5 → 0.6.2-dev.3d69403
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +150 -37
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10103,12 +10103,12 @@ async function multiSelectPrompt(message, choices) {
|
|
|
10103
10103
|
init_dist();
|
|
10104
10104
|
var CONVENTIONAL_COMMIT_SYSTEM_PROMPT = `Git commit message generator. Format: <type>[!][(<scope>)]: <description>
|
|
10105
10105
|
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
|
|
10106
|
-
Rules: breaking (!) only for feat/fix/refactor/perf; imperative mood; max 72 chars; lowercase start; scope optional camelCase/kebab-case. Return ONLY the message line.
|
|
10106
|
+
Rules: breaking (!) only for feat/fix/refactor/perf; imperative mood; max 72 chars; lowercase start; scope optional camelCase/kebab-case. Do NOT use backticks, quotes, or markdown formatting around filenames, functions, or identifiers. Return ONLY the message line.
|
|
10107
10107
|
Examples: feat: add user auth | fix(auth): resolve token expiry | feat!: redesign auth API`;
|
|
10108
10108
|
var CLEAN_COMMIT_SYSTEM_PROMPT = `Git commit message generator. EXACT format: <emoji> <type>[!][ (<scope>)]: <description>
|
|
10109
10109
|
Spacing: EMOJI SPACE TYPE [SPACE OPENPAREN SCOPE CLOSEPAREN] COLON SPACE DESCRIPTION
|
|
10110
10110
|
Types: \uD83D\uDCE6 new, \uD83D\uDD27 update, \uD83D\uDDD1️ remove, \uD83D\uDD12 security, ⚙️ setup, ☕ chore, \uD83E\uDDEA test, \uD83D\uDCD6 docs, \uD83D\uDE80 release
|
|
10111
|
-
Rules: breaking (!) only for new/update/remove/security; imperative mood; max 72 chars; lowercase start; scope optional. Return ONLY the message line.
|
|
10111
|
+
Rules: breaking (!) only for new/update/remove/security; imperative mood; max 72 chars; lowercase start; scope optional. Do NOT use backticks, quotes, or markdown formatting around filenames, functions, or identifiers. Return ONLY the message line.
|
|
10112
10112
|
Correct: \uD83D\uDCE6 new: add user auth | \uD83D\uDD27 update (api): improve error handling | ⚙️ setup (ci): configure github actions
|
|
10113
10113
|
WRONG: ⚙️setup(ci): ... | \uD83D\uDD27 update(api): ... ← always space before scope parenthesis`;
|
|
10114
10114
|
function getGroupingSystemPrompt(convention) {
|
|
@@ -10133,6 +10133,7 @@ Rules:
|
|
|
10133
10133
|
- Each group should represent ONE logical change
|
|
10134
10134
|
- Every file must appear in exactly one group
|
|
10135
10135
|
- Commit messages must follow the convention, be concise, imperative, max 72 chars
|
|
10136
|
+
- Do not use backticks, quotes, or markdown formatting in commit messages
|
|
10136
10137
|
- Order groups so foundational changes come first (types, utils) and consumers come after
|
|
10137
10138
|
- Return ONLY the JSON array, nothing else`;
|
|
10138
10139
|
}
|
|
@@ -10351,6 +10352,9 @@ function extractJson(raw) {
|
|
|
10351
10352
|
}
|
|
10352
10353
|
return text;
|
|
10353
10354
|
}
|
|
10355
|
+
function sanitizeGeneratedCommitMessage(message) {
|
|
10356
|
+
return message.replace(/`+/g, "").replace(/\s+/g, " ").trim();
|
|
10357
|
+
}
|
|
10354
10358
|
async function generateCommitMessage(diff, stagedFiles, model, convention = "clean-commit", context) {
|
|
10355
10359
|
try {
|
|
10356
10360
|
const isLarge = stagedFiles.length >= BATCH_CONFIG.LARGE_CHANGESET_THRESHOLD;
|
|
@@ -10368,7 +10372,7 @@ Files (${stagedFiles.length}): ${stagedFiles.join(", ")}
|
|
|
10368
10372
|
Diff:
|
|
10369
10373
|
${diffContent}${multiFileHint}${squashHint}`;
|
|
10370
10374
|
const result = await callCopilot(getCommitSystemPrompt(convention), userMessage, model, isLarge ? COPILOT_LONG_TIMEOUT_MS : COPILOT_TIMEOUT_MS);
|
|
10371
|
-
return result
|
|
10375
|
+
return result ? sanitizeGeneratedCommitMessage(result) : null;
|
|
10372
10376
|
} catch {
|
|
10373
10377
|
return null;
|
|
10374
10378
|
}
|
|
@@ -10415,6 +10419,40 @@ ${conflictDiff.slice(0, 4000)}`;
|
|
|
10415
10419
|
return null;
|
|
10416
10420
|
}
|
|
10417
10421
|
}
|
|
10422
|
+
function normalizeCommitGroups(changedFiles, groups) {
|
|
10423
|
+
const changedSet = new Set(changedFiles);
|
|
10424
|
+
const assignedFiles = new Set;
|
|
10425
|
+
const unknownFiles = new Set;
|
|
10426
|
+
const duplicateFiles = new Set;
|
|
10427
|
+
const normalizedGroups = groups.map((group) => {
|
|
10428
|
+
const uniqueFiles = new Set;
|
|
10429
|
+
const files = [];
|
|
10430
|
+
for (const file of group.files) {
|
|
10431
|
+
if (!changedSet.has(file)) {
|
|
10432
|
+
unknownFiles.add(file);
|
|
10433
|
+
continue;
|
|
10434
|
+
}
|
|
10435
|
+
if (uniqueFiles.has(file) || assignedFiles.has(file)) {
|
|
10436
|
+
duplicateFiles.add(file);
|
|
10437
|
+
continue;
|
|
10438
|
+
}
|
|
10439
|
+
uniqueFiles.add(file);
|
|
10440
|
+
assignedFiles.add(file);
|
|
10441
|
+
files.push(file);
|
|
10442
|
+
}
|
|
10443
|
+
return {
|
|
10444
|
+
...group,
|
|
10445
|
+
files
|
|
10446
|
+
};
|
|
10447
|
+
}).filter((group) => group.files.length > 0);
|
|
10448
|
+
const unassignedFiles = changedFiles.filter((file) => !assignedFiles.has(file));
|
|
10449
|
+
return {
|
|
10450
|
+
groups: normalizedGroups,
|
|
10451
|
+
unknownFiles: [...unknownFiles],
|
|
10452
|
+
duplicateFiles: [...duplicateFiles],
|
|
10453
|
+
unassignedFiles
|
|
10454
|
+
};
|
|
10455
|
+
}
|
|
10418
10456
|
async function generateCommitGroups(files, diffs, model, convention = "clean-commit") {
|
|
10419
10457
|
const isLarge = files.length >= BATCH_CONFIG.LARGE_CHANGESET_THRESHOLD;
|
|
10420
10458
|
const diffContent = isLarge ? createCompactDiff(files, diffs) : diffs.slice(0, 6000);
|
|
@@ -10455,7 +10493,10 @@ ${diffContent}${largeHint}`;
|
|
|
10455
10493
|
throw new Error("AI returned groups with invalid structure (missing files or message)");
|
|
10456
10494
|
}
|
|
10457
10495
|
}
|
|
10458
|
-
return groups
|
|
10496
|
+
return groups.map((group) => ({
|
|
10497
|
+
...group,
|
|
10498
|
+
message: sanitizeGeneratedCommitMessage(group.message)
|
|
10499
|
+
}));
|
|
10459
10500
|
}
|
|
10460
10501
|
async function generateCommitGroupsInBatches(files, diffs, model, convention = "clean-commit") {
|
|
10461
10502
|
const batchSize = BATCH_CONFIG.FALLBACK_BATCH_SIZE;
|
|
@@ -10490,7 +10531,11 @@ NOTE: Processing batch ${batchNum}/${totalBatches} of a large changeset. Group o
|
|
|
10490
10531
|
const batchFileSet = new Set(batchFiles);
|
|
10491
10532
|
const filteredFiles = group.files.filter((f3) => batchFileSet.has(f3));
|
|
10492
10533
|
if (filteredFiles.length > 0) {
|
|
10493
|
-
allGroups.push({
|
|
10534
|
+
allGroups.push({
|
|
10535
|
+
...group,
|
|
10536
|
+
files: filteredFiles,
|
|
10537
|
+
message: sanitizeGeneratedCommitMessage(group.message)
|
|
10538
|
+
});
|
|
10494
10539
|
}
|
|
10495
10540
|
}
|
|
10496
10541
|
}
|
|
@@ -10533,7 +10578,7 @@ ${diffContent}`;
|
|
|
10533
10578
|
return groups;
|
|
10534
10579
|
return groups.map((g3, i2) => ({
|
|
10535
10580
|
files: g3.files,
|
|
10536
|
-
message: typeof parsed[i2]?.message === "string" ? parsed[i2].message : g3.message
|
|
10581
|
+
message: typeof parsed[i2]?.message === "string" ? sanitizeGeneratedCommitMessage(parsed[i2].message) : g3.message
|
|
10537
10582
|
}));
|
|
10538
10583
|
} catch {
|
|
10539
10584
|
return groups;
|
|
@@ -10550,7 +10595,7 @@ Files: ${files.join(", ")}
|
|
|
10550
10595
|
Diff:
|
|
10551
10596
|
${diffContent}`;
|
|
10552
10597
|
const result = await callCopilot(getCommitSystemPrompt(convention), userMessage, model);
|
|
10553
|
-
return result
|
|
10598
|
+
return result ? sanitizeGeneratedCommitMessage(result) : null;
|
|
10554
10599
|
} catch {
|
|
10555
10600
|
return null;
|
|
10556
10601
|
}
|
|
@@ -10986,17 +11031,24 @@ var CONVENTION_FORMAT_HINTS = {
|
|
|
10986
11031
|
conventional: [
|
|
10987
11032
|
"Format: <type>[!][(<scope>)]: <description>",
|
|
10988
11033
|
"Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert",
|
|
10989
|
-
"Examples: feat: add login page | fix(auth): resolve token expiry | docs: update README"
|
|
11034
|
+
"Examples: feat: add login page | fix(auth): resolve token expiry | docs: update README",
|
|
11035
|
+
"Do not use backticks or markdown formatting in the message."
|
|
10990
11036
|
],
|
|
10991
11037
|
"clean-commit": [
|
|
10992
11038
|
"Format: <emoji> <type>[!][(<scope>)]: <description>",
|
|
10993
11039
|
"Types: \uD83D\uDCE6 new | \uD83D\uDD27 update | \uD83D\uDDD1️ remove | \uD83D\uDD12 security | ⚙️ setup | ☕ chore | \uD83E\uDDEA test | \uD83D\uDCD6 docs | \uD83D\uDE80 release",
|
|
10994
|
-
"Examples: \uD83D\uDCE6 new: user auth | \uD83D\uDD27 update (api): improve errors | ⚙️ setup (ci): add workflow"
|
|
11040
|
+
"Examples: \uD83D\uDCE6 new: user auth | \uD83D\uDD27 update (api): improve errors | ⚙️ setup (ci): add workflow",
|
|
11041
|
+
"Do not use backticks or markdown formatting in the message."
|
|
10995
11042
|
]
|
|
10996
11043
|
};
|
|
11044
|
+
function hasUnsupportedCommitMessageChars(message) {
|
|
11045
|
+
return message.includes("`");
|
|
11046
|
+
}
|
|
10997
11047
|
function validateCommitMessage(message, convention) {
|
|
10998
11048
|
if (convention === "none")
|
|
10999
11049
|
return true;
|
|
11050
|
+
if (hasUnsupportedCommitMessageChars(message))
|
|
11051
|
+
return false;
|
|
11000
11052
|
if (convention === "clean-commit")
|
|
11001
11053
|
return CLEAN_COMMIT_PATTERN.test(message);
|
|
11002
11054
|
if (convention === "conventional")
|
|
@@ -11008,6 +11060,7 @@ function getValidationError(convention) {
|
|
|
11008
11060
|
return [];
|
|
11009
11061
|
return [
|
|
11010
11062
|
`Commit message does not follow ${CONVENTION_LABELS[convention]} format.`,
|
|
11063
|
+
"Do not use backticks or markdown formatting in commit messages.",
|
|
11011
11064
|
...CONVENTION_FORMAT_HINTS[convention]
|
|
11012
11065
|
];
|
|
11013
11066
|
}
|
|
@@ -11200,6 +11253,15 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11200
11253
|
success(`Committed: ${import_picocolors8.default.bold(finalMessage)}`);
|
|
11201
11254
|
}
|
|
11202
11255
|
});
|
|
11256
|
+
function getFallbackGroupMessage(convention) {
|
|
11257
|
+
if (convention === "conventional") {
|
|
11258
|
+
return "chore: commit remaining changes";
|
|
11259
|
+
}
|
|
11260
|
+
if (convention === "clean-commit") {
|
|
11261
|
+
return "☕ chore: commit remaining changes";
|
|
11262
|
+
}
|
|
11263
|
+
return "commit remaining changes";
|
|
11264
|
+
}
|
|
11203
11265
|
async function runGroupCommit(model, config) {
|
|
11204
11266
|
const [copilotError, changedFiles] = await Promise.all([
|
|
11205
11267
|
checkCopilotAvailable(),
|
|
@@ -11237,15 +11299,25 @@ ${import_picocolors8.default.bold("Changed files:")}`);
|
|
|
11237
11299
|
error("AI could not produce commit groups. Try committing files manually.");
|
|
11238
11300
|
process.exit(1);
|
|
11239
11301
|
}
|
|
11240
|
-
const
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
}
|
|
11246
|
-
|
|
11302
|
+
const normalized = normalizeCommitGroups(changedFiles, groups);
|
|
11303
|
+
if (normalized.unknownFiles.length > 0) {
|
|
11304
|
+
warn(`AI suggested unknown file(s): ${normalized.unknownFiles.join(", ")} — removed from groups.`);
|
|
11305
|
+
}
|
|
11306
|
+
if (normalized.duplicateFiles.length > 0) {
|
|
11307
|
+
warn(`AI assigned duplicate file(s) across groups: ${normalized.duplicateFiles.join(", ")} — keeping the first assignment only.`);
|
|
11308
|
+
}
|
|
11309
|
+
let validGroups = normalized.groups;
|
|
11310
|
+
if (normalized.unassignedFiles.length > 0) {
|
|
11311
|
+
warn(`AI left ${normalized.unassignedFiles.length} file(s) ungrouped: ${normalized.unassignedFiles.join(", ")}. Creating a fallback group.`);
|
|
11312
|
+
const fallbackMessage = await regenerateGroupMessage(normalized.unassignedFiles, diffs, model, config.commitConvention) ?? getFallbackGroupMessage(config.commitConvention);
|
|
11313
|
+
validGroups = [
|
|
11314
|
+
...validGroups,
|
|
11315
|
+
{
|
|
11316
|
+
files: normalized.unassignedFiles,
|
|
11317
|
+
message: fallbackMessage
|
|
11318
|
+
}
|
|
11319
|
+
];
|
|
11247
11320
|
}
|
|
11248
|
-
let validGroups = groups.filter((g3) => g3.files.length > 0);
|
|
11249
11321
|
if (validGroups.length === 0) {
|
|
11250
11322
|
error("No valid groups remain after validation. Try committing files manually.");
|
|
11251
11323
|
process.exit(1);
|
|
@@ -11291,7 +11363,17 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11291
11363
|
if (commitAll) {
|
|
11292
11364
|
for (let i2 = 0;i2 < validGroups.length; i2++) {
|
|
11293
11365
|
const group = validGroups[i2];
|
|
11294
|
-
const
|
|
11366
|
+
const remainingChangedFiles = new Set(await getChangedFiles());
|
|
11367
|
+
const stageableFiles = group.files.filter((file) => remainingChangedFiles.has(file));
|
|
11368
|
+
const skippedFiles = group.files.filter((file) => !remainingChangedFiles.has(file));
|
|
11369
|
+
if (skippedFiles.length > 0) {
|
|
11370
|
+
warn(`Group ${i2 + 1} file(s) no longer have changes: ${skippedFiles.join(", ")}`);
|
|
11371
|
+
}
|
|
11372
|
+
if (stageableFiles.length === 0) {
|
|
11373
|
+
warn(`Skipped group ${i2 + 1}: no files remain to commit.`);
|
|
11374
|
+
continue;
|
|
11375
|
+
}
|
|
11376
|
+
const stageResult = await stageFiles(stageableFiles);
|
|
11295
11377
|
if (stageResult.exitCode !== 0) {
|
|
11296
11378
|
error(`Failed to stage group ${i2 + 1}: ${stageResult.stderr}`);
|
|
11297
11379
|
continue;
|
|
@@ -11300,7 +11382,7 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11300
11382
|
if (commitResult.exitCode !== 0) {
|
|
11301
11383
|
const detail = (commitResult.stderr || commitResult.stdout).trim();
|
|
11302
11384
|
error(`Failed to commit group ${i2 + 1}: ${detail}`);
|
|
11303
|
-
await unstageFiles(
|
|
11385
|
+
await unstageFiles(stageableFiles);
|
|
11304
11386
|
continue;
|
|
11305
11387
|
}
|
|
11306
11388
|
committed++;
|
|
@@ -11360,7 +11442,18 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11360
11442
|
continue;
|
|
11361
11443
|
}
|
|
11362
11444
|
}
|
|
11363
|
-
const
|
|
11445
|
+
const remainingChangedFiles = new Set(await getChangedFiles());
|
|
11446
|
+
const stageableFiles = group.files.filter((file) => remainingChangedFiles.has(file));
|
|
11447
|
+
const skippedFiles = group.files.filter((file) => !remainingChangedFiles.has(file));
|
|
11448
|
+
if (skippedFiles.length > 0) {
|
|
11449
|
+
warn(`Group ${i2 + 1} file(s) no longer have changes: ${skippedFiles.join(", ")}`);
|
|
11450
|
+
}
|
|
11451
|
+
if (stageableFiles.length === 0) {
|
|
11452
|
+
warn(`Skipped group ${i2 + 1}: no files remain to commit.`);
|
|
11453
|
+
actionDone = true;
|
|
11454
|
+
continue;
|
|
11455
|
+
}
|
|
11456
|
+
const stageResult = await stageFiles(stageableFiles);
|
|
11364
11457
|
if (stageResult.exitCode !== 0) {
|
|
11365
11458
|
error(`Failed to stage group ${i2 + 1}: ${stageResult.stderr}`);
|
|
11366
11459
|
actionDone = true;
|
|
@@ -11370,7 +11463,7 @@ ${import_picocolors8.default.bold(`AI suggested ${validGroups.length} commit gro
|
|
|
11370
11463
|
if (commitResult.exitCode !== 0) {
|
|
11371
11464
|
const detail = (commitResult.stderr || commitResult.stdout).trim();
|
|
11372
11465
|
error(`Failed to commit group ${i2 + 1}: ${detail}`);
|
|
11373
|
-
await unstageFiles(
|
|
11466
|
+
await unstageFiles(stageableFiles);
|
|
11374
11467
|
actionDone = true;
|
|
11375
11468
|
continue;
|
|
11376
11469
|
}
|
|
@@ -11395,7 +11488,7 @@ var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
|
11395
11488
|
// package.json
|
|
11396
11489
|
var package_default = {
|
|
11397
11490
|
name: "contribute-now",
|
|
11398
|
-
version: "0.6.2-dev.
|
|
11491
|
+
version: "0.6.2-dev.3d69403",
|
|
11399
11492
|
description: "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
|
|
11400
11493
|
type: "module",
|
|
11401
11494
|
bin: {
|
|
@@ -11806,13 +11899,13 @@ esac
|
|
|
11806
11899
|
|
|
11807
11900
|
# Detect available package runner
|
|
11808
11901
|
if command -v contrib >/dev/null 2>&1; then
|
|
11809
|
-
contrib validate "$
|
|
11902
|
+
contrib validate --file "$commit_msg_file"
|
|
11810
11903
|
elif command -v bunx >/dev/null 2>&1; then
|
|
11811
|
-
bunx contrib validate "$
|
|
11904
|
+
bunx contrib validate --file "$commit_msg_file"
|
|
11812
11905
|
elif command -v pnpx >/dev/null 2>&1; then
|
|
11813
|
-
pnpx contrib validate "$
|
|
11906
|
+
pnpx contrib validate --file "$commit_msg_file"
|
|
11814
11907
|
elif command -v npx >/dev/null 2>&1; then
|
|
11815
|
-
npx contrib validate "$
|
|
11908
|
+
npx contrib validate --file "$commit_msg_file"
|
|
11816
11909
|
else
|
|
11817
11910
|
echo "Warning: No package runner found. Skipping commit message validation."
|
|
11818
11911
|
exit 0
|
|
@@ -12965,16 +13058,27 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
12965
13058
|
if (!message) {
|
|
12966
13059
|
const copilotError = await checkCopilotAvailable();
|
|
12967
13060
|
if (!copilotError) {
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
|
|
12974
|
-
|
|
13061
|
+
while (!message) {
|
|
13062
|
+
const spinner = createSpinner("Generating AI commit message for squash merge...");
|
|
13063
|
+
const [stagedDiff, stagedFiles] = await Promise.all([getStagedDiff(), getStagedFiles()]);
|
|
13064
|
+
const aiMsg = await generateCommitMessage(stagedDiff, stagedFiles, options?.model, options?.convention ?? "clean-commit", "squash-merge");
|
|
13065
|
+
if (aiMsg) {
|
|
13066
|
+
message = aiMsg;
|
|
13067
|
+
spinner.success("AI commit message generated.");
|
|
13068
|
+
console.log(`
|
|
12975
13069
|
${import_picocolors16.default.dim("AI suggestion:")} ${import_picocolors16.default.bold(import_picocolors16.default.cyan(message))}`);
|
|
12976
|
-
|
|
13070
|
+
break;
|
|
13071
|
+
}
|
|
12977
13072
|
spinner.fail("AI did not return a commit message.");
|
|
13073
|
+
const retryAction = await selectPrompt("AI could not generate a commit message. What would you like to do?", ["Try again with AI", "Write manually", "Cancel"]);
|
|
13074
|
+
if (retryAction === "Try again with AI") {
|
|
13075
|
+
continue;
|
|
13076
|
+
}
|
|
13077
|
+
if (retryAction === "Cancel") {
|
|
13078
|
+
warn("Squash merge commit cancelled.");
|
|
13079
|
+
process.exit(0);
|
|
13080
|
+
}
|
|
13081
|
+
break;
|
|
12978
13082
|
}
|
|
12979
13083
|
} else {
|
|
12980
13084
|
warn(`AI unavailable: ${copilotError}`);
|
|
@@ -13004,7 +13108,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
|
|
|
13004
13108
|
${import_picocolors16.default.dim("AI suggestion:")} ${import_picocolors16.default.bold(import_picocolors16.default.cyan(regen))}`);
|
|
13005
13109
|
} else {
|
|
13006
13110
|
spinner.fail("Regeneration failed.");
|
|
13007
|
-
|
|
13111
|
+
continue;
|
|
13008
13112
|
}
|
|
13009
13113
|
} else {
|
|
13010
13114
|
finalMsg = await inputPrompt("Enter commit message");
|
|
@@ -14040,6 +14144,7 @@ ${import_picocolors19.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance
|
|
|
14040
14144
|
|
|
14041
14145
|
// src/commands/validate.ts
|
|
14042
14146
|
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
14147
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
14043
14148
|
var validate_default = defineCommand({
|
|
14044
14149
|
meta: {
|
|
14045
14150
|
name: "validate",
|
|
@@ -14049,7 +14154,11 @@ var validate_default = defineCommand({
|
|
|
14049
14154
|
message: {
|
|
14050
14155
|
type: "positional",
|
|
14051
14156
|
description: "The commit message to validate",
|
|
14052
|
-
required:
|
|
14157
|
+
required: false
|
|
14158
|
+
},
|
|
14159
|
+
file: {
|
|
14160
|
+
type: "string",
|
|
14161
|
+
description: "Path to a commit message file; only the first line is validated"
|
|
14053
14162
|
}
|
|
14054
14163
|
},
|
|
14055
14164
|
async run({ args }) {
|
|
@@ -14063,7 +14172,11 @@ var validate_default = defineCommand({
|
|
|
14063
14172
|
info('Commit convention is set to "none". All messages are accepted.');
|
|
14064
14173
|
process.exit(0);
|
|
14065
14174
|
}
|
|
14066
|
-
const message = args.message;
|
|
14175
|
+
const message = args.file ? readFileSync5(args.file, "utf-8").split(/\r?\n/, 1)[0] ?? "" : args.message;
|
|
14176
|
+
if (!message) {
|
|
14177
|
+
error("No commit message provided. Pass a message or use --file <path>.");
|
|
14178
|
+
process.exit(1);
|
|
14179
|
+
}
|
|
14067
14180
|
if (validateCommitMessage(message, convention)) {
|
|
14068
14181
|
success(`Valid ${CONVENTION_LABELS[convention]} message.`);
|
|
14069
14182
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "contribute-now",
|
|
3
|
-
"version": "0.6.2-dev.
|
|
3
|
+
"version": "0.6.2-dev.3d69403",
|
|
4
4
|
"description": "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|