@releasekit/notes 0.2.0 → 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/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 fs8 = __toESM(require("fs"), 1);
47
- var path6 = __toESM(require("path"), 1);
48
- var import_core8 = require("@releasekit/core");
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);
@@ -794,136 +1090,7 @@ function createProvider(config) {
794
1090
  // src/output/github-release.ts
795
1091
  var import_rest = require("@octokit/rest");
796
1092
  var import_core6 = require("@releasekit/core");
797
-
798
- // src/output/markdown.ts
799
- var fs2 = __toESM(require("fs"), 1);
800
- var path = __toESM(require("path"), 1);
801
- var import_core5 = require("@releasekit/core");
802
- var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
803
- var TYPE_LABELS = {
804
- added: "Added",
805
- changed: "Changed",
806
- deprecated: "Deprecated",
807
- removed: "Removed",
808
- fixed: "Fixed",
809
- security: "Security"
810
- };
811
- function groupEntriesByType(entries) {
812
- const grouped = /* @__PURE__ */ new Map();
813
- for (const type of TYPE_ORDER) {
814
- grouped.set(type, []);
815
- }
816
- for (const entry of entries) {
817
- const existing = grouped.get(entry.type) ?? [];
818
- existing.push(entry);
819
- grouped.set(entry.type, existing);
820
- }
821
- return grouped;
822
- }
823
- function formatEntry(entry) {
824
- let line;
825
- if (entry.breaking && entry.scope) {
826
- line = `- **BREAKING** **${entry.scope}**: ${entry.description}`;
827
- } else if (entry.breaking) {
828
- line = `- **BREAKING** ${entry.description}`;
829
- } else if (entry.scope) {
830
- line = `- **${entry.scope}**: ${entry.description}`;
831
- } else {
832
- line = `- ${entry.description}`;
833
- }
834
- if (entry.issueIds && entry.issueIds.length > 0) {
835
- line += ` (${entry.issueIds.join(", ")})`;
836
- }
837
- return line;
838
- }
839
- function formatVersion(context) {
840
- const lines = [];
841
- const versionHeader = context.previousVersion ? `## [${context.version}]` : `## ${context.version}`;
842
- lines.push(`${versionHeader} - ${context.date}`);
843
- lines.push("");
844
- if (context.compareUrl) {
845
- lines.push(`[Full Changelog](${context.compareUrl})`);
846
- lines.push("");
847
- }
848
- if (context.enhanced?.summary) {
849
- lines.push(context.enhanced.summary);
850
- lines.push("");
851
- }
852
- const grouped = groupEntriesByType(context.entries);
853
- for (const [type, entries] of grouped) {
854
- if (entries.length === 0) continue;
855
- lines.push(`### ${TYPE_LABELS[type]}`);
856
- for (const entry of entries) {
857
- lines.push(formatEntry(entry));
858
- }
859
- lines.push("");
860
- }
861
- return lines.join("\n");
862
- }
863
- function formatHeader() {
864
- return `# Changelog
865
-
866
- All notable changes to this project will be documented in this file.
867
-
868
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
869
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
870
-
871
- `;
872
- }
873
- function renderMarkdown(contexts) {
874
- const sections = [formatHeader()];
875
- for (const context of contexts) {
876
- sections.push(formatVersion(context));
877
- }
878
- return sections.join("\n");
879
- }
880
- function prependVersion(existingPath, context) {
881
- let existing = "";
882
- if (fs2.existsSync(existingPath)) {
883
- existing = fs2.readFileSync(existingPath, "utf-8");
884
- const headerEnd = existing.indexOf("\n## ");
885
- if (headerEnd >= 0) {
886
- const header = existing.slice(0, headerEnd);
887
- const body = existing.slice(headerEnd + 1);
888
- const newVersion = formatVersion(context);
889
- return `${header}
890
-
891
- ${newVersion}
892
- ${body}`;
893
- }
894
- }
895
- return renderMarkdown([context]);
896
- }
897
- function writeMarkdown(outputPath, contexts, config, dryRun) {
898
- const content = renderMarkdown(contexts);
899
- if (dryRun) {
900
- (0, import_core5.info)(`Would write changelog to ${outputPath}`);
901
- (0, import_core5.debug)("--- Changelog Preview ---");
902
- (0, import_core5.debug)(content);
903
- (0, import_core5.debug)("--- End Preview ---");
904
- return;
905
- }
906
- const dir = path.dirname(outputPath);
907
- if (!fs2.existsSync(dir)) {
908
- fs2.mkdirSync(dir, { recursive: true });
909
- }
910
- if (outputPath === "-") {
911
- process.stdout.write(content);
912
- return;
913
- }
914
- if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
915
- const firstContext = contexts[0];
916
- if (firstContext) {
917
- const updated = prependVersion(outputPath, firstContext);
918
- fs2.writeFileSync(outputPath, updated, "utf-8");
919
- }
920
- } else {
921
- fs2.writeFileSync(outputPath, content, "utf-8");
922
- }
923
- (0, import_core5.success)(`Changelog written to ${outputPath}`);
924
- }
925
-
926
- // src/output/github-release.ts
1093
+ init_markdown();
927
1094
  var GitHubClient = class {
928
1095
  octokit;
929
1096
  owner;
@@ -1073,6 +1240,9 @@ function writeJson(outputPath, contexts, dryRun) {
1073
1240
  (0, import_core7.success)(`JSON output written to ${outputPath}`);
1074
1241
  }
1075
1242
 
1243
+ // src/core/pipeline.ts
1244
+ init_markdown();
1245
+
1076
1246
  // src/templates/ejs.ts
1077
1247
  var fs4 = __toESM(require("fs"), 1);
1078
1248
  var import_ejs = __toESM(require("ejs"), 1);
@@ -1395,9 +1565,9 @@ async function processWithLLM(context, config) {
1395
1565
  entries: context.entries
1396
1566
  };
1397
1567
  try {
1398
- (0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1568
+ (0, import_core9.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1399
1569
  if (config.llm.baseURL) {
1400
- (0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
1570
+ (0, import_core9.info)(`LLM base URL: ${config.llm.baseURL}`);
1401
1571
  }
1402
1572
  const rawProvider = createProvider(config.llm);
1403
1573
  const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
@@ -1406,49 +1576,49 @@ async function processWithLLM(context, config) {
1406
1576
  complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
1407
1577
  };
1408
1578
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1409
- (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1579
+ (0, import_core9.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1410
1580
  if (tasks.enhance && tasks.categorize) {
1411
- (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1581
+ (0, import_core9.info)("Enhancing and categorizing entries with LLM...");
1412
1582
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1413
1583
  enhanced.entries = result.enhancedEntries;
1414
1584
  enhanced.categories = {};
1415
1585
  for (const cat of result.categories) {
1416
1586
  enhanced.categories[cat.category] = cat.entries;
1417
1587
  }
1418
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1588
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1419
1589
  } else {
1420
1590
  if (tasks.enhance) {
1421
- (0, import_core8.info)("Enhancing entries with LLM...");
1591
+ (0, import_core9.info)("Enhancing entries with LLM...");
1422
1592
  enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1423
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
1593
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries`);
1424
1594
  }
1425
1595
  if (tasks.categorize) {
1426
- (0, import_core8.info)("Categorizing entries with LLM...");
1596
+ (0, import_core9.info)("Categorizing entries with LLM...");
1427
1597
  const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1428
1598
  enhanced.categories = {};
1429
1599
  for (const cat of categorized) {
1430
1600
  enhanced.categories[cat.category] = cat.entries;
1431
1601
  }
1432
- (0, import_core8.info)(`Created ${categorized.length} categories`);
1602
+ (0, import_core9.info)(`Created ${categorized.length} categories`);
1433
1603
  }
1434
1604
  }
1435
1605
  if (tasks.summarize) {
1436
- (0, import_core8.info)("Summarizing entries with LLM...");
1606
+ (0, import_core9.info)("Summarizing entries with LLM...");
1437
1607
  enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
1438
1608
  if (enhanced.summary) {
1439
- (0, import_core8.info)("Summary generated successfully");
1440
- (0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1609
+ (0, import_core9.info)("Summary generated successfully");
1610
+ (0, import_core9.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1441
1611
  } else {
1442
- (0, import_core8.warn)("Summary generation returned empty result");
1612
+ (0, import_core9.warn)("Summary generation returned empty result");
1443
1613
  }
1444
1614
  }
1445
1615
  if (tasks.releaseNotes) {
1446
- (0, import_core8.info)("Generating release notes with LLM...");
1616
+ (0, import_core9.info)("Generating release notes with LLM...");
1447
1617
  enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
1448
1618
  if (enhanced.releaseNotes) {
1449
- (0, import_core8.info)("Release notes generated successfully");
1619
+ (0, import_core9.info)("Release notes generated successfully");
1450
1620
  } else {
1451
- (0, import_core8.warn)("Release notes generation returned empty result");
1621
+ (0, import_core9.warn)("Release notes generation returned empty result");
1452
1622
  }
1453
1623
  }
1454
1624
  return {
@@ -1456,8 +1626,8 @@ async function processWithLLM(context, config) {
1456
1626
  enhanced
1457
1627
  };
1458
1628
  } catch (error2) {
1459
- (0, import_core8.warn)(`LLM processing failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
1460
- (0, import_core8.warn)("Falling back to raw entries");
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");
1461
1631
  return context;
1462
1632
  }
1463
1633
  }
@@ -1465,17 +1635,17 @@ function getBuiltinTemplatePath(style) {
1465
1635
  let packageRoot;
1466
1636
  try {
1467
1637
  const currentUrl = import_meta.url;
1468
- packageRoot = path6.dirname(new URL(currentUrl).pathname);
1469
- packageRoot = path6.join(packageRoot, "..", "..");
1638
+ packageRoot = path7.dirname(new URL(currentUrl).pathname);
1639
+ packageRoot = path7.join(packageRoot, "..", "..");
1470
1640
  } catch {
1471
1641
  packageRoot = __dirname;
1472
1642
  }
1473
- return path6.join(packageRoot, "templates", style);
1643
+ return path7.join(packageRoot, "templates", style);
1474
1644
  }
1475
1645
  async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1476
1646
  let templatePath;
1477
1647
  if (config.templates?.path) {
1478
- templatePath = path6.resolve(config.templates.path);
1648
+ templatePath = path7.resolve(config.templates.path);
1479
1649
  } else {
1480
1650
  templatePath = getBuiltinTemplatePath("keep-a-changelog");
1481
1651
  }
@@ -1485,67 +1655,78 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1485
1655
  );
1486
1656
  const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
1487
1657
  if (dryRun) {
1488
- (0, import_core8.info)(`Would write templated output to ${outputPath}`);
1489
- (0, import_core8.debug)("--- Changelog Preview ---");
1490
- (0, import_core8.debug)(result.content);
1491
- (0, import_core8.debug)("--- End Preview ---");
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 ---");
1492
1662
  return;
1493
1663
  }
1494
1664
  if (outputPath === "-") {
1495
1665
  process.stdout.write(result.content);
1496
1666
  return;
1497
1667
  }
1498
- const dir = path6.dirname(outputPath);
1499
- if (!fs8.existsSync(dir)) {
1500
- fs8.mkdirSync(dir, { recursive: true });
1668
+ const dir = path7.dirname(outputPath);
1669
+ if (!fs9.existsSync(dir)) {
1670
+ fs9.mkdirSync(dir, { recursive: true });
1501
1671
  }
1502
- fs8.writeFileSync(outputPath, result.content, "utf-8");
1503
- (0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1672
+ fs9.writeFileSync(outputPath, result.content, "utf-8");
1673
+ (0, import_core9.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1504
1674
  }
1505
1675
  async function runPipeline(input, config, dryRun) {
1506
- (0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
1676
+ (0, import_core9.debug)(`Processing ${input.packages.length} package(s)`);
1507
1677
  let contexts = input.packages.map(createTemplateContext);
1508
1678
  if (config.llm && !process.env.CHANGELOG_NO_LLM) {
1509
- (0, import_core8.info)("Processing with LLM enhancement");
1679
+ (0, import_core9.info)("Processing with LLM enhancement");
1510
1680
  contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
1511
1681
  }
1682
+ const files = [];
1512
1683
  for (const output of config.output) {
1513
- (0, import_core8.info)(`Generating ${output.format} output`);
1684
+ (0, import_core9.info)(`Generating ${output.format} output`);
1514
1685
  switch (output.format) {
1515
1686
  case "markdown": {
1516
1687
  const file = output.file ?? "CHANGELOG.md";
1517
- const effectiveTemplateConfig = output.templates ?? config.templates;
1518
- if (effectiveTemplateConfig?.path || output.options?.template) {
1519
- const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
1520
- await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
1521
- } else {
1522
- writeMarkdown(file, contexts, config, dryRun);
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)}`);
1523
1699
  }
1524
1700
  break;
1525
1701
  }
1526
1702
  case "json": {
1527
1703
  const file = output.file ?? "changelog.json";
1528
- writeJson(file, contexts, dryRun);
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
+ }
1529
1710
  break;
1530
1711
  }
1531
1712
  case "github-release": {
1532
1713
  if (dryRun) {
1533
- (0, import_core8.info)("[DRY RUN] Would create GitHub release");
1714
+ (0, import_core9.info)("[DRY RUN] Would create GitHub release");
1534
1715
  break;
1535
1716
  }
1536
1717
  const firstContext = contexts[0];
1537
1718
  if (!firstContext) {
1538
- (0, import_core8.warn)("No context available for GitHub release");
1719
+ (0, import_core9.warn)("No context available for GitHub release");
1539
1720
  break;
1540
1721
  }
1541
1722
  const repoUrl = firstContext.repoUrl;
1542
1723
  if (!repoUrl) {
1543
- (0, import_core8.warn)("No repo URL available, cannot create GitHub release");
1724
+ (0, import_core9.warn)("No repo URL available, cannot create GitHub release");
1544
1725
  break;
1545
1726
  }
1546
1727
  const parsed = parseRepoUrl(repoUrl);
1547
1728
  if (!parsed) {
1548
- (0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
1729
+ (0, import_core9.warn)(`Could not parse repo URL: ${repoUrl}`);
1549
1730
  break;
1550
1731
  }
1551
1732
  await createGitHubRelease(firstContext, {
@@ -1558,135 +1739,29 @@ async function runPipeline(input, config, dryRun) {
1558
1739
  }
1559
1740
  }
1560
1741
  }
1561
- }
1562
-
1563
- // src/monorepo/aggregator.ts
1564
- var fs9 = __toESM(require("fs"), 1);
1565
- var path7 = __toESM(require("path"), 1);
1566
- var import_core9 = require("@releasekit/core");
1567
-
1568
- // src/monorepo/splitter.ts
1569
- function splitByPackage(contexts) {
1570
- const byPackage = /* @__PURE__ */ new Map();
1571
- for (const ctx of contexts) {
1572
- byPackage.set(ctx.packageName, ctx);
1573
- }
1574
- return byPackage;
1575
- }
1576
-
1577
- // src/monorepo/aggregator.ts
1578
- function writeFile(outputPath, content, dryRun) {
1579
- if (dryRun) {
1580
- (0, import_core9.info)(`Would write to ${outputPath}`);
1581
- (0, import_core9.debug)(content);
1582
- return;
1583
- }
1584
- const dir = path7.dirname(outputPath);
1585
- if (!fs9.existsSync(dir)) {
1586
- fs9.mkdirSync(dir, { recursive: true });
1587
- }
1588
- fs9.writeFileSync(outputPath, content, "utf-8");
1589
- (0, import_core9.success)(`Changelog written to ${outputPath}`);
1590
- }
1591
- function aggregateToRoot(contexts) {
1592
- const aggregated = {
1593
- packageName: "monorepo",
1594
- version: contexts[0]?.version ?? "0.0.0",
1595
- previousVersion: contexts[0]?.previousVersion ?? null,
1596
- date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "",
1597
- repoUrl: contexts[0]?.repoUrl ?? null,
1598
- entries: []
1599
- };
1600
- for (const ctx of contexts) {
1601
- for (const entry of ctx.entries) {
1602
- aggregated.entries.push({
1603
- ...entry,
1604
- scope: entry.scope ? `${ctx.packageName}/${entry.scope}` : ctx.packageName
1605
- });
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);
1606
1758
  }
1607
1759
  }
1608
- return aggregated;
1609
- }
1610
- function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1611
- if (options.mode === "root" || options.mode === "both") {
1612
- const aggregated = aggregateToRoot(contexts);
1613
- const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
1614
- (0, import_core9.info)(`Writing root changelog to ${rootPath}`);
1615
- const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
1616
- writeFile(rootPath, rootContent, dryRun);
1617
- }
1618
- if (options.mode === "packages" || options.mode === "both") {
1619
- const byPackage = splitByPackage(contexts);
1620
- const packageDirMap = buildPackageDirMap(options.rootPath, options.packagesPath);
1621
- for (const [packageName, ctx] of byPackage) {
1622
- const simpleName = packageName.split("/").pop();
1623
- const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
1624
- if (packageDir) {
1625
- const changelogPath = path7.join(packageDir, "CHANGELOG.md");
1626
- (0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1627
- const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
1628
- writeFile(changelogPath, pkgContent, dryRun);
1629
- } else {
1630
- (0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
1631
- }
1632
- }
1633
- }
1634
- }
1635
- function buildPackageDirMap(rootPath, packagesPath) {
1636
- const map = /* @__PURE__ */ new Map();
1637
- const packagesDir = path7.join(rootPath, packagesPath);
1638
- if (!fs9.existsSync(packagesDir)) {
1639
- return map;
1640
- }
1641
- for (const entry of fs9.readdirSync(packagesDir, { withFileTypes: true })) {
1642
- if (!entry.isDirectory()) continue;
1643
- const dirPath = path7.join(packagesDir, entry.name);
1644
- map.set(entry.name, dirPath);
1645
- const packageJsonPath = path7.join(dirPath, "package.json");
1646
- if (fs9.existsSync(packageJsonPath)) {
1647
- try {
1648
- const pkg = JSON.parse(fs9.readFileSync(packageJsonPath, "utf-8"));
1649
- if (pkg.name) {
1650
- map.set(pkg.name, dirPath);
1651
- }
1652
- } catch {
1653
- }
1654
- }
1655
- }
1656
- return map;
1657
- }
1658
- function detectMonorepo(cwd) {
1659
- const pnpmWorkspacesPath = path7.join(cwd, "pnpm-workspace.yaml");
1660
- const packageJsonPath = path7.join(cwd, "package.json");
1661
- if (fs9.existsSync(pnpmWorkspacesPath)) {
1662
- const content = fs9.readFileSync(pnpmWorkspacesPath, "utf-8");
1663
- const packagesMatch = content.match(/packages:\s*\n\s*-\s*['"]([^'"]+)['"]/);
1664
- if (packagesMatch?.[1]) {
1665
- const packagesGlob = packagesMatch[1];
1666
- const packagesPath = packagesGlob.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
1667
- return { isMonorepo: true, packagesPath: packagesPath || "packages" };
1668
- }
1669
- return { isMonorepo: true, packagesPath: "packages" };
1670
- }
1671
- if (fs9.existsSync(packageJsonPath)) {
1672
- try {
1673
- const content = fs9.readFileSync(packageJsonPath, "utf-8");
1674
- const pkg = JSON.parse(content);
1675
- if (pkg.workspaces) {
1676
- const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages;
1677
- if (workspaces?.length) {
1678
- const firstWorkspace = workspaces[0];
1679
- if (firstWorkspace) {
1680
- const packagesPath = firstWorkspace.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
1681
- return { isMonorepo: true, packagesPath: packagesPath || "packages" };
1682
- }
1683
- }
1684
- }
1685
- } catch {
1686
- return { isMonorepo: false, packagesPath: "" };
1687
- }
1760
+ const packageNotes = {};
1761
+ for (const ctx of contexts) {
1762
+ packageNotes[ctx.packageName] = formatVersion(ctx);
1688
1763
  }
1689
- return { isMonorepo: false, packagesPath: "" };
1764
+ return { packageNotes, files };
1690
1765
  }
1691
1766
 
1692
1767
  // src/cli.ts
@@ -1754,29 +1829,10 @@ program.command("generate", { isDefault: true }).description("Generate changelog
1754
1829
  }
1755
1830
  (0, import_core10.info)(`Filtered to package: ${options.target}`);
1756
1831
  }
1757
- if (options.monorepo || config.monorepo) {
1758
- const monorepoMode = options.monorepo ?? config.monorepo?.mode ?? "both";
1759
- const detected = detectMonorepo(process.cwd());
1760
- if (!detected.isMonorepo) {
1761
- (0, import_core10.info)("No monorepo detected, using single package mode");
1762
- await runPipeline(input, config, options.dryRun ?? false);
1763
- } else {
1764
- (0, import_core10.info)(`Monorepo detected with packages at ${detected.packagesPath}`);
1765
- const contexts = input.packages.map(createTemplateContext);
1766
- writeMonorepoChangelogs(
1767
- contexts,
1768
- {
1769
- rootPath: config.monorepo?.rootPath ?? process.cwd(),
1770
- packagesPath: config.monorepo?.packagesPath ?? detected.packagesPath,
1771
- mode: monorepoMode
1772
- },
1773
- config,
1774
- options.dryRun ?? false
1775
- );
1776
- }
1777
- } else {
1778
- await runPipeline(input, config, options.dryRun ?? false);
1832
+ if (options.monorepo) {
1833
+ config.monorepo = { ...config.monorepo, mode: options.monorepo };
1779
1834
  }
1835
+ await runPipeline(input, config, options.dryRun ?? false);
1780
1836
  if (options.dryRun) {
1781
1837
  (0, import_core10.info)("Dry run complete - no files were written");
1782
1838
  } else {