@releasekit/notes 0.2.0 → 0.3.0-next.1

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);
@@ -255,7 +551,7 @@ var OllamaProvider = class extends BaseLLMProvider {
255
551
  "Content-Type": "application/json"
256
552
  };
257
553
  if (this.apiKey) {
258
- headers["Authorization"] = `Bearer ${this.apiKey}`;
554
+ headers.Authorization = `Bearer ${this.apiKey}`;
259
555
  }
260
556
  const baseUrl = this.baseURL.endsWith("/api") ? this.baseURL.slice(0, -4) : this.baseURL;
261
557
  const response = await fetch(`${baseUrl}/api/chat`, {
@@ -416,7 +712,6 @@ function validateScope(scope, allowedScopes, rules) {
416
712
  return scope;
417
713
  case "fallback":
418
714
  return rules?.fallbackScope;
419
- case "remove":
420
715
  default:
421
716
  return void 0;
422
717
  }
@@ -794,136 +1089,7 @@ function createProvider(config) {
794
1089
  // src/output/github-release.ts
795
1090
  var import_rest = require("@octokit/rest");
796
1091
  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
1092
+ init_markdown();
927
1093
  var GitHubClient = class {
928
1094
  octokit;
929
1095
  owner;
@@ -1073,6 +1239,9 @@ function writeJson(outputPath, contexts, dryRun) {
1073
1239
  (0, import_core7.success)(`JSON output written to ${outputPath}`);
1074
1240
  }
1075
1241
 
1242
+ // src/core/pipeline.ts
1243
+ init_markdown();
1244
+
1076
1245
  // src/templates/ejs.ts
1077
1246
  var fs4 = __toESM(require("fs"), 1);
1078
1247
  var import_ejs = __toESM(require("ejs"), 1);
@@ -1395,9 +1564,9 @@ async function processWithLLM(context, config) {
1395
1564
  entries: context.entries
1396
1565
  };
1397
1566
  try {
1398
- (0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1567
+ (0, import_core9.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1399
1568
  if (config.llm.baseURL) {
1400
- (0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
1569
+ (0, import_core9.info)(`LLM base URL: ${config.llm.baseURL}`);
1401
1570
  }
1402
1571
  const rawProvider = createProvider(config.llm);
1403
1572
  const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
@@ -1406,49 +1575,49 @@ async function processWithLLM(context, config) {
1406
1575
  complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
1407
1576
  };
1408
1577
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1409
- (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1578
+ (0, import_core9.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1410
1579
  if (tasks.enhance && tasks.categorize) {
1411
- (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1580
+ (0, import_core9.info)("Enhancing and categorizing entries with LLM...");
1412
1581
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1413
1582
  enhanced.entries = result.enhancedEntries;
1414
1583
  enhanced.categories = {};
1415
1584
  for (const cat of result.categories) {
1416
1585
  enhanced.categories[cat.category] = cat.entries;
1417
1586
  }
1418
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1587
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1419
1588
  } else {
1420
1589
  if (tasks.enhance) {
1421
- (0, import_core8.info)("Enhancing entries with LLM...");
1590
+ (0, import_core9.info)("Enhancing entries with LLM...");
1422
1591
  enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1423
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
1592
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries`);
1424
1593
  }
1425
1594
  if (tasks.categorize) {
1426
- (0, import_core8.info)("Categorizing entries with LLM...");
1595
+ (0, import_core9.info)("Categorizing entries with LLM...");
1427
1596
  const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1428
1597
  enhanced.categories = {};
1429
1598
  for (const cat of categorized) {
1430
1599
  enhanced.categories[cat.category] = cat.entries;
1431
1600
  }
1432
- (0, import_core8.info)(`Created ${categorized.length} categories`);
1601
+ (0, import_core9.info)(`Created ${categorized.length} categories`);
1433
1602
  }
1434
1603
  }
1435
1604
  if (tasks.summarize) {
1436
- (0, import_core8.info)("Summarizing entries with LLM...");
1605
+ (0, import_core9.info)("Summarizing entries with LLM...");
1437
1606
  enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
1438
1607
  if (enhanced.summary) {
1439
- (0, import_core8.info)("Summary generated successfully");
1440
- (0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1608
+ (0, import_core9.info)("Summary generated successfully");
1609
+ (0, import_core9.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1441
1610
  } else {
1442
- (0, import_core8.warn)("Summary generation returned empty result");
1611
+ (0, import_core9.warn)("Summary generation returned empty result");
1443
1612
  }
1444
1613
  }
1445
1614
  if (tasks.releaseNotes) {
1446
- (0, import_core8.info)("Generating release notes with LLM...");
1615
+ (0, import_core9.info)("Generating release notes with LLM...");
1447
1616
  enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
1448
1617
  if (enhanced.releaseNotes) {
1449
- (0, import_core8.info)("Release notes generated successfully");
1618
+ (0, import_core9.info)("Release notes generated successfully");
1450
1619
  } else {
1451
- (0, import_core8.warn)("Release notes generation returned empty result");
1620
+ (0, import_core9.warn)("Release notes generation returned empty result");
1452
1621
  }
1453
1622
  }
1454
1623
  return {
@@ -1456,8 +1625,8 @@ async function processWithLLM(context, config) {
1456
1625
  enhanced
1457
1626
  };
1458
1627
  } 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");
1628
+ (0, import_core9.warn)(`LLM processing failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
1629
+ (0, import_core9.warn)("Falling back to raw entries");
1461
1630
  return context;
1462
1631
  }
1463
1632
  }
@@ -1465,17 +1634,17 @@ function getBuiltinTemplatePath(style) {
1465
1634
  let packageRoot;
1466
1635
  try {
1467
1636
  const currentUrl = import_meta.url;
1468
- packageRoot = path6.dirname(new URL(currentUrl).pathname);
1469
- packageRoot = path6.join(packageRoot, "..", "..");
1637
+ packageRoot = path7.dirname(new URL(currentUrl).pathname);
1638
+ packageRoot = path7.join(packageRoot, "..", "..");
1470
1639
  } catch {
1471
1640
  packageRoot = __dirname;
1472
1641
  }
1473
- return path6.join(packageRoot, "templates", style);
1642
+ return path7.join(packageRoot, "templates", style);
1474
1643
  }
1475
1644
  async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1476
1645
  let templatePath;
1477
1646
  if (config.templates?.path) {
1478
- templatePath = path6.resolve(config.templates.path);
1647
+ templatePath = path7.resolve(config.templates.path);
1479
1648
  } else {
1480
1649
  templatePath = getBuiltinTemplatePath("keep-a-changelog");
1481
1650
  }
@@ -1485,67 +1654,78 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1485
1654
  );
1486
1655
  const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
1487
1656
  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 ---");
1657
+ (0, import_core9.info)(`Would write templated output to ${outputPath}`);
1658
+ (0, import_core9.debug)("--- Changelog Preview ---");
1659
+ (0, import_core9.debug)(result.content);
1660
+ (0, import_core9.debug)("--- End Preview ---");
1492
1661
  return;
1493
1662
  }
1494
1663
  if (outputPath === "-") {
1495
1664
  process.stdout.write(result.content);
1496
1665
  return;
1497
1666
  }
1498
- const dir = path6.dirname(outputPath);
1499
- if (!fs8.existsSync(dir)) {
1500
- fs8.mkdirSync(dir, { recursive: true });
1667
+ const dir = path7.dirname(outputPath);
1668
+ if (!fs9.existsSync(dir)) {
1669
+ fs9.mkdirSync(dir, { recursive: true });
1501
1670
  }
1502
- fs8.writeFileSync(outputPath, result.content, "utf-8");
1503
- (0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1671
+ fs9.writeFileSync(outputPath, result.content, "utf-8");
1672
+ (0, import_core9.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1504
1673
  }
1505
1674
  async function runPipeline(input, config, dryRun) {
1506
- (0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
1675
+ (0, import_core9.debug)(`Processing ${input.packages.length} package(s)`);
1507
1676
  let contexts = input.packages.map(createTemplateContext);
1508
1677
  if (config.llm && !process.env.CHANGELOG_NO_LLM) {
1509
- (0, import_core8.info)("Processing with LLM enhancement");
1678
+ (0, import_core9.info)("Processing with LLM enhancement");
1510
1679
  contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
1511
1680
  }
1681
+ const files = [];
1512
1682
  for (const output of config.output) {
1513
- (0, import_core8.info)(`Generating ${output.format} output`);
1683
+ (0, import_core9.info)(`Generating ${output.format} output`);
1514
1684
  switch (output.format) {
1515
1685
  case "markdown": {
1516
1686
  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);
1687
+ try {
1688
+ const effectiveTemplateConfig = output.templates ?? config.templates;
1689
+ if (effectiveTemplateConfig?.path || output.options?.template) {
1690
+ const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
1691
+ await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
1692
+ } else {
1693
+ writeMarkdown(file, contexts, config, dryRun);
1694
+ }
1695
+ if (!dryRun) files.push(file);
1696
+ } catch (error2) {
1697
+ (0, import_core9.warn)(`Failed to write ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
1523
1698
  }
1524
1699
  break;
1525
1700
  }
1526
1701
  case "json": {
1527
1702
  const file = output.file ?? "changelog.json";
1528
- writeJson(file, contexts, dryRun);
1703
+ try {
1704
+ writeJson(file, contexts, dryRun);
1705
+ if (!dryRun) files.push(file);
1706
+ } catch (error2) {
1707
+ (0, import_core9.warn)(`Failed to write ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`);
1708
+ }
1529
1709
  break;
1530
1710
  }
1531
1711
  case "github-release": {
1532
1712
  if (dryRun) {
1533
- (0, import_core8.info)("[DRY RUN] Would create GitHub release");
1713
+ (0, import_core9.info)("[DRY RUN] Would create GitHub release");
1534
1714
  break;
1535
1715
  }
1536
1716
  const firstContext = contexts[0];
1537
1717
  if (!firstContext) {
1538
- (0, import_core8.warn)("No context available for GitHub release");
1718
+ (0, import_core9.warn)("No context available for GitHub release");
1539
1719
  break;
1540
1720
  }
1541
1721
  const repoUrl = firstContext.repoUrl;
1542
1722
  if (!repoUrl) {
1543
- (0, import_core8.warn)("No repo URL available, cannot create GitHub release");
1723
+ (0, import_core9.warn)("No repo URL available, cannot create GitHub release");
1544
1724
  break;
1545
1725
  }
1546
1726
  const parsed = parseRepoUrl(repoUrl);
1547
1727
  if (!parsed) {
1548
- (0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
1728
+ (0, import_core9.warn)(`Could not parse repo URL: ${repoUrl}`);
1549
1729
  break;
1550
1730
  }
1551
1731
  await createGitHubRelease(firstContext, {
@@ -1558,135 +1738,29 @@ async function runPipeline(input, config, dryRun) {
1558
1738
  }
1559
1739
  }
1560
1740
  }
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
- });
1741
+ if (config.monorepo?.mode) {
1742
+ const { detectMonorepo: detectMonorepo2, writeMonorepoChangelogs: writeMonorepoChangelogs2 } = await Promise.resolve().then(() => (init_aggregator(), aggregator_exports));
1743
+ const cwd = process.cwd();
1744
+ const detected = detectMonorepo2(cwd);
1745
+ if (detected.isMonorepo) {
1746
+ const monoFiles = writeMonorepoChangelogs2(
1747
+ contexts,
1748
+ {
1749
+ rootPath: config.monorepo.rootPath ?? cwd,
1750
+ packagesPath: config.monorepo.packagesPath ?? detected.packagesPath,
1751
+ mode: config.monorepo.mode
1752
+ },
1753
+ config,
1754
+ dryRun
1755
+ );
1756
+ files.push(...monoFiles);
1606
1757
  }
1607
1758
  }
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
- }
1759
+ const packageNotes = {};
1760
+ for (const ctx of contexts) {
1761
+ packageNotes[ctx.packageName] = formatVersion(ctx);
1688
1762
  }
1689
- return { isMonorepo: false, packagesPath: "" };
1763
+ return { packageNotes, files };
1690
1764
  }
1691
1765
 
1692
1766
  // src/cli.ts
@@ -1754,29 +1828,10 @@ program.command("generate", { isDefault: true }).description("Generate changelog
1754
1828
  }
1755
1829
  (0, import_core10.info)(`Filtered to package: ${options.target}`);
1756
1830
  }
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);
1831
+ if (options.monorepo) {
1832
+ config.monorepo = { ...config.monorepo, mode: options.monorepo };
1779
1833
  }
1834
+ await runPipeline(input, config, options.dryRun ?? false);
1780
1835
  if (options.dryRun) {
1781
1836
  (0, import_core10.info)("Dry run complete - no files were written");
1782
1837
  } else {