@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/index.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,295 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
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
+
30
322
  // src/index.ts
31
323
  var index_exports = {};
32
324
  __export(index_exports, {
@@ -41,6 +333,7 @@ __export(index_exports, {
41
333
  aggregateToRoot: () => aggregateToRoot,
42
334
  createTemplateContext: () => createTemplateContext,
43
335
  detectMonorepo: () => detectMonorepo,
336
+ formatVersion: () => formatVersion,
44
337
  getDefaultConfig: () => getDefaultConfig,
45
338
  getExitCode: () => getExitCode,
46
339
  loadAuth: () => import_config.loadAuth,
@@ -73,9 +366,9 @@ function getDefaultConfig() {
73
366
  }
74
367
 
75
368
  // src/core/pipeline.ts
76
- var fs8 = __toESM(require("fs"), 1);
77
- var path6 = __toESM(require("path"), 1);
78
- var import_core8 = require("@releasekit/core");
369
+ var fs9 = __toESM(require("fs"), 1);
370
+ var path7 = __toESM(require("path"), 1);
371
+ var import_core9 = require("@releasekit/core");
79
372
 
80
373
  // src/input/package-versioner.ts
81
374
  var fs = __toESM(require("fs"), 1);
@@ -305,7 +598,7 @@ var OllamaProvider = class extends BaseLLMProvider {
305
598
  "Content-Type": "application/json"
306
599
  };
307
600
  if (this.apiKey) {
308
- headers["Authorization"] = `Bearer ${this.apiKey}`;
601
+ headers.Authorization = `Bearer ${this.apiKey}`;
309
602
  }
310
603
  const baseUrl = this.baseURL.endsWith("/api") ? this.baseURL.slice(0, -4) : this.baseURL;
311
604
  const response = await fetch(`${baseUrl}/api/chat`, {
@@ -466,7 +759,6 @@ function validateScope(scope, allowedScopes, rules) {
466
759
  return scope;
467
760
  case "fallback":
468
761
  return rules?.fallbackScope;
469
- case "remove":
470
762
  default:
471
763
  return void 0;
472
764
  }
@@ -844,136 +1136,7 @@ function createProvider(config) {
844
1136
  // src/output/github-release.ts
845
1137
  var import_rest = require("@octokit/rest");
846
1138
  var import_core6 = require("@releasekit/core");
847
-
848
- // src/output/markdown.ts
849
- var fs2 = __toESM(require("fs"), 1);
850
- var path = __toESM(require("path"), 1);
851
- var import_core5 = require("@releasekit/core");
852
- var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
853
- var TYPE_LABELS = {
854
- added: "Added",
855
- changed: "Changed",
856
- deprecated: "Deprecated",
857
- removed: "Removed",
858
- fixed: "Fixed",
859
- security: "Security"
860
- };
861
- function groupEntriesByType(entries) {
862
- const grouped = /* @__PURE__ */ new Map();
863
- for (const type of TYPE_ORDER) {
864
- grouped.set(type, []);
865
- }
866
- for (const entry of entries) {
867
- const existing = grouped.get(entry.type) ?? [];
868
- existing.push(entry);
869
- grouped.set(entry.type, existing);
870
- }
871
- return grouped;
872
- }
873
- function formatEntry(entry) {
874
- let line;
875
- if (entry.breaking && entry.scope) {
876
- line = `- **BREAKING** **${entry.scope}**: ${entry.description}`;
877
- } else if (entry.breaking) {
878
- line = `- **BREAKING** ${entry.description}`;
879
- } else if (entry.scope) {
880
- line = `- **${entry.scope}**: ${entry.description}`;
881
- } else {
882
- line = `- ${entry.description}`;
883
- }
884
- if (entry.issueIds && entry.issueIds.length > 0) {
885
- line += ` (${entry.issueIds.join(", ")})`;
886
- }
887
- return line;
888
- }
889
- function formatVersion(context) {
890
- const lines = [];
891
- const versionHeader = context.previousVersion ? `## [${context.version}]` : `## ${context.version}`;
892
- lines.push(`${versionHeader} - ${context.date}`);
893
- lines.push("");
894
- if (context.compareUrl) {
895
- lines.push(`[Full Changelog](${context.compareUrl})`);
896
- lines.push("");
897
- }
898
- if (context.enhanced?.summary) {
899
- lines.push(context.enhanced.summary);
900
- lines.push("");
901
- }
902
- const grouped = groupEntriesByType(context.entries);
903
- for (const [type, entries] of grouped) {
904
- if (entries.length === 0) continue;
905
- lines.push(`### ${TYPE_LABELS[type]}`);
906
- for (const entry of entries) {
907
- lines.push(formatEntry(entry));
908
- }
909
- lines.push("");
910
- }
911
- return lines.join("\n");
912
- }
913
- function formatHeader() {
914
- return `# Changelog
915
-
916
- All notable changes to this project will be documented in this file.
917
-
918
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
919
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
920
-
921
- `;
922
- }
923
- function renderMarkdown(contexts) {
924
- const sections = [formatHeader()];
925
- for (const context of contexts) {
926
- sections.push(formatVersion(context));
927
- }
928
- return sections.join("\n");
929
- }
930
- function prependVersion(existingPath, context) {
931
- let existing = "";
932
- if (fs2.existsSync(existingPath)) {
933
- existing = fs2.readFileSync(existingPath, "utf-8");
934
- const headerEnd = existing.indexOf("\n## ");
935
- if (headerEnd >= 0) {
936
- const header = existing.slice(0, headerEnd);
937
- const body = existing.slice(headerEnd + 1);
938
- const newVersion = formatVersion(context);
939
- return `${header}
940
-
941
- ${newVersion}
942
- ${body}`;
943
- }
944
- }
945
- return renderMarkdown([context]);
946
- }
947
- function writeMarkdown(outputPath, contexts, config, dryRun) {
948
- const content = renderMarkdown(contexts);
949
- if (dryRun) {
950
- (0, import_core5.info)(`Would write changelog to ${outputPath}`);
951
- (0, import_core5.debug)("--- Changelog Preview ---");
952
- (0, import_core5.debug)(content);
953
- (0, import_core5.debug)("--- End Preview ---");
954
- return;
955
- }
956
- const dir = path.dirname(outputPath);
957
- if (!fs2.existsSync(dir)) {
958
- fs2.mkdirSync(dir, { recursive: true });
959
- }
960
- if (outputPath === "-") {
961
- process.stdout.write(content);
962
- return;
963
- }
964
- if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
965
- const firstContext = contexts[0];
966
- if (firstContext) {
967
- const updated = prependVersion(outputPath, firstContext);
968
- fs2.writeFileSync(outputPath, updated, "utf-8");
969
- }
970
- } else {
971
- fs2.writeFileSync(outputPath, content, "utf-8");
972
- }
973
- (0, import_core5.success)(`Changelog written to ${outputPath}`);
974
- }
975
-
976
- // src/output/github-release.ts
1139
+ init_markdown();
977
1140
  var GitHubClient = class {
978
1141
  octokit;
979
1142
  owner;
@@ -1123,6 +1286,9 @@ function writeJson(outputPath, contexts, dryRun) {
1123
1286
  (0, import_core7.success)(`JSON output written to ${outputPath}`);
1124
1287
  }
1125
1288
 
1289
+ // src/core/pipeline.ts
1290
+ init_markdown();
1291
+
1126
1292
  // src/templates/ejs.ts
1127
1293
  var fs4 = __toESM(require("fs"), 1);
1128
1294
  var import_ejs = __toESM(require("ejs"), 1);
@@ -1445,9 +1611,9 @@ async function processWithLLM(context, config) {
1445
1611
  entries: context.entries
1446
1612
  };
1447
1613
  try {
1448
- (0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1614
+ (0, import_core9.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1449
1615
  if (config.llm.baseURL) {
1450
- (0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
1616
+ (0, import_core9.info)(`LLM base URL: ${config.llm.baseURL}`);
1451
1617
  }
1452
1618
  const rawProvider = createProvider(config.llm);
1453
1619
  const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
@@ -1456,49 +1622,49 @@ async function processWithLLM(context, config) {
1456
1622
  complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
1457
1623
  };
1458
1624
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1459
- (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1625
+ (0, import_core9.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1460
1626
  if (tasks.enhance && tasks.categorize) {
1461
- (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1627
+ (0, import_core9.info)("Enhancing and categorizing entries with LLM...");
1462
1628
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1463
1629
  enhanced.entries = result.enhancedEntries;
1464
1630
  enhanced.categories = {};
1465
1631
  for (const cat of result.categories) {
1466
1632
  enhanced.categories[cat.category] = cat.entries;
1467
1633
  }
1468
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1634
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1469
1635
  } else {
1470
1636
  if (tasks.enhance) {
1471
- (0, import_core8.info)("Enhancing entries with LLM...");
1637
+ (0, import_core9.info)("Enhancing entries with LLM...");
1472
1638
  enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1473
- (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
1639
+ (0, import_core9.info)(`Enhanced ${enhanced.entries.length} entries`);
1474
1640
  }
1475
1641
  if (tasks.categorize) {
1476
- (0, import_core8.info)("Categorizing entries with LLM...");
1642
+ (0, import_core9.info)("Categorizing entries with LLM...");
1477
1643
  const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1478
1644
  enhanced.categories = {};
1479
1645
  for (const cat of categorized) {
1480
1646
  enhanced.categories[cat.category] = cat.entries;
1481
1647
  }
1482
- (0, import_core8.info)(`Created ${categorized.length} categories`);
1648
+ (0, import_core9.info)(`Created ${categorized.length} categories`);
1483
1649
  }
1484
1650
  }
1485
1651
  if (tasks.summarize) {
1486
- (0, import_core8.info)("Summarizing entries with LLM...");
1652
+ (0, import_core9.info)("Summarizing entries with LLM...");
1487
1653
  enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
1488
1654
  if (enhanced.summary) {
1489
- (0, import_core8.info)("Summary generated successfully");
1490
- (0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1655
+ (0, import_core9.info)("Summary generated successfully");
1656
+ (0, import_core9.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1491
1657
  } else {
1492
- (0, import_core8.warn)("Summary generation returned empty result");
1658
+ (0, import_core9.warn)("Summary generation returned empty result");
1493
1659
  }
1494
1660
  }
1495
1661
  if (tasks.releaseNotes) {
1496
- (0, import_core8.info)("Generating release notes with LLM...");
1662
+ (0, import_core9.info)("Generating release notes with LLM...");
1497
1663
  enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
1498
1664
  if (enhanced.releaseNotes) {
1499
- (0, import_core8.info)("Release notes generated successfully");
1665
+ (0, import_core9.info)("Release notes generated successfully");
1500
1666
  } else {
1501
- (0, import_core8.warn)("Release notes generation returned empty result");
1667
+ (0, import_core9.warn)("Release notes generation returned empty result");
1502
1668
  }
1503
1669
  }
1504
1670
  return {
@@ -1506,8 +1672,8 @@ async function processWithLLM(context, config) {
1506
1672
  enhanced
1507
1673
  };
1508
1674
  } catch (error) {
1509
- (0, import_core8.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1510
- (0, import_core8.warn)("Falling back to raw entries");
1675
+ (0, import_core9.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1676
+ (0, import_core9.warn)("Falling back to raw entries");
1511
1677
  return context;
1512
1678
  }
1513
1679
  }
@@ -1515,17 +1681,17 @@ function getBuiltinTemplatePath(style) {
1515
1681
  let packageRoot;
1516
1682
  try {
1517
1683
  const currentUrl = import_meta.url;
1518
- packageRoot = path6.dirname(new URL(currentUrl).pathname);
1519
- packageRoot = path6.join(packageRoot, "..", "..");
1684
+ packageRoot = path7.dirname(new URL(currentUrl).pathname);
1685
+ packageRoot = path7.join(packageRoot, "..", "..");
1520
1686
  } catch {
1521
1687
  packageRoot = __dirname;
1522
1688
  }
1523
- return path6.join(packageRoot, "templates", style);
1689
+ return path7.join(packageRoot, "templates", style);
1524
1690
  }
1525
1691
  async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1526
1692
  let templatePath;
1527
1693
  if (config.templates?.path) {
1528
- templatePath = path6.resolve(config.templates.path);
1694
+ templatePath = path7.resolve(config.templates.path);
1529
1695
  } else {
1530
1696
  templatePath = getBuiltinTemplatePath("keep-a-changelog");
1531
1697
  }
@@ -1535,67 +1701,78 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1535
1701
  );
1536
1702
  const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
1537
1703
  if (dryRun) {
1538
- (0, import_core8.info)(`Would write templated output to ${outputPath}`);
1539
- (0, import_core8.debug)("--- Changelog Preview ---");
1540
- (0, import_core8.debug)(result.content);
1541
- (0, import_core8.debug)("--- End Preview ---");
1704
+ (0, import_core9.info)(`Would write templated output to ${outputPath}`);
1705
+ (0, import_core9.debug)("--- Changelog Preview ---");
1706
+ (0, import_core9.debug)(result.content);
1707
+ (0, import_core9.debug)("--- End Preview ---");
1542
1708
  return;
1543
1709
  }
1544
1710
  if (outputPath === "-") {
1545
1711
  process.stdout.write(result.content);
1546
1712
  return;
1547
1713
  }
1548
- const dir = path6.dirname(outputPath);
1549
- if (!fs8.existsSync(dir)) {
1550
- fs8.mkdirSync(dir, { recursive: true });
1714
+ const dir = path7.dirname(outputPath);
1715
+ if (!fs9.existsSync(dir)) {
1716
+ fs9.mkdirSync(dir, { recursive: true });
1551
1717
  }
1552
- fs8.writeFileSync(outputPath, result.content, "utf-8");
1553
- (0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1718
+ fs9.writeFileSync(outputPath, result.content, "utf-8");
1719
+ (0, import_core9.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1554
1720
  }
1555
1721
  async function runPipeline(input, config, dryRun) {
1556
- (0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
1722
+ (0, import_core9.debug)(`Processing ${input.packages.length} package(s)`);
1557
1723
  let contexts = input.packages.map(createTemplateContext);
1558
1724
  if (config.llm && !process.env.CHANGELOG_NO_LLM) {
1559
- (0, import_core8.info)("Processing with LLM enhancement");
1725
+ (0, import_core9.info)("Processing with LLM enhancement");
1560
1726
  contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
1561
1727
  }
1728
+ const files = [];
1562
1729
  for (const output of config.output) {
1563
- (0, import_core8.info)(`Generating ${output.format} output`);
1730
+ (0, import_core9.info)(`Generating ${output.format} output`);
1564
1731
  switch (output.format) {
1565
1732
  case "markdown": {
1566
1733
  const file = output.file ?? "CHANGELOG.md";
1567
- const effectiveTemplateConfig = output.templates ?? config.templates;
1568
- if (effectiveTemplateConfig?.path || output.options?.template) {
1569
- const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
1570
- await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
1571
- } else {
1572
- writeMarkdown(file, contexts, config, dryRun);
1734
+ try {
1735
+ const effectiveTemplateConfig = output.templates ?? config.templates;
1736
+ if (effectiveTemplateConfig?.path || output.options?.template) {
1737
+ const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
1738
+ await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
1739
+ } else {
1740
+ writeMarkdown(file, contexts, config, dryRun);
1741
+ }
1742
+ if (!dryRun) files.push(file);
1743
+ } catch (error) {
1744
+ (0, import_core9.warn)(`Failed to write ${file}: ${error instanceof Error ? error.message : String(error)}`);
1573
1745
  }
1574
1746
  break;
1575
1747
  }
1576
1748
  case "json": {
1577
1749
  const file = output.file ?? "changelog.json";
1578
- writeJson(file, contexts, dryRun);
1750
+ try {
1751
+ writeJson(file, contexts, dryRun);
1752
+ if (!dryRun) files.push(file);
1753
+ } catch (error) {
1754
+ (0, import_core9.warn)(`Failed to write ${file}: ${error instanceof Error ? error.message : String(error)}`);
1755
+ }
1579
1756
  break;
1580
1757
  }
1581
1758
  case "github-release": {
1582
1759
  if (dryRun) {
1583
- (0, import_core8.info)("[DRY RUN] Would create GitHub release");
1760
+ (0, import_core9.info)("[DRY RUN] Would create GitHub release");
1584
1761
  break;
1585
1762
  }
1586
1763
  const firstContext = contexts[0];
1587
1764
  if (!firstContext) {
1588
- (0, import_core8.warn)("No context available for GitHub release");
1765
+ (0, import_core9.warn)("No context available for GitHub release");
1589
1766
  break;
1590
1767
  }
1591
1768
  const repoUrl = firstContext.repoUrl;
1592
1769
  if (!repoUrl) {
1593
- (0, import_core8.warn)("No repo URL available, cannot create GitHub release");
1770
+ (0, import_core9.warn)("No repo URL available, cannot create GitHub release");
1594
1771
  break;
1595
1772
  }
1596
1773
  const parsed = parseRepoUrl(repoUrl);
1597
1774
  if (!parsed) {
1598
- (0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
1775
+ (0, import_core9.warn)(`Could not parse repo URL: ${repoUrl}`);
1599
1776
  break;
1600
1777
  }
1601
1778
  await createGitHubRelease(firstContext, {
@@ -1608,140 +1785,38 @@ async function runPipeline(input, config, dryRun) {
1608
1785
  }
1609
1786
  }
1610
1787
  }
1611
- }
1612
- async function processInput(inputJson, config, dryRun) {
1613
- const input = parsePackageVersioner(inputJson);
1614
- await runPipeline(input, config, dryRun);
1615
- }
1616
-
1617
- // src/monorepo/aggregator.ts
1618
- var fs9 = __toESM(require("fs"), 1);
1619
- var path7 = __toESM(require("path"), 1);
1620
- var import_core9 = require("@releasekit/core");
1621
-
1622
- // src/monorepo/splitter.ts
1623
- function splitByPackage(contexts) {
1624
- const byPackage = /* @__PURE__ */ new Map();
1625
- for (const ctx of contexts) {
1626
- byPackage.set(ctx.packageName, ctx);
1627
- }
1628
- return byPackage;
1629
- }
1630
-
1631
- // src/monorepo/aggregator.ts
1632
- function writeFile(outputPath, content, dryRun) {
1633
- if (dryRun) {
1634
- (0, import_core9.info)(`Would write to ${outputPath}`);
1635
- (0, import_core9.debug)(content);
1636
- return;
1637
- }
1638
- const dir = path7.dirname(outputPath);
1639
- if (!fs9.existsSync(dir)) {
1640
- fs9.mkdirSync(dir, { recursive: true });
1641
- }
1642
- fs9.writeFileSync(outputPath, content, "utf-8");
1643
- (0, import_core9.success)(`Changelog written to ${outputPath}`);
1644
- }
1645
- function aggregateToRoot(contexts) {
1646
- const aggregated = {
1647
- packageName: "monorepo",
1648
- version: contexts[0]?.version ?? "0.0.0",
1649
- previousVersion: contexts[0]?.previousVersion ?? null,
1650
- date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "",
1651
- repoUrl: contexts[0]?.repoUrl ?? null,
1652
- entries: []
1653
- };
1654
- for (const ctx of contexts) {
1655
- for (const entry of ctx.entries) {
1656
- aggregated.entries.push({
1657
- ...entry,
1658
- scope: entry.scope ? `${ctx.packageName}/${entry.scope}` : ctx.packageName
1659
- });
1788
+ if (config.monorepo?.mode) {
1789
+ const { detectMonorepo: detectMonorepo2, writeMonorepoChangelogs: writeMonorepoChangelogs2 } = await Promise.resolve().then(() => (init_aggregator(), aggregator_exports));
1790
+ const cwd = process.cwd();
1791
+ const detected = detectMonorepo2(cwd);
1792
+ if (detected.isMonorepo) {
1793
+ const monoFiles = writeMonorepoChangelogs2(
1794
+ contexts,
1795
+ {
1796
+ rootPath: config.monorepo.rootPath ?? cwd,
1797
+ packagesPath: config.monorepo.packagesPath ?? detected.packagesPath,
1798
+ mode: config.monorepo.mode
1799
+ },
1800
+ config,
1801
+ dryRun
1802
+ );
1803
+ files.push(...monoFiles);
1660
1804
  }
1661
1805
  }
1662
- return aggregated;
1663
- }
1664
- function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1665
- if (options.mode === "root" || options.mode === "both") {
1666
- const aggregated = aggregateToRoot(contexts);
1667
- const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
1668
- (0, import_core9.info)(`Writing root changelog to ${rootPath}`);
1669
- const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
1670
- writeFile(rootPath, rootContent, dryRun);
1671
- }
1672
- if (options.mode === "packages" || options.mode === "both") {
1673
- const byPackage = splitByPackage(contexts);
1674
- const packageDirMap = buildPackageDirMap(options.rootPath, options.packagesPath);
1675
- for (const [packageName, ctx] of byPackage) {
1676
- const simpleName = packageName.split("/").pop();
1677
- const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
1678
- if (packageDir) {
1679
- const changelogPath = path7.join(packageDir, "CHANGELOG.md");
1680
- (0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1681
- const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
1682
- writeFile(changelogPath, pkgContent, dryRun);
1683
- } else {
1684
- (0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
1685
- }
1686
- }
1687
- }
1688
- }
1689
- function buildPackageDirMap(rootPath, packagesPath) {
1690
- const map = /* @__PURE__ */ new Map();
1691
- const packagesDir = path7.join(rootPath, packagesPath);
1692
- if (!fs9.existsSync(packagesDir)) {
1693
- return map;
1694
- }
1695
- for (const entry of fs9.readdirSync(packagesDir, { withFileTypes: true })) {
1696
- if (!entry.isDirectory()) continue;
1697
- const dirPath = path7.join(packagesDir, entry.name);
1698
- map.set(entry.name, dirPath);
1699
- const packageJsonPath = path7.join(dirPath, "package.json");
1700
- if (fs9.existsSync(packageJsonPath)) {
1701
- try {
1702
- const pkg = JSON.parse(fs9.readFileSync(packageJsonPath, "utf-8"));
1703
- if (pkg.name) {
1704
- map.set(pkg.name, dirPath);
1705
- }
1706
- } catch {
1707
- }
1708
- }
1806
+ const packageNotes = {};
1807
+ for (const ctx of contexts) {
1808
+ packageNotes[ctx.packageName] = formatVersion(ctx);
1709
1809
  }
1710
- return map;
1810
+ return { packageNotes, files };
1711
1811
  }
1712
- function detectMonorepo(cwd) {
1713
- const pnpmWorkspacesPath = path7.join(cwd, "pnpm-workspace.yaml");
1714
- const packageJsonPath = path7.join(cwd, "package.json");
1715
- if (fs9.existsSync(pnpmWorkspacesPath)) {
1716
- const content = fs9.readFileSync(pnpmWorkspacesPath, "utf-8");
1717
- const packagesMatch = content.match(/packages:\s*\n\s*-\s*['"]([^'"]+)['"]/);
1718
- if (packagesMatch?.[1]) {
1719
- const packagesGlob = packagesMatch[1];
1720
- const packagesPath = packagesGlob.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
1721
- return { isMonorepo: true, packagesPath: packagesPath || "packages" };
1722
- }
1723
- return { isMonorepo: true, packagesPath: "packages" };
1724
- }
1725
- if (fs9.existsSync(packageJsonPath)) {
1726
- try {
1727
- const content = fs9.readFileSync(packageJsonPath, "utf-8");
1728
- const pkg = JSON.parse(content);
1729
- if (pkg.workspaces) {
1730
- const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces.packages;
1731
- if (workspaces?.length) {
1732
- const firstWorkspace = workspaces[0];
1733
- if (firstWorkspace) {
1734
- const packagesPath = firstWorkspace.replace(/\/?\*$/, "").replace(/\/\*\*$/, "");
1735
- return { isMonorepo: true, packagesPath: packagesPath || "packages" };
1736
- }
1737
- }
1738
- }
1739
- } catch {
1740
- return { isMonorepo: false, packagesPath: "" };
1741
- }
1742
- }
1743
- return { isMonorepo: false, packagesPath: "" };
1812
+ async function processInput(inputJson, config, dryRun) {
1813
+ const input = parsePackageVersioner(inputJson);
1814
+ return runPipeline(input, config, dryRun);
1744
1815
  }
1816
+
1817
+ // src/index.ts
1818
+ init_aggregator();
1819
+ init_markdown();
1745
1820
  // Annotate the CommonJS export names for ESM import in node:
1746
1821
  0 && (module.exports = {
1747
1822
  ChangelogCreatorError,
@@ -1755,6 +1830,7 @@ function detectMonorepo(cwd) {
1755
1830
  aggregateToRoot,
1756
1831
  createTemplateContext,
1757
1832
  detectMonorepo,
1833
+ formatVersion,
1758
1834
  getDefaultConfig,
1759
1835
  getExitCode,
1760
1836
  loadAuth,