@releasekit/notes 0.2.0-next.1 → 0.2.0-next.10
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-ACXCEHQT.js} +173 -53
- package/dist/cli.cjs +235 -106
- package/dist/cli.js +11 -2
- package/dist/index.cjs +208 -88
- 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-ACXCEHQT.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,41 +1274,24 @@ 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 = {};
|
|
1279
|
+
function extractVersionFromTag(tag) {
|
|
1280
|
+
if (tag.includes("@") && !tag.startsWith("@")) {
|
|
1281
|
+
return tag;
|
|
1282
|
+
}
|
|
1283
|
+
return tag.replace(/^v/, "");
|
|
1284
|
+
}
|
|
1182
1285
|
function generateCompareUrl(repoUrl, from, to) {
|
|
1286
|
+
const fromVersion = extractVersionFromTag(from);
|
|
1287
|
+
const toVersion = extractVersionFromTag(to);
|
|
1183
1288
|
if (/gitlab\.com/i.test(repoUrl)) {
|
|
1184
|
-
return `${repoUrl}/-/compare/${
|
|
1289
|
+
return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
|
|
1185
1290
|
}
|
|
1186
1291
|
if (/bitbucket\.org/i.test(repoUrl)) {
|
|
1187
|
-
return `${repoUrl}/branches/compare/${
|
|
1292
|
+
return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
|
|
1188
1293
|
}
|
|
1189
|
-
return `${repoUrl}/compare/${
|
|
1294
|
+
return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
|
|
1190
1295
|
}
|
|
1191
1296
|
function createTemplateContext(pkg) {
|
|
1192
1297
|
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
|
|
@@ -1233,9 +1338,9 @@ async function processWithLLM(context, config) {
|
|
|
1233
1338
|
entries: context.entries
|
|
1234
1339
|
};
|
|
1235
1340
|
try {
|
|
1236
|
-
(0,
|
|
1341
|
+
(0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
|
|
1237
1342
|
if (config.llm.baseURL) {
|
|
1238
|
-
(0,
|
|
1343
|
+
(0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
|
|
1239
1344
|
}
|
|
1240
1345
|
const rawProvider = createProvider(config.llm);
|
|
1241
1346
|
const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
|
|
@@ -1244,38 +1349,49 @@ async function processWithLLM(context, config) {
|
|
|
1244
1349
|
complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
|
|
1245
1350
|
};
|
|
1246
1351
|
const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
|
|
1247
|
-
(0,
|
|
1248
|
-
if (tasks.enhance) {
|
|
1249
|
-
(0,
|
|
1250
|
-
|
|
1251
|
-
|
|
1352
|
+
(0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
|
|
1353
|
+
if (tasks.enhance && tasks.categorize) {
|
|
1354
|
+
(0, import_core8.info)("Enhancing and categorizing entries with LLM...");
|
|
1355
|
+
const result = await enhanceAndCategorize(provider, context.entries, llmContext);
|
|
1356
|
+
enhanced.entries = result.enhancedEntries;
|
|
1357
|
+
enhanced.categories = {};
|
|
1358
|
+
for (const cat of result.categories) {
|
|
1359
|
+
enhanced.categories[cat.category] = cat.entries;
|
|
1360
|
+
}
|
|
1361
|
+
(0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
|
|
1362
|
+
} else {
|
|
1363
|
+
if (tasks.enhance) {
|
|
1364
|
+
(0, import_core8.info)("Enhancing entries with LLM...");
|
|
1365
|
+
enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
|
|
1366
|
+
(0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
|
|
1367
|
+
}
|
|
1368
|
+
if (tasks.categorize) {
|
|
1369
|
+
(0, import_core8.info)("Categorizing entries with LLM...");
|
|
1370
|
+
const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
|
|
1371
|
+
enhanced.categories = {};
|
|
1372
|
+
for (const cat of categorized) {
|
|
1373
|
+
enhanced.categories[cat.category] = cat.entries;
|
|
1374
|
+
}
|
|
1375
|
+
(0, import_core8.info)(`Created ${categorized.length} categories`);
|
|
1376
|
+
}
|
|
1252
1377
|
}
|
|
1253
1378
|
if (tasks.summarize) {
|
|
1254
|
-
(0,
|
|
1379
|
+
(0, import_core8.info)("Summarizing entries with LLM...");
|
|
1255
1380
|
enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
|
|
1256
1381
|
if (enhanced.summary) {
|
|
1257
|
-
(0,
|
|
1258
|
-
(0,
|
|
1382
|
+
(0, import_core8.info)("Summary generated successfully");
|
|
1383
|
+
(0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
|
|
1259
1384
|
} 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;
|
|
1385
|
+
(0, import_core8.warn)("Summary generation returned empty result");
|
|
1269
1386
|
}
|
|
1270
|
-
(0, import_core7.info)(`Created ${categorized.length} categories`);
|
|
1271
1387
|
}
|
|
1272
1388
|
if (tasks.releaseNotes) {
|
|
1273
|
-
(0,
|
|
1389
|
+
(0, import_core8.info)("Generating release notes with LLM...");
|
|
1274
1390
|
enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
|
|
1275
1391
|
if (enhanced.releaseNotes) {
|
|
1276
|
-
(0,
|
|
1392
|
+
(0, import_core8.info)("Release notes generated successfully");
|
|
1277
1393
|
} else {
|
|
1278
|
-
(0,
|
|
1394
|
+
(0, import_core8.warn)("Release notes generation returned empty result");
|
|
1279
1395
|
}
|
|
1280
1396
|
}
|
|
1281
1397
|
return {
|
|
@@ -1284,8 +1400,8 @@ async function processWithLLM(context, config) {
|
|
|
1284
1400
|
enhanced
|
|
1285
1401
|
};
|
|
1286
1402
|
} catch (error) {
|
|
1287
|
-
(0,
|
|
1288
|
-
(0,
|
|
1403
|
+
(0, import_core8.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1404
|
+
(0, import_core8.warn)("Falling back to raw entries");
|
|
1289
1405
|
return context;
|
|
1290
1406
|
}
|
|
1291
1407
|
}
|
|
@@ -1313,9 +1429,13 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1313
1429
|
);
|
|
1314
1430
|
const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
|
|
1315
1431
|
if (dryRun) {
|
|
1316
|
-
(0,
|
|
1432
|
+
(0, import_core8.info)("--- Changelog Preview ---");
|
|
1317
1433
|
console.log(result.content);
|
|
1318
|
-
(0,
|
|
1434
|
+
(0, import_core8.info)("--- End Preview ---");
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
if (outputPath === "-") {
|
|
1438
|
+
process.stdout.write(result.content);
|
|
1319
1439
|
return;
|
|
1320
1440
|
}
|
|
1321
1441
|
const dir = path6.dirname(outputPath);
|
|
@@ -1323,17 +1443,17 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1323
1443
|
fs8.mkdirSync(dir, { recursive: true });
|
|
1324
1444
|
}
|
|
1325
1445
|
fs8.writeFileSync(outputPath, result.content, "utf-8");
|
|
1326
|
-
(0,
|
|
1446
|
+
(0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
|
|
1327
1447
|
}
|
|
1328
1448
|
async function runPipeline(input, config, dryRun) {
|
|
1329
|
-
(0,
|
|
1449
|
+
(0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
|
|
1330
1450
|
let contexts = input.packages.map(createTemplateContext);
|
|
1331
1451
|
if (config.llm && !process.env.CHANGELOG_NO_LLM) {
|
|
1332
|
-
(0,
|
|
1452
|
+
(0, import_core8.info)("Processing with LLM enhancement");
|
|
1333
1453
|
contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
|
|
1334
1454
|
}
|
|
1335
1455
|
for (const output of config.output) {
|
|
1336
|
-
(0,
|
|
1456
|
+
(0, import_core8.info)(`Generating ${output.format} output`);
|
|
1337
1457
|
switch (output.format) {
|
|
1338
1458
|
case "markdown": {
|
|
1339
1459
|
const file = output.file ?? "CHANGELOG.md";
|
|
@@ -1351,22 +1471,22 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1351
1471
|
}
|
|
1352
1472
|
case "github-release": {
|
|
1353
1473
|
if (dryRun) {
|
|
1354
|
-
(0,
|
|
1474
|
+
(0, import_core8.info)("[DRY RUN] Would create GitHub release");
|
|
1355
1475
|
break;
|
|
1356
1476
|
}
|
|
1357
1477
|
const firstContext = contexts[0];
|
|
1358
1478
|
if (!firstContext) {
|
|
1359
|
-
(0,
|
|
1479
|
+
(0, import_core8.warn)("No context available for GitHub release");
|
|
1360
1480
|
break;
|
|
1361
1481
|
}
|
|
1362
1482
|
const repoUrl = firstContext.repoUrl;
|
|
1363
1483
|
if (!repoUrl) {
|
|
1364
|
-
(0,
|
|
1484
|
+
(0, import_core8.warn)("No repo URL available, cannot create GitHub release");
|
|
1365
1485
|
break;
|
|
1366
1486
|
}
|
|
1367
1487
|
const parsed = parseRepoUrl(repoUrl);
|
|
1368
1488
|
if (!parsed) {
|
|
1369
|
-
(0,
|
|
1489
|
+
(0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
|
|
1370
1490
|
break;
|
|
1371
1491
|
}
|
|
1372
1492
|
await createGitHubRelease(firstContext, {
|
|
@@ -1388,7 +1508,7 @@ async function processInput(inputJson, config, dryRun) {
|
|
|
1388
1508
|
// src/monorepo/aggregator.ts
|
|
1389
1509
|
var fs9 = __toESM(require("fs"), 1);
|
|
1390
1510
|
var path7 = __toESM(require("path"), 1);
|
|
1391
|
-
var
|
|
1511
|
+
var import_core9 = require("@releasekit/core");
|
|
1392
1512
|
|
|
1393
1513
|
// src/monorepo/splitter.ts
|
|
1394
1514
|
function splitByPackage(contexts) {
|
|
@@ -1402,7 +1522,7 @@ function splitByPackage(contexts) {
|
|
|
1402
1522
|
// src/monorepo/aggregator.ts
|
|
1403
1523
|
function writeFile(outputPath, content, dryRun) {
|
|
1404
1524
|
if (dryRun) {
|
|
1405
|
-
(0,
|
|
1525
|
+
(0, import_core9.info)(`[DRY RUN] Would write to ${outputPath}`);
|
|
1406
1526
|
console.log(content);
|
|
1407
1527
|
return;
|
|
1408
1528
|
}
|
|
@@ -1411,7 +1531,7 @@ function writeFile(outputPath, content, dryRun) {
|
|
|
1411
1531
|
fs9.mkdirSync(dir, { recursive: true });
|
|
1412
1532
|
}
|
|
1413
1533
|
fs9.writeFileSync(outputPath, content, "utf-8");
|
|
1414
|
-
(0,
|
|
1534
|
+
(0, import_core9.success)(`Changelog written to ${outputPath}`);
|
|
1415
1535
|
}
|
|
1416
1536
|
function aggregateToRoot(contexts) {
|
|
1417
1537
|
const aggregated = {
|
|
@@ -1436,7 +1556,7 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
|
|
|
1436
1556
|
if (options.mode === "root" || options.mode === "both") {
|
|
1437
1557
|
const aggregated = aggregateToRoot(contexts);
|
|
1438
1558
|
const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
|
|
1439
|
-
(0,
|
|
1559
|
+
(0, import_core9.info)(`Writing root changelog to ${rootPath}`);
|
|
1440
1560
|
const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
|
|
1441
1561
|
writeFile(rootPath, rootContent, dryRun);
|
|
1442
1562
|
}
|
|
@@ -1448,11 +1568,11 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
|
|
|
1448
1568
|
const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
|
|
1449
1569
|
if (packageDir) {
|
|
1450
1570
|
const changelogPath = path7.join(packageDir, "CHANGELOG.md");
|
|
1451
|
-
(0,
|
|
1571
|
+
(0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
|
|
1452
1572
|
const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
|
|
1453
1573
|
writeFile(changelogPath, pkgContent, dryRun);
|
|
1454
1574
|
} else {
|
|
1455
|
-
(0,
|
|
1575
|
+
(0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
|
|
1456
1576
|
}
|
|
1457
1577
|
}
|
|
1458
1578
|
}
|
package/dist/index.js
CHANGED