@releasekit/notes 0.2.0-next.9 → 0.3.0-next.0
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/aggregator-BDTUZWOA.js +13 -0
- package/dist/chunk-H7G2HRHI.js +134 -0
- package/dist/chunk-O4VCGEZT.js +147 -0
- package/dist/{chunk-BLWJTLRD.js → chunk-X4LY5WGG.js} +289 -394
- package/dist/cli.cjs +542 -369
- package/dist/cli.js +6 -27
- package/dist/index.cjs +544 -350
- package/dist/index.d.cts +41 -8
- package/dist/index.d.ts +41 -8
- package/dist/index.js +12 -6
- package/package.json +42 -31
package/dist/cli.cjs
CHANGED
|
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
9
16
|
var __copyProps = (to, from, except, desc) => {
|
|
10
17
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
18
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,6 +30,295 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
30
|
mod
|
|
24
31
|
));
|
|
25
32
|
|
|
33
|
+
// src/output/markdown.ts
|
|
34
|
+
function groupEntriesByType(entries) {
|
|
35
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const type of TYPE_ORDER) {
|
|
37
|
+
grouped.set(type, []);
|
|
38
|
+
}
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const existing = grouped.get(entry.type) ?? [];
|
|
41
|
+
existing.push(entry);
|
|
42
|
+
grouped.set(entry.type, existing);
|
|
43
|
+
}
|
|
44
|
+
return grouped;
|
|
45
|
+
}
|
|
46
|
+
function formatEntry(entry) {
|
|
47
|
+
let line;
|
|
48
|
+
if (entry.breaking && entry.scope) {
|
|
49
|
+
line = `- **BREAKING** **${entry.scope}**: ${entry.description}`;
|
|
50
|
+
} else if (entry.breaking) {
|
|
51
|
+
line = `- **BREAKING** ${entry.description}`;
|
|
52
|
+
} else if (entry.scope) {
|
|
53
|
+
line = `- **${entry.scope}**: ${entry.description}`;
|
|
54
|
+
} else {
|
|
55
|
+
line = `- ${entry.description}`;
|
|
56
|
+
}
|
|
57
|
+
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
58
|
+
line += ` (${entry.issueIds.join(", ")})`;
|
|
59
|
+
}
|
|
60
|
+
return line;
|
|
61
|
+
}
|
|
62
|
+
function formatVersion(context) {
|
|
63
|
+
const lines = [];
|
|
64
|
+
const versionHeader = context.previousVersion ? `## [${context.version}]` : `## ${context.version}`;
|
|
65
|
+
lines.push(`${versionHeader} - ${context.date}`);
|
|
66
|
+
lines.push("");
|
|
67
|
+
if (context.compareUrl) {
|
|
68
|
+
lines.push(`[Full Changelog](${context.compareUrl})`);
|
|
69
|
+
lines.push("");
|
|
70
|
+
}
|
|
71
|
+
if (context.enhanced?.summary) {
|
|
72
|
+
lines.push(context.enhanced.summary);
|
|
73
|
+
lines.push("");
|
|
74
|
+
}
|
|
75
|
+
const grouped = groupEntriesByType(context.entries);
|
|
76
|
+
for (const [type, entries] of grouped) {
|
|
77
|
+
if (entries.length === 0) continue;
|
|
78
|
+
lines.push(`### ${TYPE_LABELS[type]}`);
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
lines.push(formatEntry(entry));
|
|
81
|
+
}
|
|
82
|
+
lines.push("");
|
|
83
|
+
}
|
|
84
|
+
return lines.join("\n");
|
|
85
|
+
}
|
|
86
|
+
function formatHeader() {
|
|
87
|
+
return `# Changelog
|
|
88
|
+
|
|
89
|
+
All notable changes to this project will be documented in this file.
|
|
90
|
+
|
|
91
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
92
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
93
|
+
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
function renderMarkdown(contexts) {
|
|
97
|
+
const sections = [formatHeader()];
|
|
98
|
+
for (const context of contexts) {
|
|
99
|
+
sections.push(formatVersion(context));
|
|
100
|
+
}
|
|
101
|
+
return sections.join("\n");
|
|
102
|
+
}
|
|
103
|
+
function prependVersion(existingPath, context) {
|
|
104
|
+
let existing = "";
|
|
105
|
+
if (fs2.existsSync(existingPath)) {
|
|
106
|
+
existing = fs2.readFileSync(existingPath, "utf-8");
|
|
107
|
+
const headerEnd = existing.indexOf("\n## ");
|
|
108
|
+
if (headerEnd >= 0) {
|
|
109
|
+
const header = existing.slice(0, headerEnd);
|
|
110
|
+
const body = existing.slice(headerEnd + 1);
|
|
111
|
+
const newVersion = formatVersion(context);
|
|
112
|
+
return `${header}
|
|
113
|
+
|
|
114
|
+
${newVersion}
|
|
115
|
+
${body}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return renderMarkdown([context]);
|
|
119
|
+
}
|
|
120
|
+
function writeMarkdown(outputPath, contexts, config, dryRun) {
|
|
121
|
+
const content = renderMarkdown(contexts);
|
|
122
|
+
if (dryRun) {
|
|
123
|
+
(0, import_core5.info)(`Would write changelog to ${outputPath}`);
|
|
124
|
+
(0, import_core5.debug)("--- Changelog Preview ---");
|
|
125
|
+
(0, import_core5.debug)(content);
|
|
126
|
+
(0, import_core5.debug)("--- End Preview ---");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const dir = path.dirname(outputPath);
|
|
130
|
+
if (!fs2.existsSync(dir)) {
|
|
131
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
if (outputPath === "-") {
|
|
134
|
+
process.stdout.write(content);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
|
|
138
|
+
const firstContext = contexts[0];
|
|
139
|
+
if (firstContext) {
|
|
140
|
+
const updated = prependVersion(outputPath, firstContext);
|
|
141
|
+
fs2.writeFileSync(outputPath, updated, "utf-8");
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
fs2.writeFileSync(outputPath, content, "utf-8");
|
|
145
|
+
}
|
|
146
|
+
(0, import_core5.success)(`Changelog written to ${outputPath}`);
|
|
147
|
+
}
|
|
148
|
+
var fs2, path, import_core5, TYPE_ORDER, TYPE_LABELS;
|
|
149
|
+
var init_markdown = __esm({
|
|
150
|
+
"src/output/markdown.ts"() {
|
|
151
|
+
"use strict";
|
|
152
|
+
fs2 = __toESM(require("fs"), 1);
|
|
153
|
+
path = __toESM(require("path"), 1);
|
|
154
|
+
import_core5 = require("@releasekit/core");
|
|
155
|
+
TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
|
|
156
|
+
TYPE_LABELS = {
|
|
157
|
+
added: "Added",
|
|
158
|
+
changed: "Changed",
|
|
159
|
+
deprecated: "Deprecated",
|
|
160
|
+
removed: "Removed",
|
|
161
|
+
fixed: "Fixed",
|
|
162
|
+
security: "Security"
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// src/monorepo/splitter.ts
|
|
168
|
+
function splitByPackage(contexts) {
|
|
169
|
+
const byPackage = /* @__PURE__ */ new Map();
|
|
170
|
+
for (const ctx of contexts) {
|
|
171
|
+
byPackage.set(ctx.packageName, ctx);
|
|
172
|
+
}
|
|
173
|
+
return byPackage;
|
|
174
|
+
}
|
|
175
|
+
var init_splitter = __esm({
|
|
176
|
+
"src/monorepo/splitter.ts"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// src/monorepo/aggregator.ts
|
|
182
|
+
var aggregator_exports = {};
|
|
183
|
+
__export(aggregator_exports, {
|
|
184
|
+
aggregateToRoot: () => aggregateToRoot,
|
|
185
|
+
detectMonorepo: () => detectMonorepo,
|
|
186
|
+
splitByPackage: () => splitByPackage,
|
|
187
|
+
writeMonorepoChangelogs: () => writeMonorepoChangelogs
|
|
188
|
+
});
|
|
189
|
+
function writeFile(outputPath, content, dryRun) {
|
|
190
|
+
if (dryRun) {
|
|
191
|
+
(0, import_core8.info)(`Would write to ${outputPath}`);
|
|
192
|
+
(0, import_core8.debug)(content);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
const dir = path6.dirname(outputPath);
|
|
196
|
+
if (!fs8.existsSync(dir)) {
|
|
197
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
198
|
+
}
|
|
199
|
+
fs8.writeFileSync(outputPath, content, "utf-8");
|
|
200
|
+
(0, import_core8.success)(`Changelog written to ${outputPath}`);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
function aggregateToRoot(contexts) {
|
|
204
|
+
const aggregated = {
|
|
205
|
+
packageName: "monorepo",
|
|
206
|
+
version: contexts[0]?.version ?? "0.0.0",
|
|
207
|
+
previousVersion: contexts[0]?.previousVersion ?? null,
|
|
208
|
+
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "",
|
|
209
|
+
repoUrl: contexts[0]?.repoUrl ?? null,
|
|
210
|
+
entries: []
|
|
211
|
+
};
|
|
212
|
+
for (const ctx of contexts) {
|
|
213
|
+
for (const entry of ctx.entries) {
|
|
214
|
+
aggregated.entries.push({
|
|
215
|
+
...entry,
|
|
216
|
+
scope: entry.scope ? `${ctx.packageName}/${entry.scope}` : ctx.packageName
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return aggregated;
|
|
221
|
+
}
|
|
222
|
+
function writeMonorepoChangelogs(contexts, options, config, dryRun) {
|
|
223
|
+
const files = [];
|
|
224
|
+
if (options.mode === "root" || options.mode === "both") {
|
|
225
|
+
const aggregated = aggregateToRoot(contexts);
|
|
226
|
+
const rootPath = path6.join(options.rootPath, "CHANGELOG.md");
|
|
227
|
+
(0, import_core8.info)(`Writing root changelog to ${rootPath}`);
|
|
228
|
+
const rootContent = config.updateStrategy === "prepend" && fs8.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
|
|
229
|
+
if (writeFile(rootPath, rootContent, dryRun)) {
|
|
230
|
+
files.push(rootPath);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (options.mode === "packages" || options.mode === "both") {
|
|
234
|
+
const byPackage = splitByPackage(contexts);
|
|
235
|
+
const packageDirMap = buildPackageDirMap(options.rootPath, options.packagesPath);
|
|
236
|
+
for (const [packageName, ctx] of byPackage) {
|
|
237
|
+
const simpleName = packageName.split("/").pop();
|
|
238
|
+
const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
|
|
239
|
+
if (packageDir) {
|
|
240
|
+
const changelogPath = path6.join(packageDir, "CHANGELOG.md");
|
|
241
|
+
(0, import_core8.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
|
|
242
|
+
const pkgContent = config.updateStrategy === "prepend" && fs8.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
|
|
243
|
+
if (writeFile(changelogPath, pkgContent, dryRun)) {
|
|
244
|
+
files.push(changelogPath);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
(0, import_core8.info)(`Could not find directory for package ${packageName}, skipping`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return files;
|
|
252
|
+
}
|
|
253
|
+
function buildPackageDirMap(rootPath, packagesPath) {
|
|
254
|
+
const map = /* @__PURE__ */ new Map();
|
|
255
|
+
const packagesDir = path6.join(rootPath, packagesPath);
|
|
256
|
+
if (!fs8.existsSync(packagesDir)) {
|
|
257
|
+
return map;
|
|
258
|
+
}
|
|
259
|
+
for (const entry of fs8.readdirSync(packagesDir, { withFileTypes: true })) {
|
|
260
|
+
if (!entry.isDirectory()) continue;
|
|
261
|
+
const dirPath = path6.join(packagesDir, entry.name);
|
|
262
|
+
map.set(entry.name, dirPath);
|
|
263
|
+
const packageJsonPath = path6.join(dirPath, "package.json");
|
|
264
|
+
if (fs8.existsSync(packageJsonPath)) {
|
|
265
|
+
try {
|
|
266
|
+
const pkg = JSON.parse(fs8.readFileSync(packageJsonPath, "utf-8"));
|
|
267
|
+
if (pkg.name) {
|
|
268
|
+
map.set(pkg.name, dirPath);
|
|
269
|
+
}
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return map;
|
|
275
|
+
}
|
|
276
|
+
function detectMonorepo(cwd) {
|
|
277
|
+
const pnpmWorkspacesPath = path6.join(cwd, "pnpm-workspace.yaml");
|
|
278
|
+
const packageJsonPath = path6.join(cwd, "package.json");
|
|
279
|
+
if (fs8.existsSync(pnpmWorkspacesPath)) {
|
|
280
|
+
const content = fs8.readFileSync(pnpmWorkspacesPath, "utf-8");
|
|
281
|
+
const packagesMatch = content.match(/packages:\s*\n\s*-\s*['"]([^'"]+)['"]/);
|
|
282
|
+
if (packagesMatch?.[1]) {
|
|
283
|
+
const packagesGlob = packagesMatch[1];
|
|
284
|
+
const packagesPath = packagesGlob.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
|
|
285
|
+
return { isMonorepo: true, packagesPath: packagesPath || "packages" };
|
|
286
|
+
}
|
|
287
|
+
return { isMonorepo: true, packagesPath: "packages" };
|
|
288
|
+
}
|
|
289
|
+
if (fs8.existsSync(packageJsonPath)) {
|
|
290
|
+
try {
|
|
291
|
+
const content = fs8.readFileSync(packageJsonPath, "utf-8");
|
|
292
|
+
const pkg = JSON.parse(content);
|
|
293
|
+
if (pkg.workspaces) {
|
|
294
|
+
const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages;
|
|
295
|
+
if (workspaces?.length) {
|
|
296
|
+
const firstWorkspace = workspaces[0];
|
|
297
|
+
if (firstWorkspace) {
|
|
298
|
+
const packagesPath = firstWorkspace.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
|
|
299
|
+
return { isMonorepo: true, packagesPath: packagesPath || "packages" };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
} catch {
|
|
304
|
+
return { isMonorepo: false, packagesPath: "" };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return { isMonorepo: false, packagesPath: "" };
|
|
308
|
+
}
|
|
309
|
+
var fs8, path6, import_core8;
|
|
310
|
+
var init_aggregator = __esm({
|
|
311
|
+
"src/monorepo/aggregator.ts"() {
|
|
312
|
+
"use strict";
|
|
313
|
+
fs8 = __toESM(require("fs"), 1);
|
|
314
|
+
path6 = __toESM(require("path"), 1);
|
|
315
|
+
import_core8 = require("@releasekit/core");
|
|
316
|
+
init_markdown();
|
|
317
|
+
init_splitter();
|
|
318
|
+
init_splitter();
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
|
|
26
322
|
// src/cli.ts
|
|
27
323
|
var fs10 = __toESM(require("fs"), 1);
|
|
28
324
|
var readline = __toESM(require("readline"), 1);
|
|
@@ -43,9 +339,9 @@ function getDefaultConfig() {
|
|
|
43
339
|
}
|
|
44
340
|
|
|
45
341
|
// src/core/pipeline.ts
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var
|
|
342
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
343
|
+
var path7 = __toESM(require("path"), 1);
|
|
344
|
+
var import_core9 = require("@releasekit/core");
|
|
49
345
|
|
|
50
346
|
// src/input/package-versioner.ts
|
|
51
347
|
var fs = __toESM(require("fs"), 1);
|
|
@@ -354,6 +650,83 @@ var OpenAICompatibleProvider = class extends BaseLLMProvider {
|
|
|
354
650
|
|
|
355
651
|
// src/llm/tasks/categorize.ts
|
|
356
652
|
var import_core3 = require("@releasekit/core");
|
|
653
|
+
|
|
654
|
+
// src/llm/prompts.ts
|
|
655
|
+
function resolvePrompt(taskName, defaultPrompt, promptsConfig) {
|
|
656
|
+
if (!promptsConfig) return defaultPrompt;
|
|
657
|
+
const fullTemplate = promptsConfig.templates?.[taskName];
|
|
658
|
+
if (fullTemplate) return fullTemplate;
|
|
659
|
+
const additionalInstructions = promptsConfig.instructions?.[taskName];
|
|
660
|
+
if (additionalInstructions) {
|
|
661
|
+
const insertionPoint = defaultPrompt.lastIndexOf("Output only valid JSON");
|
|
662
|
+
if (insertionPoint !== -1) {
|
|
663
|
+
return `${defaultPrompt.slice(0, insertionPoint)}Additional instructions:
|
|
664
|
+
${additionalInstructions}
|
|
665
|
+
|
|
666
|
+
${defaultPrompt.slice(insertionPoint)}`;
|
|
667
|
+
}
|
|
668
|
+
return `${defaultPrompt}
|
|
669
|
+
|
|
670
|
+
Additional instructions:
|
|
671
|
+
${additionalInstructions}`;
|
|
672
|
+
}
|
|
673
|
+
return defaultPrompt;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// src/llm/scopes.ts
|
|
677
|
+
function getAllowedScopesFromCategories(categories) {
|
|
678
|
+
const scopeMap = /* @__PURE__ */ new Map();
|
|
679
|
+
for (const cat of categories) {
|
|
680
|
+
if (cat.scopes && cat.scopes.length > 0) {
|
|
681
|
+
scopeMap.set(cat.name, cat.scopes);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return scopeMap;
|
|
685
|
+
}
|
|
686
|
+
function resolveAllowedScopes(scopeConfig, categories, packageNames) {
|
|
687
|
+
if (!scopeConfig || scopeConfig.mode === "unrestricted") return null;
|
|
688
|
+
if (scopeConfig.mode === "none") return [];
|
|
689
|
+
if (scopeConfig.mode === "packages") return packageNames ?? [];
|
|
690
|
+
if (scopeConfig.mode === "restricted") {
|
|
691
|
+
const explicit = scopeConfig.rules?.allowed ?? [];
|
|
692
|
+
const all = new Set(explicit);
|
|
693
|
+
if (categories) {
|
|
694
|
+
const fromCategories = getAllowedScopesFromCategories(categories);
|
|
695
|
+
for (const scopes of fromCategories.values()) {
|
|
696
|
+
for (const s of scopes) all.add(s);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return [...all];
|
|
700
|
+
}
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
function validateScope(scope, allowedScopes, rules) {
|
|
704
|
+
if (!scope || allowedScopes === null) return scope;
|
|
705
|
+
if (allowedScopes.length === 0) return void 0;
|
|
706
|
+
const caseSensitive = rules?.caseSensitive ?? false;
|
|
707
|
+
const normalise = (s) => caseSensitive ? s : s.toLowerCase();
|
|
708
|
+
const isAllowed = allowedScopes.some((a) => normalise(a) === normalise(scope));
|
|
709
|
+
if (isAllowed) return scope;
|
|
710
|
+
switch (rules?.invalidScopeAction ?? "remove") {
|
|
711
|
+
case "keep":
|
|
712
|
+
return scope;
|
|
713
|
+
case "fallback":
|
|
714
|
+
return rules?.fallbackScope;
|
|
715
|
+
case "remove":
|
|
716
|
+
default:
|
|
717
|
+
return void 0;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
function validateEntryScopes(entries, scopeConfig, categories) {
|
|
721
|
+
const allowedScopes = resolveAllowedScopes(scopeConfig, categories);
|
|
722
|
+
if (allowedScopes === null) return entries;
|
|
723
|
+
return entries.map((entry) => ({
|
|
724
|
+
...entry,
|
|
725
|
+
scope: validateScope(entry.scope, allowedScopes, scopeConfig?.rules)
|
|
726
|
+
}));
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/llm/tasks/categorize.ts
|
|
357
730
|
var DEFAULT_CATEGORIZE_PROMPT = `You are categorizing changelog entries for a software release.
|
|
358
731
|
|
|
359
732
|
Given the following entries, group them into meaningful categories (e.g., "Core", "UI", "API", "Performance", "Bug Fixes", "Documentation").
|
|
@@ -365,20 +738,21 @@ Entries:
|
|
|
365
738
|
|
|
366
739
|
Output only valid JSON, nothing else:`;
|
|
367
740
|
function buildCustomCategorizePrompt(categories) {
|
|
368
|
-
const categoryList = categories.map((c) =>
|
|
369
|
-
|
|
741
|
+
const categoryList = categories.map((c) => {
|
|
742
|
+
const scopeInfo = c.scopes?.length ? ` Allowed scopes: ${c.scopes.join(", ")}.` : "";
|
|
743
|
+
return `- "${c.name}": ${c.description}${scopeInfo}`;
|
|
744
|
+
}).join("\n");
|
|
745
|
+
const scopeMap = getAllowedScopesFromCategories(categories);
|
|
370
746
|
let scopeInstructions = "";
|
|
371
|
-
if (
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (scopes.length > 0) {
|
|
376
|
-
scopeInstructions = `
|
|
377
|
-
|
|
378
|
-
For the "Developer" category, you MUST assign a scope from this exact list: ${scopes.join(", ")}.
|
|
379
|
-
`;
|
|
380
|
-
}
|
|
747
|
+
if (scopeMap.size > 0) {
|
|
748
|
+
const entries = [];
|
|
749
|
+
for (const [catName, scopes] of scopeMap) {
|
|
750
|
+
entries.push(`For "${catName}", assign a scope from: ${scopes.join(", ")}.`);
|
|
381
751
|
}
|
|
752
|
+
scopeInstructions = `
|
|
753
|
+
|
|
754
|
+
${entries.join("\n")}
|
|
755
|
+
Only use scopes from these predefined lists. If an entry does not fit any scope, set scope to null.`;
|
|
382
756
|
}
|
|
383
757
|
return `You are categorizing changelog entries for a software release.
|
|
384
758
|
|
|
@@ -386,9 +760,10 @@ Given the following entries, group them into the specified categories. Only use
|
|
|
386
760
|
|
|
387
761
|
Categories:
|
|
388
762
|
${categoryList}${scopeInstructions}
|
|
763
|
+
|
|
389
764
|
Output a JSON object with two fields:
|
|
390
765
|
- "categories": an object where keys are category names and values are arrays of entry indices (0-based)
|
|
391
|
-
- "scopes": an object where keys are entry indices (as strings) and values are scope labels
|
|
766
|
+
- "scopes": an object where keys are entry indices (as strings) and values are scope labels. Only include entries that have a valid scope from the predefined list.
|
|
392
767
|
|
|
393
768
|
Entries:
|
|
394
769
|
{{entries}}
|
|
@@ -399,9 +774,11 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
399
774
|
if (entries.length === 0) {
|
|
400
775
|
return [];
|
|
401
776
|
}
|
|
402
|
-
const
|
|
777
|
+
const entriesCopy = entries.map((e) => ({ ...e, scope: void 0 }));
|
|
778
|
+
const entriesText = entriesCopy.map((e, i) => `${i}. [${e.type}]: ${e.description}`).join("\n");
|
|
403
779
|
const hasCustomCategories = context.categories && context.categories.length > 0;
|
|
404
|
-
const
|
|
780
|
+
const defaultPrompt = hasCustomCategories ? buildCustomCategorizePrompt(context.categories) : DEFAULT_CATEGORIZE_PROMPT;
|
|
781
|
+
const promptTemplate = resolvePrompt("categorize", defaultPrompt, context.prompts);
|
|
405
782
|
const prompt = promptTemplate.replace("{{entries}}", entriesText);
|
|
406
783
|
try {
|
|
407
784
|
const response = await provider.complete(prompt);
|
|
@@ -413,13 +790,14 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
413
790
|
const scopeMap = parsed.scopes || {};
|
|
414
791
|
for (const [indexStr, scope] of Object.entries(scopeMap)) {
|
|
415
792
|
const idx = Number.parseInt(indexStr, 10);
|
|
416
|
-
if (
|
|
417
|
-
|
|
793
|
+
if (entriesCopy[idx] && scope && scope.trim()) {
|
|
794
|
+
entriesCopy[idx] = { ...entriesCopy[idx], scope: scope.trim() };
|
|
418
795
|
}
|
|
419
796
|
}
|
|
797
|
+
const validatedEntries = validateEntryScopes(entriesCopy, context.scopes, context.categories);
|
|
420
798
|
for (const [category, rawIndices] of Object.entries(categoryMap)) {
|
|
421
799
|
const indices = Array.isArray(rawIndices) ? rawIndices : [];
|
|
422
|
-
const categoryEntries = indices.map((i) =>
|
|
800
|
+
const categoryEntries = indices.map((i) => validatedEntries[i]).filter((e) => e !== void 0);
|
|
423
801
|
if (categoryEntries.length > 0) {
|
|
424
802
|
result.push({ category, entries: categoryEntries });
|
|
425
803
|
}
|
|
@@ -428,7 +806,7 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
428
806
|
const categoryMap = parsed;
|
|
429
807
|
for (const [category, rawIndices] of Object.entries(categoryMap)) {
|
|
430
808
|
const indices = Array.isArray(rawIndices) ? rawIndices : [];
|
|
431
|
-
const categoryEntries = indices.map((i) =>
|
|
809
|
+
const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
|
|
432
810
|
if (categoryEntries.length > 0) {
|
|
433
811
|
result.push({ category, entries: categoryEntries });
|
|
434
812
|
}
|
|
@@ -439,12 +817,12 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
439
817
|
(0, import_core3.warn)(
|
|
440
818
|
`LLM categorization failed, falling back to General: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
441
819
|
);
|
|
442
|
-
return [{ category: "General", entries }];
|
|
820
|
+
return [{ category: "General", entries: entriesCopy }];
|
|
443
821
|
}
|
|
444
822
|
}
|
|
445
823
|
|
|
446
824
|
// src/llm/tasks/enhance.ts
|
|
447
|
-
var
|
|
825
|
+
var DEFAULT_ENHANCE_PROMPT = `You are improving changelog entries for a software project.
|
|
448
826
|
Given a technical commit message, rewrite it as a clear, user-friendly changelog entry.
|
|
449
827
|
|
|
450
828
|
Rules:
|
|
@@ -460,9 +838,10 @@ Type: {{type}}
|
|
|
460
838
|
Description: {{description}}
|
|
461
839
|
|
|
462
840
|
Rewritten description (only output the new description, nothing else):`;
|
|
463
|
-
async function enhanceEntry(provider, entry,
|
|
464
|
-
const styleText =
|
|
465
|
-
const
|
|
841
|
+
async function enhanceEntry(provider, entry, context) {
|
|
842
|
+
const styleText = context.style ? `- ${context.style}` : '- Use present tense ("Add feature" not "Added feature")';
|
|
843
|
+
const defaultPrompt = DEFAULT_ENHANCE_PROMPT.replace("{{style}}", styleText).replace("{{type}}", entry.type).replace("{{#if scope}}Scope: {{scope}}{{/if}}", entry.scope ? `Scope: ${entry.scope}` : "").replace("{{description}}", entry.description);
|
|
844
|
+
const prompt = resolvePrompt("enhance", defaultPrompt, context.prompts);
|
|
466
845
|
const response = await provider.complete(prompt);
|
|
467
846
|
return response.trim();
|
|
468
847
|
}
|
|
@@ -518,7 +897,23 @@ function buildPrompt(entries, categories, style) {
|
|
|
518
897
|
const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
|
|
519
898
|
const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
|
|
520
899
|
const categorySection = categories ? `Categories (use ONLY these):
|
|
521
|
-
${categories.map((c) =>
|
|
900
|
+
${categories.map((c) => {
|
|
901
|
+
const scopeInfo = c.scopes?.length ? ` Allowed scopes: ${c.scopes.join(", ")}.` : "";
|
|
902
|
+
return `- "${c.name}": ${c.description}${scopeInfo}`;
|
|
903
|
+
}).join("\n")}` : `Categories: Group into meaningful categories (e.g., "New", "Fixed", "Changed", "Removed").`;
|
|
904
|
+
let scopeInstruction = "";
|
|
905
|
+
if (categories) {
|
|
906
|
+
const scopeMap = getAllowedScopesFromCategories(categories);
|
|
907
|
+
if (scopeMap.size > 0) {
|
|
908
|
+
const parts = [];
|
|
909
|
+
for (const [catName, scopes] of scopeMap) {
|
|
910
|
+
parts.push(`For "${catName}" entries, assign a scope from: ${scopes.join(", ")}.`);
|
|
911
|
+
}
|
|
912
|
+
scopeInstruction = `
|
|
913
|
+
${parts.join("\n")}
|
|
914
|
+
Only use scopes from these predefined lists. Set scope to null if no scope applies.`;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
522
917
|
return `You are generating release notes for a software project. Given the following changelog entries, do two things:
|
|
523
918
|
|
|
524
919
|
1. **Rewrite** each entry as a clear, user-friendly description
|
|
@@ -529,9 +924,7 @@ Style guidelines:
|
|
|
529
924
|
- Be concise (1 short sentence per entry)
|
|
530
925
|
- Focus on what changed, not implementation details
|
|
531
926
|
|
|
532
|
-
${categorySection}
|
|
533
|
-
|
|
534
|
-
${categories ? 'For entries in categories involving internal/developer changes, set a "scope" field with a short subcategory label (e.g., "CI", "Dependencies", "Testing").' : ""}
|
|
927
|
+
${categorySection}${scopeInstruction}
|
|
535
928
|
|
|
536
929
|
Entries:
|
|
537
930
|
${entriesText}
|
|
@@ -548,7 +941,8 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
548
941
|
const retryOpts = LLM_DEFAULTS.retry;
|
|
549
942
|
try {
|
|
550
943
|
return await withRetry(async () => {
|
|
551
|
-
const
|
|
944
|
+
const defaultPrompt = buildPrompt(entries, context.categories, context.style);
|
|
945
|
+
const prompt = resolvePrompt("enhanceAndCategorize", defaultPrompt, context.prompts);
|
|
552
946
|
const response = await provider.complete(prompt);
|
|
553
947
|
const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
554
948
|
const parsed = JSON.parse(cleaned);
|
|
@@ -564,22 +958,23 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
564
958
|
scope: result.scope || original.scope
|
|
565
959
|
};
|
|
566
960
|
});
|
|
961
|
+
const validatedEntries = validateEntryScopes(enhancedEntries, context.scopes, context.categories);
|
|
567
962
|
const categoryMap = /* @__PURE__ */ new Map();
|
|
568
963
|
for (let i = 0; i < parsed.entries.length; i++) {
|
|
569
964
|
const result = parsed.entries[i];
|
|
570
965
|
const category = result?.category || "General";
|
|
571
|
-
const entry =
|
|
966
|
+
const entry = validatedEntries[i];
|
|
572
967
|
if (!entry) continue;
|
|
573
968
|
if (!categoryMap.has(category)) {
|
|
574
969
|
categoryMap.set(category, []);
|
|
575
970
|
}
|
|
576
|
-
categoryMap.get(category)
|
|
971
|
+
categoryMap.get(category)?.push(entry);
|
|
577
972
|
}
|
|
578
973
|
const categories = [];
|
|
579
974
|
for (const [category, catEntries] of categoryMap) {
|
|
580
975
|
categories.push({ category, entries: catEntries });
|
|
581
976
|
}
|
|
582
|
-
return { enhancedEntries, categories };
|
|
977
|
+
return { enhancedEntries: validatedEntries, categories };
|
|
583
978
|
}, retryOpts);
|
|
584
979
|
} catch (error2) {
|
|
585
980
|
(0, import_core4.warn)(
|
|
@@ -593,7 +988,7 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
593
988
|
}
|
|
594
989
|
|
|
595
990
|
// src/llm/tasks/release-notes.ts
|
|
596
|
-
var
|
|
991
|
+
var DEFAULT_RELEASE_NOTES_PROMPT = `You are writing release notes for a software project.
|
|
597
992
|
|
|
598
993
|
Create engaging, user-friendly release notes for the following changes.
|
|
599
994
|
|
|
@@ -626,16 +1021,17 @@ No notable changes in this release.`;
|
|
|
626
1021
|
if (e.breaking) line += " **BREAKING**";
|
|
627
1022
|
return line;
|
|
628
1023
|
}).join("\n");
|
|
629
|
-
const
|
|
1024
|
+
const defaultPrompt = DEFAULT_RELEASE_NOTES_PROMPT.replace("{{version}}", context.version ?? "v1.0.0").replace(
|
|
630
1025
|
"{{#if previousVersion}}Previous version: {{previousVersion}}{{/if}}",
|
|
631
1026
|
context.previousVersion ? `Previous version: ${context.previousVersion}` : ""
|
|
632
1027
|
).replace("{{date}}", context.date ?? (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "").replace("{{entries}}", entriesText);
|
|
1028
|
+
const prompt = resolvePrompt("releaseNotes", defaultPrompt, context.prompts);
|
|
633
1029
|
const response = await provider.complete(prompt);
|
|
634
1030
|
return response.trim();
|
|
635
1031
|
}
|
|
636
1032
|
|
|
637
1033
|
// src/llm/tasks/summarize.ts
|
|
638
|
-
var
|
|
1034
|
+
var DEFAULT_SUMMARIZE_PROMPT = `You are creating a summary of changes for a software release.
|
|
639
1035
|
|
|
640
1036
|
Given the following changelog entries, create a brief summary (2-3 sentences) that captures the main themes of this release.
|
|
641
1037
|
|
|
@@ -643,12 +1039,13 @@ Entries:
|
|
|
643
1039
|
{{entries}}
|
|
644
1040
|
|
|
645
1041
|
Summary (only output the summary, nothing else):`;
|
|
646
|
-
async function summarizeEntries(provider, entries,
|
|
1042
|
+
async function summarizeEntries(provider, entries, context) {
|
|
647
1043
|
if (entries.length === 0) {
|
|
648
1044
|
return "";
|
|
649
1045
|
}
|
|
650
1046
|
const entriesText = entries.map((e) => `- [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
|
|
651
|
-
const
|
|
1047
|
+
const defaultPrompt = DEFAULT_SUMMARIZE_PROMPT.replace("{{entries}}", entriesText);
|
|
1048
|
+
const prompt = resolvePrompt("summarize", defaultPrompt, context.prompts);
|
|
652
1049
|
const response = await provider.complete(prompt);
|
|
653
1050
|
return response.trim();
|
|
654
1051
|
}
|
|
@@ -693,135 +1090,7 @@ function createProvider(config) {
|
|
|
693
1090
|
// src/output/github-release.ts
|
|
694
1091
|
var import_rest = require("@octokit/rest");
|
|
695
1092
|
var import_core6 = require("@releasekit/core");
|
|
696
|
-
|
|
697
|
-
// src/output/markdown.ts
|
|
698
|
-
var fs2 = __toESM(require("fs"), 1);
|
|
699
|
-
var path = __toESM(require("path"), 1);
|
|
700
|
-
var import_core5 = require("@releasekit/core");
|
|
701
|
-
var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
|
|
702
|
-
var TYPE_LABELS = {
|
|
703
|
-
added: "Added",
|
|
704
|
-
changed: "Changed",
|
|
705
|
-
deprecated: "Deprecated",
|
|
706
|
-
removed: "Removed",
|
|
707
|
-
fixed: "Fixed",
|
|
708
|
-
security: "Security"
|
|
709
|
-
};
|
|
710
|
-
function groupEntriesByType(entries) {
|
|
711
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
712
|
-
for (const type of TYPE_ORDER) {
|
|
713
|
-
grouped.set(type, []);
|
|
714
|
-
}
|
|
715
|
-
for (const entry of entries) {
|
|
716
|
-
const existing = grouped.get(entry.type) ?? [];
|
|
717
|
-
existing.push(entry);
|
|
718
|
-
grouped.set(entry.type, existing);
|
|
719
|
-
}
|
|
720
|
-
return grouped;
|
|
721
|
-
}
|
|
722
|
-
function formatEntry(entry) {
|
|
723
|
-
let line;
|
|
724
|
-
if (entry.breaking && entry.scope) {
|
|
725
|
-
line = `- **BREAKING** **${entry.scope}**: ${entry.description}`;
|
|
726
|
-
} else if (entry.breaking) {
|
|
727
|
-
line = `- **BREAKING** ${entry.description}`;
|
|
728
|
-
} else if (entry.scope) {
|
|
729
|
-
line = `- **${entry.scope}**: ${entry.description}`;
|
|
730
|
-
} else {
|
|
731
|
-
line = `- ${entry.description}`;
|
|
732
|
-
}
|
|
733
|
-
if (entry.issueIds && entry.issueIds.length > 0) {
|
|
734
|
-
line += ` (${entry.issueIds.join(", ")})`;
|
|
735
|
-
}
|
|
736
|
-
return line;
|
|
737
|
-
}
|
|
738
|
-
function formatVersion(context) {
|
|
739
|
-
const lines = [];
|
|
740
|
-
const versionHeader = context.previousVersion ? `## [${context.version}]` : `## ${context.version}`;
|
|
741
|
-
lines.push(`${versionHeader} - ${context.date}`);
|
|
742
|
-
lines.push("");
|
|
743
|
-
if (context.compareUrl) {
|
|
744
|
-
lines.push(`[Full Changelog](${context.compareUrl})`);
|
|
745
|
-
lines.push("");
|
|
746
|
-
}
|
|
747
|
-
if (context.enhanced?.summary) {
|
|
748
|
-
lines.push(context.enhanced.summary);
|
|
749
|
-
lines.push("");
|
|
750
|
-
}
|
|
751
|
-
const grouped = groupEntriesByType(context.entries);
|
|
752
|
-
for (const [type, entries] of grouped) {
|
|
753
|
-
if (entries.length === 0) continue;
|
|
754
|
-
lines.push(`### ${TYPE_LABELS[type]}`);
|
|
755
|
-
for (const entry of entries) {
|
|
756
|
-
lines.push(formatEntry(entry));
|
|
757
|
-
}
|
|
758
|
-
lines.push("");
|
|
759
|
-
}
|
|
760
|
-
return lines.join("\n");
|
|
761
|
-
}
|
|
762
|
-
function formatHeader() {
|
|
763
|
-
return `# Changelog
|
|
764
|
-
|
|
765
|
-
All notable changes to this project will be documented in this file.
|
|
766
|
-
|
|
767
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
768
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
769
|
-
|
|
770
|
-
`;
|
|
771
|
-
}
|
|
772
|
-
function renderMarkdown(contexts) {
|
|
773
|
-
const sections = [formatHeader()];
|
|
774
|
-
for (const context of contexts) {
|
|
775
|
-
sections.push(formatVersion(context));
|
|
776
|
-
}
|
|
777
|
-
return sections.join("\n");
|
|
778
|
-
}
|
|
779
|
-
function prependVersion(existingPath, context) {
|
|
780
|
-
let existing = "";
|
|
781
|
-
if (fs2.existsSync(existingPath)) {
|
|
782
|
-
existing = fs2.readFileSync(existingPath, "utf-8");
|
|
783
|
-
const headerEnd = existing.indexOf("\n## ");
|
|
784
|
-
if (headerEnd >= 0) {
|
|
785
|
-
const header = existing.slice(0, headerEnd);
|
|
786
|
-
const body = existing.slice(headerEnd + 1);
|
|
787
|
-
const newVersion = formatVersion(context);
|
|
788
|
-
return `${header}
|
|
789
|
-
|
|
790
|
-
${newVersion}
|
|
791
|
-
${body}`;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
return renderMarkdown([context]);
|
|
795
|
-
}
|
|
796
|
-
function writeMarkdown(outputPath, contexts, config, dryRun) {
|
|
797
|
-
const content = renderMarkdown(contexts);
|
|
798
|
-
if (dryRun) {
|
|
799
|
-
(0, import_core5.info)("--- Changelog Preview ---");
|
|
800
|
-
console.log(content);
|
|
801
|
-
(0, import_core5.info)("--- End Preview ---");
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
const dir = path.dirname(outputPath);
|
|
805
|
-
if (!fs2.existsSync(dir)) {
|
|
806
|
-
fs2.mkdirSync(dir, { recursive: true });
|
|
807
|
-
}
|
|
808
|
-
if (outputPath === "-") {
|
|
809
|
-
process.stdout.write(content);
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
|
|
813
|
-
const firstContext = contexts[0];
|
|
814
|
-
if (firstContext) {
|
|
815
|
-
const updated = prependVersion(outputPath, firstContext);
|
|
816
|
-
fs2.writeFileSync(outputPath, updated, "utf-8");
|
|
817
|
-
}
|
|
818
|
-
} else {
|
|
819
|
-
fs2.writeFileSync(outputPath, content, "utf-8");
|
|
820
|
-
}
|
|
821
|
-
(0, import_core5.success)(`Changelog written to ${outputPath}`);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// src/output/github-release.ts
|
|
1093
|
+
init_markdown();
|
|
825
1094
|
var GitHubClient = class {
|
|
826
1095
|
octokit;
|
|
827
1096
|
owner;
|
|
@@ -957,9 +1226,10 @@ function renderJson(contexts) {
|
|
|
957
1226
|
function writeJson(outputPath, contexts, dryRun) {
|
|
958
1227
|
const content = renderJson(contexts);
|
|
959
1228
|
if (dryRun) {
|
|
960
|
-
(0, import_core7.info)(
|
|
961
|
-
|
|
962
|
-
(0, import_core7.
|
|
1229
|
+
(0, import_core7.info)(`Would write JSON output to ${outputPath}`);
|
|
1230
|
+
(0, import_core7.debug)("--- JSON Output Preview ---");
|
|
1231
|
+
(0, import_core7.debug)(content);
|
|
1232
|
+
(0, import_core7.debug)("--- End Preview ---");
|
|
963
1233
|
return;
|
|
964
1234
|
}
|
|
965
1235
|
const dir = path2.dirname(outputPath);
|
|
@@ -970,6 +1240,9 @@ function writeJson(outputPath, contexts, dryRun) {
|
|
|
970
1240
|
(0, import_core7.success)(`JSON output written to ${outputPath}`);
|
|
971
1241
|
}
|
|
972
1242
|
|
|
1243
|
+
// src/core/pipeline.ts
|
|
1244
|
+
init_markdown();
|
|
1245
|
+
|
|
973
1246
|
// src/templates/ejs.ts
|
|
974
1247
|
var fs4 = __toESM(require("fs"), 1);
|
|
975
1248
|
var import_ejs = __toESM(require("ejs"), 1);
|
|
@@ -1226,17 +1499,27 @@ function renderTemplate(templatePath, context, engine) {
|
|
|
1226
1499
|
|
|
1227
1500
|
// src/core/pipeline.ts
|
|
1228
1501
|
var import_meta = {};
|
|
1229
|
-
function generateCompareUrl(repoUrl, from, to) {
|
|
1502
|
+
function generateCompareUrl(repoUrl, from, to, packageName) {
|
|
1503
|
+
const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
|
|
1504
|
+
let fromVersion;
|
|
1505
|
+
let toVersion;
|
|
1506
|
+
if (isPackageSpecific) {
|
|
1507
|
+
fromVersion = from;
|
|
1508
|
+
toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
|
|
1509
|
+
} else {
|
|
1510
|
+
fromVersion = from.replace(/^v/, "");
|
|
1511
|
+
toVersion = to.replace(/^v/, "");
|
|
1512
|
+
}
|
|
1230
1513
|
if (/gitlab\.com/i.test(repoUrl)) {
|
|
1231
|
-
return `${repoUrl}/-/compare/${
|
|
1514
|
+
return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
|
|
1232
1515
|
}
|
|
1233
1516
|
if (/bitbucket\.org/i.test(repoUrl)) {
|
|
1234
|
-
return `${repoUrl}/branches/compare/${
|
|
1517
|
+
return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
|
|
1235
1518
|
}
|
|
1236
|
-
return `${repoUrl}/compare/${
|
|
1519
|
+
return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
|
|
1237
1520
|
}
|
|
1238
1521
|
function createTemplateContext(pkg) {
|
|
1239
|
-
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
|
|
1522
|
+
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
|
|
1240
1523
|
return {
|
|
1241
1524
|
packageName: pkg.packageName,
|
|
1242
1525
|
version: pkg.version,
|
|
@@ -1274,15 +1557,17 @@ async function processWithLLM(context, config) {
|
|
|
1274
1557
|
previousVersion: context.previousVersion ?? void 0,
|
|
1275
1558
|
date: context.date,
|
|
1276
1559
|
categories: config.llm.categories,
|
|
1277
|
-
style: config.llm.style
|
|
1560
|
+
style: config.llm.style,
|
|
1561
|
+
scopes: config.llm.scopes,
|
|
1562
|
+
prompts: config.llm.prompts
|
|
1278
1563
|
};
|
|
1279
1564
|
const enhanced = {
|
|
1280
1565
|
entries: context.entries
|
|
1281
1566
|
};
|
|
1282
1567
|
try {
|
|
1283
|
-
(0,
|
|
1568
|
+
(0, import_core9.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
|
|
1284
1569
|
if (config.llm.baseURL) {
|
|
1285
|
-
(0,
|
|
1570
|
+
(0, import_core9.info)(`LLM base URL: ${config.llm.baseURL}`);
|
|
1286
1571
|
}
|
|
1287
1572
|
const rawProvider = createProvider(config.llm);
|
|
1288
1573
|
const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
|
|
@@ -1291,59 +1576,58 @@ async function processWithLLM(context, config) {
|
|
|
1291
1576
|
complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
|
|
1292
1577
|
};
|
|
1293
1578
|
const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
|
|
1294
|
-
(0,
|
|
1579
|
+
(0, import_core9.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
|
|
1295
1580
|
if (tasks.enhance && tasks.categorize) {
|
|
1296
|
-
(0,
|
|
1581
|
+
(0, import_core9.info)("Enhancing and categorizing entries with LLM...");
|
|
1297
1582
|
const result = await enhanceAndCategorize(provider, context.entries, llmContext);
|
|
1298
1583
|
enhanced.entries = result.enhancedEntries;
|
|
1299
1584
|
enhanced.categories = {};
|
|
1300
1585
|
for (const cat of result.categories) {
|
|
1301
1586
|
enhanced.categories[cat.category] = cat.entries;
|
|
1302
1587
|
}
|
|
1303
|
-
(0,
|
|
1588
|
+
(0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
|
|
1304
1589
|
} else {
|
|
1305
1590
|
if (tasks.enhance) {
|
|
1306
|
-
(0,
|
|
1591
|
+
(0, import_core9.info)("Enhancing entries with LLM...");
|
|
1307
1592
|
enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
|
|
1308
|
-
(0,
|
|
1593
|
+
(0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries`);
|
|
1309
1594
|
}
|
|
1310
1595
|
if (tasks.categorize) {
|
|
1311
|
-
(0,
|
|
1596
|
+
(0, import_core9.info)("Categorizing entries with LLM...");
|
|
1312
1597
|
const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
|
|
1313
1598
|
enhanced.categories = {};
|
|
1314
1599
|
for (const cat of categorized) {
|
|
1315
1600
|
enhanced.categories[cat.category] = cat.entries;
|
|
1316
1601
|
}
|
|
1317
|
-
(0,
|
|
1602
|
+
(0, import_core9.info)(`Created ${categorized.length} categories`);
|
|
1318
1603
|
}
|
|
1319
1604
|
}
|
|
1320
1605
|
if (tasks.summarize) {
|
|
1321
|
-
(0,
|
|
1606
|
+
(0, import_core9.info)("Summarizing entries with LLM...");
|
|
1322
1607
|
enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
|
|
1323
1608
|
if (enhanced.summary) {
|
|
1324
|
-
(0,
|
|
1325
|
-
(0,
|
|
1609
|
+
(0, import_core9.info)("Summary generated successfully");
|
|
1610
|
+
(0, import_core9.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
|
|
1326
1611
|
} else {
|
|
1327
|
-
(0,
|
|
1612
|
+
(0, import_core9.warn)("Summary generation returned empty result");
|
|
1328
1613
|
}
|
|
1329
1614
|
}
|
|
1330
1615
|
if (tasks.releaseNotes) {
|
|
1331
|
-
(0,
|
|
1616
|
+
(0, import_core9.info)("Generating release notes with LLM...");
|
|
1332
1617
|
enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
|
|
1333
1618
|
if (enhanced.releaseNotes) {
|
|
1334
|
-
(0,
|
|
1619
|
+
(0, import_core9.info)("Release notes generated successfully");
|
|
1335
1620
|
} else {
|
|
1336
|
-
(0,
|
|
1621
|
+
(0, import_core9.warn)("Release notes generation returned empty result");
|
|
1337
1622
|
}
|
|
1338
1623
|
}
|
|
1339
1624
|
return {
|
|
1340
1625
|
...context,
|
|
1341
|
-
entries: enhanced.entries,
|
|
1342
1626
|
enhanced
|
|
1343
1627
|
};
|
|
1344
1628
|
} catch (error2) {
|
|
1345
|
-
(0,
|
|
1346
|
-
(0,
|
|
1629
|
+
(0, import_core9.warn)(`LLM processing failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1630
|
+
(0, import_core9.warn)("Falling back to raw entries");
|
|
1347
1631
|
return context;
|
|
1348
1632
|
}
|
|
1349
1633
|
}
|
|
@@ -1351,17 +1635,17 @@ function getBuiltinTemplatePath(style) {
|
|
|
1351
1635
|
let packageRoot;
|
|
1352
1636
|
try {
|
|
1353
1637
|
const currentUrl = import_meta.url;
|
|
1354
|
-
packageRoot =
|
|
1355
|
-
packageRoot =
|
|
1638
|
+
packageRoot = path7.dirname(new URL(currentUrl).pathname);
|
|
1639
|
+
packageRoot = path7.join(packageRoot, "..", "..");
|
|
1356
1640
|
} catch {
|
|
1357
1641
|
packageRoot = __dirname;
|
|
1358
1642
|
}
|
|
1359
|
-
return
|
|
1643
|
+
return path7.join(packageRoot, "templates", style);
|
|
1360
1644
|
}
|
|
1361
1645
|
async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
1362
1646
|
let templatePath;
|
|
1363
1647
|
if (config.templates?.path) {
|
|
1364
|
-
templatePath =
|
|
1648
|
+
templatePath = path7.resolve(config.templates.path);
|
|
1365
1649
|
} else {
|
|
1366
1650
|
templatePath = getBuiltinTemplatePath("keep-a-changelog");
|
|
1367
1651
|
}
|
|
@@ -1371,64 +1655,78 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1371
1655
|
);
|
|
1372
1656
|
const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
|
|
1373
1657
|
if (dryRun) {
|
|
1374
|
-
(0,
|
|
1375
|
-
|
|
1376
|
-
(0,
|
|
1658
|
+
(0, import_core9.info)(`Would write templated output to ${outputPath}`);
|
|
1659
|
+
(0, import_core9.debug)("--- Changelog Preview ---");
|
|
1660
|
+
(0, import_core9.debug)(result.content);
|
|
1661
|
+
(0, import_core9.debug)("--- End Preview ---");
|
|
1377
1662
|
return;
|
|
1378
1663
|
}
|
|
1379
1664
|
if (outputPath === "-") {
|
|
1380
1665
|
process.stdout.write(result.content);
|
|
1381
1666
|
return;
|
|
1382
1667
|
}
|
|
1383
|
-
const dir =
|
|
1384
|
-
if (!
|
|
1385
|
-
|
|
1668
|
+
const dir = path7.dirname(outputPath);
|
|
1669
|
+
if (!fs9.existsSync(dir)) {
|
|
1670
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1386
1671
|
}
|
|
1387
|
-
|
|
1388
|
-
(0,
|
|
1672
|
+
fs9.writeFileSync(outputPath, result.content, "utf-8");
|
|
1673
|
+
(0, import_core9.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
|
|
1389
1674
|
}
|
|
1390
1675
|
async function runPipeline(input, config, dryRun) {
|
|
1391
|
-
(0,
|
|
1676
|
+
(0, import_core9.debug)(`Processing ${input.packages.length} package(s)`);
|
|
1392
1677
|
let contexts = input.packages.map(createTemplateContext);
|
|
1393
1678
|
if (config.llm && !process.env.CHANGELOG_NO_LLM) {
|
|
1394
|
-
(0,
|
|
1679
|
+
(0, import_core9.info)("Processing with LLM enhancement");
|
|
1395
1680
|
contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
|
|
1396
1681
|
}
|
|
1682
|
+
const files = [];
|
|
1397
1683
|
for (const output of config.output) {
|
|
1398
|
-
(0,
|
|
1684
|
+
(0, import_core9.info)(`Generating ${output.format} output`);
|
|
1399
1685
|
switch (output.format) {
|
|
1400
1686
|
case "markdown": {
|
|
1401
1687
|
const file = output.file ?? "CHANGELOG.md";
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1688
|
+
try {
|
|
1689
|
+
const effectiveTemplateConfig = output.templates ?? config.templates;
|
|
1690
|
+
if (effectiveTemplateConfig?.path || output.options?.template) {
|
|
1691
|
+
const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
|
|
1692
|
+
await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
|
|
1693
|
+
} else {
|
|
1694
|
+
writeMarkdown(file, contexts, config, dryRun);
|
|
1695
|
+
}
|
|
1696
|
+
if (!dryRun) files.push(file);
|
|
1697
|
+
} catch (error2) {
|
|
1698
|
+
(0, import_core9.warn)(`Failed to write ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1406
1699
|
}
|
|
1407
1700
|
break;
|
|
1408
1701
|
}
|
|
1409
1702
|
case "json": {
|
|
1410
1703
|
const file = output.file ?? "changelog.json";
|
|
1411
|
-
|
|
1704
|
+
try {
|
|
1705
|
+
writeJson(file, contexts, dryRun);
|
|
1706
|
+
if (!dryRun) files.push(file);
|
|
1707
|
+
} catch (error2) {
|
|
1708
|
+
(0, import_core9.warn)(`Failed to write ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1709
|
+
}
|
|
1412
1710
|
break;
|
|
1413
1711
|
}
|
|
1414
1712
|
case "github-release": {
|
|
1415
1713
|
if (dryRun) {
|
|
1416
|
-
(0,
|
|
1714
|
+
(0, import_core9.info)("[DRY RUN] Would create GitHub release");
|
|
1417
1715
|
break;
|
|
1418
1716
|
}
|
|
1419
1717
|
const firstContext = contexts[0];
|
|
1420
1718
|
if (!firstContext) {
|
|
1421
|
-
(0,
|
|
1719
|
+
(0, import_core9.warn)("No context available for GitHub release");
|
|
1422
1720
|
break;
|
|
1423
1721
|
}
|
|
1424
1722
|
const repoUrl = firstContext.repoUrl;
|
|
1425
1723
|
if (!repoUrl) {
|
|
1426
|
-
(0,
|
|
1724
|
+
(0, import_core9.warn)("No repo URL available, cannot create GitHub release");
|
|
1427
1725
|
break;
|
|
1428
1726
|
}
|
|
1429
1727
|
const parsed = parseRepoUrl(repoUrl);
|
|
1430
1728
|
if (!parsed) {
|
|
1431
|
-
(0,
|
|
1729
|
+
(0, import_core9.warn)(`Could not parse repo URL: ${repoUrl}`);
|
|
1432
1730
|
break;
|
|
1433
1731
|
}
|
|
1434
1732
|
await createGitHubRelease(firstContext, {
|
|
@@ -1441,135 +1739,29 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1441
1739
|
}
|
|
1442
1740
|
}
|
|
1443
1741
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
// src/monorepo/aggregator.ts
|
|
1461
|
-
function writeFile(outputPath, content, dryRun) {
|
|
1462
|
-
if (dryRun) {
|
|
1463
|
-
(0, import_core9.info)(`[DRY RUN] Would write to ${outputPath}`);
|
|
1464
|
-
console.log(content);
|
|
1465
|
-
return;
|
|
1466
|
-
}
|
|
1467
|
-
const dir = path7.dirname(outputPath);
|
|
1468
|
-
if (!fs9.existsSync(dir)) {
|
|
1469
|
-
fs9.mkdirSync(dir, { recursive: true });
|
|
1470
|
-
}
|
|
1471
|
-
fs9.writeFileSync(outputPath, content, "utf-8");
|
|
1472
|
-
(0, import_core9.success)(`Changelog written to ${outputPath}`);
|
|
1473
|
-
}
|
|
1474
|
-
function aggregateToRoot(contexts) {
|
|
1475
|
-
const aggregated = {
|
|
1476
|
-
packageName: "monorepo",
|
|
1477
|
-
version: contexts[0]?.version ?? "0.0.0",
|
|
1478
|
-
previousVersion: contexts[0]?.previousVersion ?? null,
|
|
1479
|
-
date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "",
|
|
1480
|
-
repoUrl: contexts[0]?.repoUrl ?? null,
|
|
1481
|
-
entries: []
|
|
1482
|
-
};
|
|
1483
|
-
for (const ctx of contexts) {
|
|
1484
|
-
for (const entry of ctx.entries) {
|
|
1485
|
-
aggregated.entries.push({
|
|
1486
|
-
...entry,
|
|
1487
|
-
scope: entry.scope ? `${ctx.packageName}/${entry.scope}` : ctx.packageName
|
|
1488
|
-
});
|
|
1742
|
+
if (config.monorepo?.mode) {
|
|
1743
|
+
const { detectMonorepo: detectMonorepo2, writeMonorepoChangelogs: writeMonorepoChangelogs2 } = await Promise.resolve().then(() => (init_aggregator(), aggregator_exports));
|
|
1744
|
+
const cwd = process.cwd();
|
|
1745
|
+
const detected = detectMonorepo2(cwd);
|
|
1746
|
+
if (detected.isMonorepo) {
|
|
1747
|
+
const monoFiles = writeMonorepoChangelogs2(
|
|
1748
|
+
contexts,
|
|
1749
|
+
{
|
|
1750
|
+
rootPath: config.monorepo.rootPath ?? cwd,
|
|
1751
|
+
packagesPath: config.monorepo.packagesPath ?? detected.packagesPath,
|
|
1752
|
+
mode: config.monorepo.mode
|
|
1753
|
+
},
|
|
1754
|
+
config,
|
|
1755
|
+
dryRun
|
|
1756
|
+
);
|
|
1757
|
+
files.push(...monoFiles);
|
|
1489
1758
|
}
|
|
1490
1759
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
if (options.mode === "root" || options.mode === "both") {
|
|
1495
|
-
const aggregated = aggregateToRoot(contexts);
|
|
1496
|
-
const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
|
|
1497
|
-
(0, import_core9.info)(`Writing root changelog to ${rootPath}`);
|
|
1498
|
-
const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
|
|
1499
|
-
writeFile(rootPath, rootContent, dryRun);
|
|
1500
|
-
}
|
|
1501
|
-
if (options.mode === "packages" || options.mode === "both") {
|
|
1502
|
-
const byPackage = splitByPackage(contexts);
|
|
1503
|
-
const packageDirMap = buildPackageDirMap(options.rootPath, options.packagesPath);
|
|
1504
|
-
for (const [packageName, ctx] of byPackage) {
|
|
1505
|
-
const simpleName = packageName.split("/").pop();
|
|
1506
|
-
const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
|
|
1507
|
-
if (packageDir) {
|
|
1508
|
-
const changelogPath = path7.join(packageDir, "CHANGELOG.md");
|
|
1509
|
-
(0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
|
|
1510
|
-
const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
|
|
1511
|
-
writeFile(changelogPath, pkgContent, dryRun);
|
|
1512
|
-
} else {
|
|
1513
|
-
(0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
function buildPackageDirMap(rootPath, packagesPath) {
|
|
1519
|
-
const map = /* @__PURE__ */ new Map();
|
|
1520
|
-
const packagesDir = path7.join(rootPath, packagesPath);
|
|
1521
|
-
if (!fs9.existsSync(packagesDir)) {
|
|
1522
|
-
return map;
|
|
1523
|
-
}
|
|
1524
|
-
for (const entry of fs9.readdirSync(packagesDir, { withFileTypes: true })) {
|
|
1525
|
-
if (!entry.isDirectory()) continue;
|
|
1526
|
-
const dirPath = path7.join(packagesDir, entry.name);
|
|
1527
|
-
map.set(entry.name, dirPath);
|
|
1528
|
-
const packageJsonPath = path7.join(dirPath, "package.json");
|
|
1529
|
-
if (fs9.existsSync(packageJsonPath)) {
|
|
1530
|
-
try {
|
|
1531
|
-
const pkg = JSON.parse(fs9.readFileSync(packageJsonPath, "utf-8"));
|
|
1532
|
-
if (pkg.name) {
|
|
1533
|
-
map.set(pkg.name, dirPath);
|
|
1534
|
-
}
|
|
1535
|
-
} catch {
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
return map;
|
|
1540
|
-
}
|
|
1541
|
-
function detectMonorepo(cwd) {
|
|
1542
|
-
const pnpmWorkspacesPath = path7.join(cwd, "pnpm-workspace.yaml");
|
|
1543
|
-
const packageJsonPath = path7.join(cwd, "package.json");
|
|
1544
|
-
if (fs9.existsSync(pnpmWorkspacesPath)) {
|
|
1545
|
-
const content = fs9.readFileSync(pnpmWorkspacesPath, "utf-8");
|
|
1546
|
-
const packagesMatch = content.match(/packages:\s*\n\s*-\s*['"]([^'"]+)['"]/);
|
|
1547
|
-
if (packagesMatch?.[1]) {
|
|
1548
|
-
const packagesGlob = packagesMatch[1];
|
|
1549
|
-
const packagesPath = packagesGlob.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
|
|
1550
|
-
return { isMonorepo: true, packagesPath: packagesPath || "packages" };
|
|
1551
|
-
}
|
|
1552
|
-
return { isMonorepo: true, packagesPath: "packages" };
|
|
1553
|
-
}
|
|
1554
|
-
if (fs9.existsSync(packageJsonPath)) {
|
|
1555
|
-
try {
|
|
1556
|
-
const content = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
1557
|
-
const pkg = JSON.parse(content);
|
|
1558
|
-
if (pkg.workspaces) {
|
|
1559
|
-
const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages;
|
|
1560
|
-
if (workspaces?.length) {
|
|
1561
|
-
const firstWorkspace = workspaces[0];
|
|
1562
|
-
if (firstWorkspace) {
|
|
1563
|
-
const packagesPath = firstWorkspace.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
|
|
1564
|
-
return { isMonorepo: true, packagesPath: packagesPath || "packages" };
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
} catch {
|
|
1569
|
-
return { isMonorepo: false, packagesPath: "" };
|
|
1570
|
-
}
|
|
1760
|
+
const packageNotes = {};
|
|
1761
|
+
for (const ctx of contexts) {
|
|
1762
|
+
packageNotes[ctx.packageName] = formatVersion(ctx);
|
|
1571
1763
|
}
|
|
1572
|
-
return {
|
|
1764
|
+
return { packageNotes, files };
|
|
1573
1765
|
}
|
|
1574
1766
|
|
|
1575
1767
|
// src/cli.ts
|
|
@@ -1637,29 +1829,10 @@ program.command("generate", { isDefault: true }).description("Generate changelog
|
|
|
1637
1829
|
}
|
|
1638
1830
|
(0, import_core10.info)(`Filtered to package: ${options.target}`);
|
|
1639
1831
|
}
|
|
1640
|
-
if (options.monorepo
|
|
1641
|
-
|
|
1642
|
-
const detected = detectMonorepo(process.cwd());
|
|
1643
|
-
if (!detected.isMonorepo) {
|
|
1644
|
-
(0, import_core10.info)("No monorepo detected, using single package mode");
|
|
1645
|
-
await runPipeline(input, config, options.dryRun ?? false);
|
|
1646
|
-
} else {
|
|
1647
|
-
(0, import_core10.info)(`Monorepo detected with packages at ${detected.packagesPath}`);
|
|
1648
|
-
const contexts = input.packages.map(createTemplateContext);
|
|
1649
|
-
writeMonorepoChangelogs(
|
|
1650
|
-
contexts,
|
|
1651
|
-
{
|
|
1652
|
-
rootPath: config.monorepo?.rootPath ?? process.cwd(),
|
|
1653
|
-
packagesPath: config.monorepo?.packagesPath ?? detected.packagesPath,
|
|
1654
|
-
mode: monorepoMode
|
|
1655
|
-
},
|
|
1656
|
-
config,
|
|
1657
|
-
options.dryRun ?? false
|
|
1658
|
-
);
|
|
1659
|
-
}
|
|
1660
|
-
} else {
|
|
1661
|
-
await runPipeline(input, config, options.dryRun ?? false);
|
|
1832
|
+
if (options.monorepo) {
|
|
1833
|
+
config.monorepo = { ...config.monorepo, mode: options.monorepo };
|
|
1662
1834
|
}
|
|
1835
|
+
await runPipeline(input, config, options.dryRun ?? false);
|
|
1663
1836
|
if (options.dryRun) {
|
|
1664
1837
|
(0, import_core10.info)("Dry run complete - no files were written");
|
|
1665
1838
|
} else {
|