@releasekit/notes 0.2.0-next.1 → 0.2.0-next.11
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/{chunk-W7DVGQ7D.js → chunk-3VS3PBTN.js} +178 -56
- package/dist/cli.cjs +239 -108
- package/dist/cli.js +11 -2
- package/dist/index.cjs +212 -90
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
runPipeline,
|
|
12
12
|
saveAuth,
|
|
13
13
|
writeMonorepoChangelogs
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-3VS3PBTN.js";
|
|
15
15
|
|
|
16
16
|
// src/cli.ts
|
|
17
17
|
import * as fs from "fs";
|
|
@@ -20,7 +20,7 @@ import { error, info, setLogLevel, setQuietMode, success } from "@releasekit/cor
|
|
|
20
20
|
import { Command } from "commander";
|
|
21
21
|
var program = new Command();
|
|
22
22
|
program.name("releasekit-notes").description("Generate changelogs with LLM-powered enhancement and flexible templating").version("0.1.0");
|
|
23
|
-
program.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("-o, --output <spec>", "Output spec (format:file)", collectOutputs, []).option("-t, --template <path>", "Template file or directory").option("-e, --engine <engine>", "Template engine (handlebars|liquid|ejs)").option("--monorepo <mode>", "Monorepo mode (root|packages|both)").option("--llm-provider <provider>", "LLM provider").option("--llm-model <model>", "LLM model").option("--llm-base-url <url>", "LLM base URL (for openai-compatible provider)").option("--llm-tasks <tasks>", "Comma-separated LLM tasks").option("--no-llm", "Disable LLM processing").option("--config <path>", "Config file path").option("--dry-run", "Preview without writing").option("--regenerate", "Regenerate entire changelog").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
|
|
23
|
+
program.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("-o, --output <spec>", "Output spec (format:file)", collectOutputs, []).option("-t, --template <path>", "Template file or directory").option("-e, --engine <engine>", "Template engine (handlebars|liquid|ejs)").option("--monorepo <mode>", "Monorepo mode (root|packages|both)").option("--llm-provider <provider>", "LLM provider").option("--llm-model <model>", "LLM model").option("--llm-base-url <url>", "LLM base URL (for openai-compatible provider)").option("--llm-tasks <tasks>", "Comma-separated LLM tasks").option("--no-llm", "Disable LLM processing").option("--target <package>", "Filter to a specific package name").option("--config <path>", "Config file path").option("--dry-run", "Preview without writing").option("--regenerate", "Regenerate entire changelog").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
|
|
24
24
|
setVerbosity(options.verbose);
|
|
25
25
|
if (options.quiet) setQuietMode(true);
|
|
26
26
|
try {
|
|
@@ -73,6 +73,15 @@ program.command("generate", { isDefault: true }).description("Generate changelog
|
|
|
73
73
|
inputJson = await readStdin();
|
|
74
74
|
}
|
|
75
75
|
const input = parsePackageVersioner(inputJson);
|
|
76
|
+
if (options.target) {
|
|
77
|
+
const before = input.packages.length;
|
|
78
|
+
input.packages = input.packages.filter((p) => p.packageName === options.target);
|
|
79
|
+
if (input.packages.length === 0) {
|
|
80
|
+
info(`No changelog found for package "${options.target}" (had ${before} package(s))`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
info(`Filtered to package: ${options.target}`);
|
|
84
|
+
}
|
|
76
85
|
if (options.monorepo || config.monorepo) {
|
|
77
86
|
const monorepoMode = options.monorepo ?? config.monorepo?.mode ?? "both";
|
|
78
87
|
const detected = detectMonorepo(process.cwd());
|
package/dist/index.cjs
CHANGED
|
@@ -75,7 +75,7 @@ function getDefaultConfig() {
|
|
|
75
75
|
// src/core/pipeline.ts
|
|
76
76
|
var fs8 = __toESM(require("fs"), 1);
|
|
77
77
|
var path6 = __toESM(require("path"), 1);
|
|
78
|
-
var
|
|
78
|
+
var import_core8 = require("@releasekit/core");
|
|
79
79
|
|
|
80
80
|
// src/input/package-versioner.ts
|
|
81
81
|
var fs = __toESM(require("fs"), 1);
|
|
@@ -416,15 +416,26 @@ Entries:
|
|
|
416
416
|
Output only valid JSON, nothing else:`;
|
|
417
417
|
function buildCustomCategorizePrompt(categories) {
|
|
418
418
|
const categoryList = categories.map((c) => `- "${c.name}": ${c.description}`).join("\n");
|
|
419
|
+
const developerCategory = categories.find((c) => c.name === "Developer");
|
|
420
|
+
let scopeInstructions = "";
|
|
421
|
+
if (developerCategory) {
|
|
422
|
+
const scopeMatch = developerCategory.description.match(/from:\s*([^.]+)/);
|
|
423
|
+
if (scopeMatch?.[1]) {
|
|
424
|
+
const scopes = scopeMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
425
|
+
if (scopes.length > 0) {
|
|
426
|
+
scopeInstructions = `
|
|
427
|
+
|
|
428
|
+
For the "Developer" category, you MUST assign a scope from this exact list: ${scopes.join(", ")}.
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
419
433
|
return `You are categorizing changelog entries for a software release.
|
|
420
434
|
|
|
421
|
-
Given the following entries, group them into the specified categories. Only use the categories listed below
|
|
435
|
+
Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
|
|
422
436
|
|
|
423
437
|
Categories:
|
|
424
|
-
${categoryList}
|
|
425
|
-
|
|
426
|
-
For entries in categories that involve internal/developer changes, set a "scope" field on those entries with a short subcategory label (e.g., "CI", "Dependencies", "Testing", "Code Quality", "Build System").
|
|
427
|
-
|
|
438
|
+
${categoryList}${scopeInstructions}
|
|
428
439
|
Output a JSON object with two fields:
|
|
429
440
|
- "categories": an object where keys are category names and values are arrays of entry indices (0-based)
|
|
430
441
|
- "scopes": an object where keys are entry indices (as strings) and values are scope labels
|
|
@@ -524,6 +535,113 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
|
|
|
524
535
|
return results;
|
|
525
536
|
}
|
|
526
537
|
|
|
538
|
+
// src/llm/tasks/enhance-and-categorize.ts
|
|
539
|
+
var import_core4 = require("@releasekit/core");
|
|
540
|
+
|
|
541
|
+
// src/utils/retry.ts
|
|
542
|
+
function sleep(ms) {
|
|
543
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
544
|
+
}
|
|
545
|
+
async function withRetry(fn, options = {}) {
|
|
546
|
+
const maxAttempts = options.maxAttempts ?? 3;
|
|
547
|
+
const initialDelay = options.initialDelay ?? 1e3;
|
|
548
|
+
const maxDelay = options.maxDelay ?? 3e4;
|
|
549
|
+
const backoffFactor = options.backoffFactor ?? 2;
|
|
550
|
+
let lastError;
|
|
551
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
552
|
+
try {
|
|
553
|
+
return await fn();
|
|
554
|
+
} catch (error) {
|
|
555
|
+
lastError = error;
|
|
556
|
+
if (attempt < maxAttempts - 1) {
|
|
557
|
+
const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
|
|
558
|
+
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
559
|
+
await sleep(Math.max(0, base + jitter));
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
throw lastError;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/llm/tasks/enhance-and-categorize.ts
|
|
567
|
+
function buildPrompt(entries, categories, style) {
|
|
568
|
+
const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
|
|
569
|
+
const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
|
|
570
|
+
const categorySection = categories ? `Categories (use ONLY these):
|
|
571
|
+
${categories.map((c) => `- "${c.name}": ${c.description}`).join("\n")}` : `Categories: Group into meaningful categories (e.g., "New", "Fixed", "Changed", "Removed").`;
|
|
572
|
+
return `You are generating release notes for a software project. Given the following changelog entries, do two things:
|
|
573
|
+
|
|
574
|
+
1. **Rewrite** each entry as a clear, user-friendly description
|
|
575
|
+
2. **Categorize** each entry into the appropriate category
|
|
576
|
+
|
|
577
|
+
Style guidelines:
|
|
578
|
+
- ${styleText}
|
|
579
|
+
- Be concise (1 short sentence per entry)
|
|
580
|
+
- Focus on what changed, not implementation details
|
|
581
|
+
|
|
582
|
+
${categorySection}
|
|
583
|
+
|
|
584
|
+
${categories ? 'For entries in categories involving internal/developer changes, set a "scope" field with a short subcategory label (e.g., "CI", "Dependencies", "Testing").' : ""}
|
|
585
|
+
|
|
586
|
+
Entries:
|
|
587
|
+
${entriesText}
|
|
588
|
+
|
|
589
|
+
Output a JSON object with:
|
|
590
|
+
- "entries": array of objects, one per input entry (same order), each with: { "description": "rewritten text", "category": "CategoryName", "scope": "optional subcategory label or null" }
|
|
591
|
+
|
|
592
|
+
Output only valid JSON, nothing else:`;
|
|
593
|
+
}
|
|
594
|
+
async function enhanceAndCategorize(provider, entries, context) {
|
|
595
|
+
if (entries.length === 0) {
|
|
596
|
+
return { enhancedEntries: [], categories: [] };
|
|
597
|
+
}
|
|
598
|
+
const retryOpts = LLM_DEFAULTS.retry;
|
|
599
|
+
try {
|
|
600
|
+
return await withRetry(async () => {
|
|
601
|
+
const prompt = buildPrompt(entries, context.categories, context.style);
|
|
602
|
+
const response = await provider.complete(prompt);
|
|
603
|
+
const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
604
|
+
const parsed = JSON.parse(cleaned);
|
|
605
|
+
if (!Array.isArray(parsed.entries)) {
|
|
606
|
+
throw new Error('Response missing "entries" array');
|
|
607
|
+
}
|
|
608
|
+
const enhancedEntries = entries.map((original, i) => {
|
|
609
|
+
const result = parsed.entries[i];
|
|
610
|
+
if (!result) return original;
|
|
611
|
+
return {
|
|
612
|
+
...original,
|
|
613
|
+
description: result.description || original.description,
|
|
614
|
+
scope: result.scope || original.scope
|
|
615
|
+
};
|
|
616
|
+
});
|
|
617
|
+
const categoryMap = /* @__PURE__ */ new Map();
|
|
618
|
+
for (let i = 0; i < parsed.entries.length; i++) {
|
|
619
|
+
const result = parsed.entries[i];
|
|
620
|
+
const category = result?.category || "General";
|
|
621
|
+
const entry = enhancedEntries[i];
|
|
622
|
+
if (!entry) continue;
|
|
623
|
+
if (!categoryMap.has(category)) {
|
|
624
|
+
categoryMap.set(category, []);
|
|
625
|
+
}
|
|
626
|
+
categoryMap.get(category).push(entry);
|
|
627
|
+
}
|
|
628
|
+
const categories = [];
|
|
629
|
+
for (const [category, catEntries] of categoryMap) {
|
|
630
|
+
categories.push({ category, entries: catEntries });
|
|
631
|
+
}
|
|
632
|
+
return { enhancedEntries, categories };
|
|
633
|
+
}, retryOpts);
|
|
634
|
+
} catch (error) {
|
|
635
|
+
(0, import_core4.warn)(
|
|
636
|
+
`Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error instanceof Error ? error.message : String(error)}`
|
|
637
|
+
);
|
|
638
|
+
return {
|
|
639
|
+
enhancedEntries: entries,
|
|
640
|
+
categories: [{ category: "General", entries }]
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
527
645
|
// src/llm/tasks/release-notes.ts
|
|
528
646
|
var RELEASE_NOTES_PROMPT = `You are writing release notes for a software project.
|
|
529
647
|
|
|
@@ -624,12 +742,12 @@ function createProvider(config) {
|
|
|
624
742
|
|
|
625
743
|
// src/output/github-release.ts
|
|
626
744
|
var import_rest = require("@octokit/rest");
|
|
627
|
-
var
|
|
745
|
+
var import_core6 = require("@releasekit/core");
|
|
628
746
|
|
|
629
747
|
// src/output/markdown.ts
|
|
630
748
|
var fs2 = __toESM(require("fs"), 1);
|
|
631
749
|
var path = __toESM(require("path"), 1);
|
|
632
|
-
var
|
|
750
|
+
var import_core5 = require("@releasekit/core");
|
|
633
751
|
var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
|
|
634
752
|
var TYPE_LABELS = {
|
|
635
753
|
added: "Added",
|
|
@@ -728,15 +846,19 @@ ${body}`;
|
|
|
728
846
|
function writeMarkdown(outputPath, contexts, config, dryRun) {
|
|
729
847
|
const content = renderMarkdown(contexts);
|
|
730
848
|
if (dryRun) {
|
|
731
|
-
(0,
|
|
849
|
+
(0, import_core5.info)("--- Changelog Preview ---");
|
|
732
850
|
console.log(content);
|
|
733
|
-
(0,
|
|
851
|
+
(0, import_core5.info)("--- End Preview ---");
|
|
734
852
|
return;
|
|
735
853
|
}
|
|
736
854
|
const dir = path.dirname(outputPath);
|
|
737
855
|
if (!fs2.existsSync(dir)) {
|
|
738
856
|
fs2.mkdirSync(dir, { recursive: true });
|
|
739
857
|
}
|
|
858
|
+
if (outputPath === "-") {
|
|
859
|
+
process.stdout.write(content);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
740
862
|
if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
|
|
741
863
|
const firstContext = contexts[0];
|
|
742
864
|
if (firstContext) {
|
|
@@ -746,7 +868,7 @@ function writeMarkdown(outputPath, contexts, config, dryRun) {
|
|
|
746
868
|
} else {
|
|
747
869
|
fs2.writeFileSync(outputPath, content, "utf-8");
|
|
748
870
|
}
|
|
749
|
-
(0,
|
|
871
|
+
(0, import_core5.success)(`Changelog written to ${outputPath}`);
|
|
750
872
|
}
|
|
751
873
|
|
|
752
874
|
// src/output/github-release.ts
|
|
@@ -771,7 +893,7 @@ var GitHubClient = class {
|
|
|
771
893
|
} else {
|
|
772
894
|
body = renderMarkdown([context]);
|
|
773
895
|
}
|
|
774
|
-
(0,
|
|
896
|
+
(0, import_core6.info)(`Creating GitHub release for ${tagName}`);
|
|
775
897
|
try {
|
|
776
898
|
const response = await this.octokit.repos.createRelease({
|
|
777
899
|
owner: this.owner,
|
|
@@ -783,7 +905,7 @@ var GitHubClient = class {
|
|
|
783
905
|
prerelease: options.prerelease ?? false,
|
|
784
906
|
generate_release_notes: options.generateNotes ?? false
|
|
785
907
|
});
|
|
786
|
-
(0,
|
|
908
|
+
(0, import_core6.success)(`Release created: ${response.data.html_url}`);
|
|
787
909
|
return {
|
|
788
910
|
id: response.data.id,
|
|
789
911
|
htmlUrl: response.data.html_url,
|
|
@@ -801,7 +923,7 @@ var GitHubClient = class {
|
|
|
801
923
|
} else {
|
|
802
924
|
body = renderMarkdown([context]);
|
|
803
925
|
}
|
|
804
|
-
(0,
|
|
926
|
+
(0, import_core6.info)(`Updating GitHub release ${releaseId}`);
|
|
805
927
|
try {
|
|
806
928
|
const response = await this.octokit.repos.updateRelease({
|
|
807
929
|
owner: this.owner,
|
|
@@ -813,7 +935,7 @@ var GitHubClient = class {
|
|
|
813
935
|
draft: options.draft ?? false,
|
|
814
936
|
prerelease: options.prerelease ?? false
|
|
815
937
|
});
|
|
816
|
-
(0,
|
|
938
|
+
(0, import_core6.success)(`Release updated: ${response.data.html_url}`);
|
|
817
939
|
return {
|
|
818
940
|
id: response.data.id,
|
|
819
941
|
htmlUrl: response.data.html_url,
|
|
@@ -865,7 +987,7 @@ async function createGitHubRelease(context, options) {
|
|
|
865
987
|
// src/output/json.ts
|
|
866
988
|
var fs3 = __toESM(require("fs"), 1);
|
|
867
989
|
var path2 = __toESM(require("path"), 1);
|
|
868
|
-
var
|
|
990
|
+
var import_core7 = require("@releasekit/core");
|
|
869
991
|
function renderJson(contexts) {
|
|
870
992
|
return JSON.stringify(
|
|
871
993
|
{
|
|
@@ -885,9 +1007,9 @@ function renderJson(contexts) {
|
|
|
885
1007
|
function writeJson(outputPath, contexts, dryRun) {
|
|
886
1008
|
const content = renderJson(contexts);
|
|
887
1009
|
if (dryRun) {
|
|
888
|
-
(0,
|
|
1010
|
+
(0, import_core7.info)("--- JSON Output Preview ---");
|
|
889
1011
|
console.log(content);
|
|
890
|
-
(0,
|
|
1012
|
+
(0, import_core7.info)("--- End Preview ---");
|
|
891
1013
|
return;
|
|
892
1014
|
}
|
|
893
1015
|
const dir = path2.dirname(outputPath);
|
|
@@ -895,7 +1017,7 @@ function writeJson(outputPath, contexts, dryRun) {
|
|
|
895
1017
|
fs3.mkdirSync(dir, { recursive: true });
|
|
896
1018
|
}
|
|
897
1019
|
fs3.writeFileSync(outputPath, content, "utf-8");
|
|
898
|
-
(0,
|
|
1020
|
+
(0, import_core7.success)(`JSON output written to ${outputPath}`);
|
|
899
1021
|
}
|
|
900
1022
|
|
|
901
1023
|
// src/templates/ejs.ts
|
|
@@ -1152,44 +1274,29 @@ function renderTemplate(templatePath, context, engine) {
|
|
|
1152
1274
|
return renderComposable(templatePath, context, engine);
|
|
1153
1275
|
}
|
|
1154
1276
|
|
|
1155
|
-
// src/utils/retry.ts
|
|
1156
|
-
function sleep(ms) {
|
|
1157
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1158
|
-
}
|
|
1159
|
-
async function withRetry(fn, options = {}) {
|
|
1160
|
-
const maxAttempts = options.maxAttempts ?? 3;
|
|
1161
|
-
const initialDelay = options.initialDelay ?? 1e3;
|
|
1162
|
-
const maxDelay = options.maxDelay ?? 3e4;
|
|
1163
|
-
const backoffFactor = options.backoffFactor ?? 2;
|
|
1164
|
-
let lastError;
|
|
1165
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1166
|
-
try {
|
|
1167
|
-
return await fn();
|
|
1168
|
-
} catch (error) {
|
|
1169
|
-
lastError = error;
|
|
1170
|
-
if (attempt < maxAttempts - 1) {
|
|
1171
|
-
const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
|
|
1172
|
-
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
1173
|
-
await sleep(Math.max(0, base + jitter));
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
throw lastError;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
1277
|
// src/core/pipeline.ts
|
|
1181
1278
|
var import_meta = {};
|
|
1182
|
-
function generateCompareUrl(repoUrl, from, to) {
|
|
1279
|
+
function generateCompareUrl(repoUrl, from, to, packageName) {
|
|
1280
|
+
const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
|
|
1281
|
+
let fromVersion;
|
|
1282
|
+
let toVersion;
|
|
1283
|
+
if (isPackageSpecific) {
|
|
1284
|
+
fromVersion = from;
|
|
1285
|
+
toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
|
|
1286
|
+
} else {
|
|
1287
|
+
fromVersion = from.replace(/^v/, "");
|
|
1288
|
+
toVersion = to.replace(/^v/, "");
|
|
1289
|
+
}
|
|
1183
1290
|
if (/gitlab\.com/i.test(repoUrl)) {
|
|
1184
|
-
return `${repoUrl}/-/compare/${
|
|
1291
|
+
return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
|
|
1185
1292
|
}
|
|
1186
1293
|
if (/bitbucket\.org/i.test(repoUrl)) {
|
|
1187
|
-
return `${repoUrl}/branches/compare/${
|
|
1294
|
+
return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
|
|
1188
1295
|
}
|
|
1189
|
-
return `${repoUrl}/compare/${
|
|
1296
|
+
return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
|
|
1190
1297
|
}
|
|
1191
1298
|
function createTemplateContext(pkg) {
|
|
1192
|
-
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
|
|
1299
|
+
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
|
|
1193
1300
|
return {
|
|
1194
1301
|
packageName: pkg.packageName,
|
|
1195
1302
|
version: pkg.version,
|
|
@@ -1233,9 +1340,9 @@ async function processWithLLM(context, config) {
|
|
|
1233
1340
|
entries: context.entries
|
|
1234
1341
|
};
|
|
1235
1342
|
try {
|
|
1236
|
-
(0,
|
|
1343
|
+
(0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
|
|
1237
1344
|
if (config.llm.baseURL) {
|
|
1238
|
-
(0,
|
|
1345
|
+
(0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
|
|
1239
1346
|
}
|
|
1240
1347
|
const rawProvider = createProvider(config.llm);
|
|
1241
1348
|
const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
|
|
@@ -1244,38 +1351,49 @@ async function processWithLLM(context, config) {
|
|
|
1244
1351
|
complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
|
|
1245
1352
|
};
|
|
1246
1353
|
const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
|
|
1247
|
-
(0,
|
|
1248
|
-
if (tasks.enhance) {
|
|
1249
|
-
(0,
|
|
1250
|
-
|
|
1251
|
-
|
|
1354
|
+
(0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
|
|
1355
|
+
if (tasks.enhance && tasks.categorize) {
|
|
1356
|
+
(0, import_core8.info)("Enhancing and categorizing entries with LLM...");
|
|
1357
|
+
const result = await enhanceAndCategorize(provider, context.entries, llmContext);
|
|
1358
|
+
enhanced.entries = result.enhancedEntries;
|
|
1359
|
+
enhanced.categories = {};
|
|
1360
|
+
for (const cat of result.categories) {
|
|
1361
|
+
enhanced.categories[cat.category] = cat.entries;
|
|
1362
|
+
}
|
|
1363
|
+
(0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
|
|
1364
|
+
} else {
|
|
1365
|
+
if (tasks.enhance) {
|
|
1366
|
+
(0, import_core8.info)("Enhancing entries with LLM...");
|
|
1367
|
+
enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
|
|
1368
|
+
(0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
|
|
1369
|
+
}
|
|
1370
|
+
if (tasks.categorize) {
|
|
1371
|
+
(0, import_core8.info)("Categorizing entries with LLM...");
|
|
1372
|
+
const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
|
|
1373
|
+
enhanced.categories = {};
|
|
1374
|
+
for (const cat of categorized) {
|
|
1375
|
+
enhanced.categories[cat.category] = cat.entries;
|
|
1376
|
+
}
|
|
1377
|
+
(0, import_core8.info)(`Created ${categorized.length} categories`);
|
|
1378
|
+
}
|
|
1252
1379
|
}
|
|
1253
1380
|
if (tasks.summarize) {
|
|
1254
|
-
(0,
|
|
1381
|
+
(0, import_core8.info)("Summarizing entries with LLM...");
|
|
1255
1382
|
enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
|
|
1256
1383
|
if (enhanced.summary) {
|
|
1257
|
-
(0,
|
|
1258
|
-
(0,
|
|
1384
|
+
(0, import_core8.info)("Summary generated successfully");
|
|
1385
|
+
(0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
|
|
1259
1386
|
} else {
|
|
1260
|
-
(0,
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
if (tasks.categorize) {
|
|
1264
|
-
(0, import_core7.info)("Categorizing entries with LLM...");
|
|
1265
|
-
const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
|
|
1266
|
-
enhanced.categories = {};
|
|
1267
|
-
for (const cat of categorized) {
|
|
1268
|
-
enhanced.categories[cat.category] = cat.entries;
|
|
1387
|
+
(0, import_core8.warn)("Summary generation returned empty result");
|
|
1269
1388
|
}
|
|
1270
|
-
(0, import_core7.info)(`Created ${categorized.length} categories`);
|
|
1271
1389
|
}
|
|
1272
1390
|
if (tasks.releaseNotes) {
|
|
1273
|
-
(0,
|
|
1391
|
+
(0, import_core8.info)("Generating release notes with LLM...");
|
|
1274
1392
|
enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
|
|
1275
1393
|
if (enhanced.releaseNotes) {
|
|
1276
|
-
(0,
|
|
1394
|
+
(0, import_core8.info)("Release notes generated successfully");
|
|
1277
1395
|
} else {
|
|
1278
|
-
(0,
|
|
1396
|
+
(0, import_core8.warn)("Release notes generation returned empty result");
|
|
1279
1397
|
}
|
|
1280
1398
|
}
|
|
1281
1399
|
return {
|
|
@@ -1284,8 +1402,8 @@ async function processWithLLM(context, config) {
|
|
|
1284
1402
|
enhanced
|
|
1285
1403
|
};
|
|
1286
1404
|
} catch (error) {
|
|
1287
|
-
(0,
|
|
1288
|
-
(0,
|
|
1405
|
+
(0, import_core8.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1406
|
+
(0, import_core8.warn)("Falling back to raw entries");
|
|
1289
1407
|
return context;
|
|
1290
1408
|
}
|
|
1291
1409
|
}
|
|
@@ -1313,9 +1431,13 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1313
1431
|
);
|
|
1314
1432
|
const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
|
|
1315
1433
|
if (dryRun) {
|
|
1316
|
-
(0,
|
|
1434
|
+
(0, import_core8.info)("--- Changelog Preview ---");
|
|
1317
1435
|
console.log(result.content);
|
|
1318
|
-
(0,
|
|
1436
|
+
(0, import_core8.info)("--- End Preview ---");
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
if (outputPath === "-") {
|
|
1440
|
+
process.stdout.write(result.content);
|
|
1319
1441
|
return;
|
|
1320
1442
|
}
|
|
1321
1443
|
const dir = path6.dirname(outputPath);
|
|
@@ -1323,17 +1445,17 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1323
1445
|
fs8.mkdirSync(dir, { recursive: true });
|
|
1324
1446
|
}
|
|
1325
1447
|
fs8.writeFileSync(outputPath, result.content, "utf-8");
|
|
1326
|
-
(0,
|
|
1448
|
+
(0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
|
|
1327
1449
|
}
|
|
1328
1450
|
async function runPipeline(input, config, dryRun) {
|
|
1329
|
-
(0,
|
|
1451
|
+
(0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
|
|
1330
1452
|
let contexts = input.packages.map(createTemplateContext);
|
|
1331
1453
|
if (config.llm && !process.env.CHANGELOG_NO_LLM) {
|
|
1332
|
-
(0,
|
|
1454
|
+
(0, import_core8.info)("Processing with LLM enhancement");
|
|
1333
1455
|
contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
|
|
1334
1456
|
}
|
|
1335
1457
|
for (const output of config.output) {
|
|
1336
|
-
(0,
|
|
1458
|
+
(0, import_core8.info)(`Generating ${output.format} output`);
|
|
1337
1459
|
switch (output.format) {
|
|
1338
1460
|
case "markdown": {
|
|
1339
1461
|
const file = output.file ?? "CHANGELOG.md";
|
|
@@ -1351,22 +1473,22 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1351
1473
|
}
|
|
1352
1474
|
case "github-release": {
|
|
1353
1475
|
if (dryRun) {
|
|
1354
|
-
(0,
|
|
1476
|
+
(0, import_core8.info)("[DRY RUN] Would create GitHub release");
|
|
1355
1477
|
break;
|
|
1356
1478
|
}
|
|
1357
1479
|
const firstContext = contexts[0];
|
|
1358
1480
|
if (!firstContext) {
|
|
1359
|
-
(0,
|
|
1481
|
+
(0, import_core8.warn)("No context available for GitHub release");
|
|
1360
1482
|
break;
|
|
1361
1483
|
}
|
|
1362
1484
|
const repoUrl = firstContext.repoUrl;
|
|
1363
1485
|
if (!repoUrl) {
|
|
1364
|
-
(0,
|
|
1486
|
+
(0, import_core8.warn)("No repo URL available, cannot create GitHub release");
|
|
1365
1487
|
break;
|
|
1366
1488
|
}
|
|
1367
1489
|
const parsed = parseRepoUrl(repoUrl);
|
|
1368
1490
|
if (!parsed) {
|
|
1369
|
-
(0,
|
|
1491
|
+
(0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
|
|
1370
1492
|
break;
|
|
1371
1493
|
}
|
|
1372
1494
|
await createGitHubRelease(firstContext, {
|
|
@@ -1388,7 +1510,7 @@ async function processInput(inputJson, config, dryRun) {
|
|
|
1388
1510
|
// src/monorepo/aggregator.ts
|
|
1389
1511
|
var fs9 = __toESM(require("fs"), 1);
|
|
1390
1512
|
var path7 = __toESM(require("path"), 1);
|
|
1391
|
-
var
|
|
1513
|
+
var import_core9 = require("@releasekit/core");
|
|
1392
1514
|
|
|
1393
1515
|
// src/monorepo/splitter.ts
|
|
1394
1516
|
function splitByPackage(contexts) {
|
|
@@ -1402,7 +1524,7 @@ function splitByPackage(contexts) {
|
|
|
1402
1524
|
// src/monorepo/aggregator.ts
|
|
1403
1525
|
function writeFile(outputPath, content, dryRun) {
|
|
1404
1526
|
if (dryRun) {
|
|
1405
|
-
(0,
|
|
1527
|
+
(0, import_core9.info)(`[DRY RUN] Would write to ${outputPath}`);
|
|
1406
1528
|
console.log(content);
|
|
1407
1529
|
return;
|
|
1408
1530
|
}
|
|
@@ -1411,7 +1533,7 @@ function writeFile(outputPath, content, dryRun) {
|
|
|
1411
1533
|
fs9.mkdirSync(dir, { recursive: true });
|
|
1412
1534
|
}
|
|
1413
1535
|
fs9.writeFileSync(outputPath, content, "utf-8");
|
|
1414
|
-
(0,
|
|
1536
|
+
(0, import_core9.success)(`Changelog written to ${outputPath}`);
|
|
1415
1537
|
}
|
|
1416
1538
|
function aggregateToRoot(contexts) {
|
|
1417
1539
|
const aggregated = {
|
|
@@ -1436,7 +1558,7 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
|
|
|
1436
1558
|
if (options.mode === "root" || options.mode === "both") {
|
|
1437
1559
|
const aggregated = aggregateToRoot(contexts);
|
|
1438
1560
|
const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
|
|
1439
|
-
(0,
|
|
1561
|
+
(0, import_core9.info)(`Writing root changelog to ${rootPath}`);
|
|
1440
1562
|
const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
|
|
1441
1563
|
writeFile(rootPath, rootContent, dryRun);
|
|
1442
1564
|
}
|
|
@@ -1448,11 +1570,11 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
|
|
|
1448
1570
|
const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
|
|
1449
1571
|
if (packageDir) {
|
|
1450
1572
|
const changelogPath = path7.join(packageDir, "CHANGELOG.md");
|
|
1451
|
-
(0,
|
|
1573
|
+
(0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
|
|
1452
1574
|
const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
|
|
1453
1575
|
writeFile(changelogPath, pkgContent, dryRun);
|
|
1454
1576
|
} else {
|
|
1455
|
-
(0,
|
|
1577
|
+
(0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
|
|
1456
1578
|
}
|
|
1457
1579
|
}
|
|
1458
1580
|
}
|
package/dist/index.js
CHANGED