@releasekit/notes 0.2.0-next.1 → 0.2.0-next.11

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.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runPipeline,
12
12
  saveAuth,
13
13
  writeMonorepoChangelogs
14
- } from "./chunk-W7DVGQ7D.js";
14
+ } from "./chunk-3VS3PBTN.js";
15
15
 
16
16
  // src/cli.ts
17
17
  import * as fs from "fs";
@@ -20,7 +20,7 @@ import { error, info, setLogLevel, setQuietMode, success } from "@releasekit/cor
20
20
  import { Command } from "commander";
21
21
  var program = new Command();
22
22
  program.name("releasekit-notes").description("Generate changelogs with LLM-powered enhancement and flexible templating").version("0.1.0");
23
- program.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("-o, --output <spec>", "Output spec (format:file)", collectOutputs, []).option("-t, --template <path>", "Template file or directory").option("-e, --engine <engine>", "Template engine (handlebars|liquid|ejs)").option("--monorepo <mode>", "Monorepo mode (root|packages|both)").option("--llm-provider <provider>", "LLM provider").option("--llm-model <model>", "LLM model").option("--llm-base-url <url>", "LLM base URL (for openai-compatible provider)").option("--llm-tasks <tasks>", "Comma-separated LLM tasks").option("--no-llm", "Disable LLM processing").option("--config <path>", "Config file path").option("--dry-run", "Preview without writing").option("--regenerate", "Regenerate entire changelog").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
23
+ program.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("-o, --output <spec>", "Output spec (format:file)", collectOutputs, []).option("-t, --template <path>", "Template file or directory").option("-e, --engine <engine>", "Template engine (handlebars|liquid|ejs)").option("--monorepo <mode>", "Monorepo mode (root|packages|both)").option("--llm-provider <provider>", "LLM provider").option("--llm-model <model>", "LLM model").option("--llm-base-url <url>", "LLM base URL (for openai-compatible provider)").option("--llm-tasks <tasks>", "Comma-separated LLM tasks").option("--no-llm", "Disable LLM processing").option("--target <package>", "Filter to a specific package name").option("--config <path>", "Config file path").option("--dry-run", "Preview without writing").option("--regenerate", "Regenerate entire changelog").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
24
24
  setVerbosity(options.verbose);
25
25
  if (options.quiet) setQuietMode(true);
26
26
  try {
@@ -73,6 +73,15 @@ program.command("generate", { isDefault: true }).description("Generate changelog
73
73
  inputJson = await readStdin();
74
74
  }
75
75
  const input = parsePackageVersioner(inputJson);
76
+ if (options.target) {
77
+ const before = input.packages.length;
78
+ input.packages = input.packages.filter((p) => p.packageName === options.target);
79
+ if (input.packages.length === 0) {
80
+ info(`No changelog found for package "${options.target}" (had ${before} package(s))`);
81
+ return;
82
+ }
83
+ info(`Filtered to package: ${options.target}`);
84
+ }
76
85
  if (options.monorepo || config.monorepo) {
77
86
  const monorepoMode = options.monorepo ?? config.monorepo?.mode ?? "both";
78
87
  const detected = detectMonorepo(process.cwd());
package/dist/index.cjs CHANGED
@@ -75,7 +75,7 @@ function getDefaultConfig() {
75
75
  // src/core/pipeline.ts
76
76
  var fs8 = __toESM(require("fs"), 1);
77
77
  var path6 = __toESM(require("path"), 1);
78
- var import_core7 = require("@releasekit/core");
78
+ var import_core8 = require("@releasekit/core");
79
79
 
80
80
  // src/input/package-versioner.ts
81
81
  var fs = __toESM(require("fs"), 1);
@@ -416,15 +416,26 @@ Entries:
416
416
  Output only valid JSON, nothing else:`;
417
417
  function buildCustomCategorizePrompt(categories) {
418
418
  const categoryList = categories.map((c) => `- "${c.name}": ${c.description}`).join("\n");
419
+ const developerCategory = categories.find((c) => c.name === "Developer");
420
+ let scopeInstructions = "";
421
+ if (developerCategory) {
422
+ const scopeMatch = developerCategory.description.match(/from:\s*([^.]+)/);
423
+ if (scopeMatch?.[1]) {
424
+ const scopes = scopeMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
425
+ if (scopes.length > 0) {
426
+ scopeInstructions = `
427
+
428
+ For the "Developer" category, you MUST assign a scope from this exact list: ${scopes.join(", ")}.
429
+ `;
430
+ }
431
+ }
432
+ }
419
433
  return `You are categorizing changelog entries for a software release.
420
434
 
421
- Given the following entries, group them into the specified categories. Only use the categories listed below.
435
+ Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
422
436
 
423
437
  Categories:
424
- ${categoryList}
425
-
426
- For entries in categories that involve internal/developer changes, set a "scope" field on those entries with a short subcategory label (e.g., "CI", "Dependencies", "Testing", "Code Quality", "Build System").
427
-
438
+ ${categoryList}${scopeInstructions}
428
439
  Output a JSON object with two fields:
429
440
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
430
441
  - "scopes": an object where keys are entry indices (as strings) and values are scope labels
@@ -524,6 +535,113 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
524
535
  return results;
525
536
  }
526
537
 
538
+ // src/llm/tasks/enhance-and-categorize.ts
539
+ var import_core4 = require("@releasekit/core");
540
+
541
+ // src/utils/retry.ts
542
+ function sleep(ms) {
543
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
544
+ }
545
+ async function withRetry(fn, options = {}) {
546
+ const maxAttempts = options.maxAttempts ?? 3;
547
+ const initialDelay = options.initialDelay ?? 1e3;
548
+ const maxDelay = options.maxDelay ?? 3e4;
549
+ const backoffFactor = options.backoffFactor ?? 2;
550
+ let lastError;
551
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
552
+ try {
553
+ return await fn();
554
+ } catch (error) {
555
+ lastError = error;
556
+ if (attempt < maxAttempts - 1) {
557
+ const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
558
+ const jitter = base * 0.2 * (Math.random() * 2 - 1);
559
+ await sleep(Math.max(0, base + jitter));
560
+ }
561
+ }
562
+ }
563
+ throw lastError;
564
+ }
565
+
566
+ // src/llm/tasks/enhance-and-categorize.ts
567
+ function buildPrompt(entries, categories, style) {
568
+ const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
569
+ const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
570
+ const categorySection = categories ? `Categories (use ONLY these):
571
+ ${categories.map((c) => `- "${c.name}": ${c.description}`).join("\n")}` : `Categories: Group into meaningful categories (e.g., "New", "Fixed", "Changed", "Removed").`;
572
+ return `You are generating release notes for a software project. Given the following changelog entries, do two things:
573
+
574
+ 1. **Rewrite** each entry as a clear, user-friendly description
575
+ 2. **Categorize** each entry into the appropriate category
576
+
577
+ Style guidelines:
578
+ - ${styleText}
579
+ - Be concise (1 short sentence per entry)
580
+ - Focus on what changed, not implementation details
581
+
582
+ ${categorySection}
583
+
584
+ ${categories ? 'For entries in categories involving internal/developer changes, set a "scope" field with a short subcategory label (e.g., "CI", "Dependencies", "Testing").' : ""}
585
+
586
+ Entries:
587
+ ${entriesText}
588
+
589
+ Output a JSON object with:
590
+ - "entries": array of objects, one per input entry (same order), each with: { "description": "rewritten text", "category": "CategoryName", "scope": "optional subcategory label or null" }
591
+
592
+ Output only valid JSON, nothing else:`;
593
+ }
594
+ async function enhanceAndCategorize(provider, entries, context) {
595
+ if (entries.length === 0) {
596
+ return { enhancedEntries: [], categories: [] };
597
+ }
598
+ const retryOpts = LLM_DEFAULTS.retry;
599
+ try {
600
+ return await withRetry(async () => {
601
+ const prompt = buildPrompt(entries, context.categories, context.style);
602
+ const response = await provider.complete(prompt);
603
+ const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
604
+ const parsed = JSON.parse(cleaned);
605
+ if (!Array.isArray(parsed.entries)) {
606
+ throw new Error('Response missing "entries" array');
607
+ }
608
+ const enhancedEntries = entries.map((original, i) => {
609
+ const result = parsed.entries[i];
610
+ if (!result) return original;
611
+ return {
612
+ ...original,
613
+ description: result.description || original.description,
614
+ scope: result.scope || original.scope
615
+ };
616
+ });
617
+ const categoryMap = /* @__PURE__ */ new Map();
618
+ for (let i = 0; i < parsed.entries.length; i++) {
619
+ const result = parsed.entries[i];
620
+ const category = result?.category || "General";
621
+ const entry = enhancedEntries[i];
622
+ if (!entry) continue;
623
+ if (!categoryMap.has(category)) {
624
+ categoryMap.set(category, []);
625
+ }
626
+ categoryMap.get(category).push(entry);
627
+ }
628
+ const categories = [];
629
+ for (const [category, catEntries] of categoryMap) {
630
+ categories.push({ category, entries: catEntries });
631
+ }
632
+ return { enhancedEntries, categories };
633
+ }, retryOpts);
634
+ } catch (error) {
635
+ (0, import_core4.warn)(
636
+ `Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error instanceof Error ? error.message : String(error)}`
637
+ );
638
+ return {
639
+ enhancedEntries: entries,
640
+ categories: [{ category: "General", entries }]
641
+ };
642
+ }
643
+ }
644
+
527
645
  // src/llm/tasks/release-notes.ts
528
646
  var RELEASE_NOTES_PROMPT = `You are writing release notes for a software project.
529
647
 
@@ -624,12 +742,12 @@ function createProvider(config) {
624
742
 
625
743
  // src/output/github-release.ts
626
744
  var import_rest = require("@octokit/rest");
627
- var import_core5 = require("@releasekit/core");
745
+ var import_core6 = require("@releasekit/core");
628
746
 
629
747
  // src/output/markdown.ts
630
748
  var fs2 = __toESM(require("fs"), 1);
631
749
  var path = __toESM(require("path"), 1);
632
- var import_core4 = require("@releasekit/core");
750
+ var import_core5 = require("@releasekit/core");
633
751
  var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
634
752
  var TYPE_LABELS = {
635
753
  added: "Added",
@@ -728,15 +846,19 @@ ${body}`;
728
846
  function writeMarkdown(outputPath, contexts, config, dryRun) {
729
847
  const content = renderMarkdown(contexts);
730
848
  if (dryRun) {
731
- (0, import_core4.info)("--- Changelog Preview ---");
849
+ (0, import_core5.info)("--- Changelog Preview ---");
732
850
  console.log(content);
733
- (0, import_core4.info)("--- End Preview ---");
851
+ (0, import_core5.info)("--- End Preview ---");
734
852
  return;
735
853
  }
736
854
  const dir = path.dirname(outputPath);
737
855
  if (!fs2.existsSync(dir)) {
738
856
  fs2.mkdirSync(dir, { recursive: true });
739
857
  }
858
+ if (outputPath === "-") {
859
+ process.stdout.write(content);
860
+ return;
861
+ }
740
862
  if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
741
863
  const firstContext = contexts[0];
742
864
  if (firstContext) {
@@ -746,7 +868,7 @@ function writeMarkdown(outputPath, contexts, config, dryRun) {
746
868
  } else {
747
869
  fs2.writeFileSync(outputPath, content, "utf-8");
748
870
  }
749
- (0, import_core4.success)(`Changelog written to ${outputPath}`);
871
+ (0, import_core5.success)(`Changelog written to ${outputPath}`);
750
872
  }
751
873
 
752
874
  // src/output/github-release.ts
@@ -771,7 +893,7 @@ var GitHubClient = class {
771
893
  } else {
772
894
  body = renderMarkdown([context]);
773
895
  }
774
- (0, import_core5.info)(`Creating GitHub release for ${tagName}`);
896
+ (0, import_core6.info)(`Creating GitHub release for ${tagName}`);
775
897
  try {
776
898
  const response = await this.octokit.repos.createRelease({
777
899
  owner: this.owner,
@@ -783,7 +905,7 @@ var GitHubClient = class {
783
905
  prerelease: options.prerelease ?? false,
784
906
  generate_release_notes: options.generateNotes ?? false
785
907
  });
786
- (0, import_core5.success)(`Release created: ${response.data.html_url}`);
908
+ (0, import_core6.success)(`Release created: ${response.data.html_url}`);
787
909
  return {
788
910
  id: response.data.id,
789
911
  htmlUrl: response.data.html_url,
@@ -801,7 +923,7 @@ var GitHubClient = class {
801
923
  } else {
802
924
  body = renderMarkdown([context]);
803
925
  }
804
- (0, import_core5.info)(`Updating GitHub release ${releaseId}`);
926
+ (0, import_core6.info)(`Updating GitHub release ${releaseId}`);
805
927
  try {
806
928
  const response = await this.octokit.repos.updateRelease({
807
929
  owner: this.owner,
@@ -813,7 +935,7 @@ var GitHubClient = class {
813
935
  draft: options.draft ?? false,
814
936
  prerelease: options.prerelease ?? false
815
937
  });
816
- (0, import_core5.success)(`Release updated: ${response.data.html_url}`);
938
+ (0, import_core6.success)(`Release updated: ${response.data.html_url}`);
817
939
  return {
818
940
  id: response.data.id,
819
941
  htmlUrl: response.data.html_url,
@@ -865,7 +987,7 @@ async function createGitHubRelease(context, options) {
865
987
  // src/output/json.ts
866
988
  var fs3 = __toESM(require("fs"), 1);
867
989
  var path2 = __toESM(require("path"), 1);
868
- var import_core6 = require("@releasekit/core");
990
+ var import_core7 = require("@releasekit/core");
869
991
  function renderJson(contexts) {
870
992
  return JSON.stringify(
871
993
  {
@@ -885,9 +1007,9 @@ function renderJson(contexts) {
885
1007
  function writeJson(outputPath, contexts, dryRun) {
886
1008
  const content = renderJson(contexts);
887
1009
  if (dryRun) {
888
- (0, import_core6.info)("--- JSON Output Preview ---");
1010
+ (0, import_core7.info)("--- JSON Output Preview ---");
889
1011
  console.log(content);
890
- (0, import_core6.info)("--- End Preview ---");
1012
+ (0, import_core7.info)("--- End Preview ---");
891
1013
  return;
892
1014
  }
893
1015
  const dir = path2.dirname(outputPath);
@@ -895,7 +1017,7 @@ function writeJson(outputPath, contexts, dryRun) {
895
1017
  fs3.mkdirSync(dir, { recursive: true });
896
1018
  }
897
1019
  fs3.writeFileSync(outputPath, content, "utf-8");
898
- (0, import_core6.success)(`JSON output written to ${outputPath}`);
1020
+ (0, import_core7.success)(`JSON output written to ${outputPath}`);
899
1021
  }
900
1022
 
901
1023
  // src/templates/ejs.ts
@@ -1152,44 +1274,29 @@ function renderTemplate(templatePath, context, engine) {
1152
1274
  return renderComposable(templatePath, context, engine);
1153
1275
  }
1154
1276
 
1155
- // src/utils/retry.ts
1156
- function sleep(ms) {
1157
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1158
- }
1159
- async function withRetry(fn, options = {}) {
1160
- const maxAttempts = options.maxAttempts ?? 3;
1161
- const initialDelay = options.initialDelay ?? 1e3;
1162
- const maxDelay = options.maxDelay ?? 3e4;
1163
- const backoffFactor = options.backoffFactor ?? 2;
1164
- let lastError;
1165
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1166
- try {
1167
- return await fn();
1168
- } catch (error) {
1169
- lastError = error;
1170
- if (attempt < maxAttempts - 1) {
1171
- const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
1172
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
1173
- await sleep(Math.max(0, base + jitter));
1174
- }
1175
- }
1176
- }
1177
- throw lastError;
1178
- }
1179
-
1180
1277
  // src/core/pipeline.ts
1181
1278
  var import_meta = {};
1182
- function generateCompareUrl(repoUrl, from, to) {
1279
+ function generateCompareUrl(repoUrl, from, to, packageName) {
1280
+ const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
1281
+ let fromVersion;
1282
+ let toVersion;
1283
+ if (isPackageSpecific) {
1284
+ fromVersion = from;
1285
+ toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
1286
+ } else {
1287
+ fromVersion = from.replace(/^v/, "");
1288
+ toVersion = to.replace(/^v/, "");
1289
+ }
1183
1290
  if (/gitlab\.com/i.test(repoUrl)) {
1184
- return `${repoUrl}/-/compare/${from}...${to}`;
1291
+ return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
1185
1292
  }
1186
1293
  if (/bitbucket\.org/i.test(repoUrl)) {
1187
- return `${repoUrl}/branches/compare/${from}..${to}`;
1294
+ return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
1188
1295
  }
1189
- return `${repoUrl}/compare/${from}...${to}`;
1296
+ return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
1190
1297
  }
1191
1298
  function createTemplateContext(pkg) {
1192
- const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
1299
+ const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
1193
1300
  return {
1194
1301
  packageName: pkg.packageName,
1195
1302
  version: pkg.version,
@@ -1233,9 +1340,9 @@ async function processWithLLM(context, config) {
1233
1340
  entries: context.entries
1234
1341
  };
1235
1342
  try {
1236
- (0, import_core7.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1343
+ (0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1237
1344
  if (config.llm.baseURL) {
1238
- (0, import_core7.info)(`LLM base URL: ${config.llm.baseURL}`);
1345
+ (0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
1239
1346
  }
1240
1347
  const rawProvider = createProvider(config.llm);
1241
1348
  const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
@@ -1244,38 +1351,49 @@ async function processWithLLM(context, config) {
1244
1351
  complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
1245
1352
  };
1246
1353
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1247
- (0, import_core7.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1248
- if (tasks.enhance) {
1249
- (0, import_core7.info)("Enhancing entries with LLM...");
1250
- enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1251
- (0, import_core7.info)(`Enhanced ${enhanced.entries.length} entries`);
1354
+ (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1355
+ if (tasks.enhance && tasks.categorize) {
1356
+ (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1357
+ const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1358
+ enhanced.entries = result.enhancedEntries;
1359
+ enhanced.categories = {};
1360
+ for (const cat of result.categories) {
1361
+ enhanced.categories[cat.category] = cat.entries;
1362
+ }
1363
+ (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1364
+ } else {
1365
+ if (tasks.enhance) {
1366
+ (0, import_core8.info)("Enhancing entries with LLM...");
1367
+ enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1368
+ (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
1369
+ }
1370
+ if (tasks.categorize) {
1371
+ (0, import_core8.info)("Categorizing entries with LLM...");
1372
+ const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1373
+ enhanced.categories = {};
1374
+ for (const cat of categorized) {
1375
+ enhanced.categories[cat.category] = cat.entries;
1376
+ }
1377
+ (0, import_core8.info)(`Created ${categorized.length} categories`);
1378
+ }
1252
1379
  }
1253
1380
  if (tasks.summarize) {
1254
- (0, import_core7.info)("Summarizing entries with LLM...");
1381
+ (0, import_core8.info)("Summarizing entries with LLM...");
1255
1382
  enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
1256
1383
  if (enhanced.summary) {
1257
- (0, import_core7.info)("Summary generated successfully");
1258
- (0, import_core7.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1384
+ (0, import_core8.info)("Summary generated successfully");
1385
+ (0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1259
1386
  } else {
1260
- (0, import_core7.warn)("Summary generation returned empty result");
1261
- }
1262
- }
1263
- if (tasks.categorize) {
1264
- (0, import_core7.info)("Categorizing entries with LLM...");
1265
- const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1266
- enhanced.categories = {};
1267
- for (const cat of categorized) {
1268
- enhanced.categories[cat.category] = cat.entries;
1387
+ (0, import_core8.warn)("Summary generation returned empty result");
1269
1388
  }
1270
- (0, import_core7.info)(`Created ${categorized.length} categories`);
1271
1389
  }
1272
1390
  if (tasks.releaseNotes) {
1273
- (0, import_core7.info)("Generating release notes with LLM...");
1391
+ (0, import_core8.info)("Generating release notes with LLM...");
1274
1392
  enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
1275
1393
  if (enhanced.releaseNotes) {
1276
- (0, import_core7.info)("Release notes generated successfully");
1394
+ (0, import_core8.info)("Release notes generated successfully");
1277
1395
  } else {
1278
- (0, import_core7.warn)("Release notes generation returned empty result");
1396
+ (0, import_core8.warn)("Release notes generation returned empty result");
1279
1397
  }
1280
1398
  }
1281
1399
  return {
@@ -1284,8 +1402,8 @@ async function processWithLLM(context, config) {
1284
1402
  enhanced
1285
1403
  };
1286
1404
  } catch (error) {
1287
- (0, import_core7.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1288
- (0, import_core7.warn)("Falling back to raw entries");
1405
+ (0, import_core8.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1406
+ (0, import_core8.warn)("Falling back to raw entries");
1289
1407
  return context;
1290
1408
  }
1291
1409
  }
@@ -1313,9 +1431,13 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1313
1431
  );
1314
1432
  const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
1315
1433
  if (dryRun) {
1316
- (0, import_core7.info)("--- Changelog Preview ---");
1434
+ (0, import_core8.info)("--- Changelog Preview ---");
1317
1435
  console.log(result.content);
1318
- (0, import_core7.info)("--- End Preview ---");
1436
+ (0, import_core8.info)("--- End Preview ---");
1437
+ return;
1438
+ }
1439
+ if (outputPath === "-") {
1440
+ process.stdout.write(result.content);
1319
1441
  return;
1320
1442
  }
1321
1443
  const dir = path6.dirname(outputPath);
@@ -1323,17 +1445,17 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1323
1445
  fs8.mkdirSync(dir, { recursive: true });
1324
1446
  }
1325
1447
  fs8.writeFileSync(outputPath, result.content, "utf-8");
1326
- (0, import_core7.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1448
+ (0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1327
1449
  }
1328
1450
  async function runPipeline(input, config, dryRun) {
1329
- (0, import_core7.debug)(`Processing ${input.packages.length} package(s)`);
1451
+ (0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
1330
1452
  let contexts = input.packages.map(createTemplateContext);
1331
1453
  if (config.llm && !process.env.CHANGELOG_NO_LLM) {
1332
- (0, import_core7.info)("Processing with LLM enhancement");
1454
+ (0, import_core8.info)("Processing with LLM enhancement");
1333
1455
  contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
1334
1456
  }
1335
1457
  for (const output of config.output) {
1336
- (0, import_core7.info)(`Generating ${output.format} output`);
1458
+ (0, import_core8.info)(`Generating ${output.format} output`);
1337
1459
  switch (output.format) {
1338
1460
  case "markdown": {
1339
1461
  const file = output.file ?? "CHANGELOG.md";
@@ -1351,22 +1473,22 @@ async function runPipeline(input, config, dryRun) {
1351
1473
  }
1352
1474
  case "github-release": {
1353
1475
  if (dryRun) {
1354
- (0, import_core7.info)("[DRY RUN] Would create GitHub release");
1476
+ (0, import_core8.info)("[DRY RUN] Would create GitHub release");
1355
1477
  break;
1356
1478
  }
1357
1479
  const firstContext = contexts[0];
1358
1480
  if (!firstContext) {
1359
- (0, import_core7.warn)("No context available for GitHub release");
1481
+ (0, import_core8.warn)("No context available for GitHub release");
1360
1482
  break;
1361
1483
  }
1362
1484
  const repoUrl = firstContext.repoUrl;
1363
1485
  if (!repoUrl) {
1364
- (0, import_core7.warn)("No repo URL available, cannot create GitHub release");
1486
+ (0, import_core8.warn)("No repo URL available, cannot create GitHub release");
1365
1487
  break;
1366
1488
  }
1367
1489
  const parsed = parseRepoUrl(repoUrl);
1368
1490
  if (!parsed) {
1369
- (0, import_core7.warn)(`Could not parse repo URL: ${repoUrl}`);
1491
+ (0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
1370
1492
  break;
1371
1493
  }
1372
1494
  await createGitHubRelease(firstContext, {
@@ -1388,7 +1510,7 @@ async function processInput(inputJson, config, dryRun) {
1388
1510
  // src/monorepo/aggregator.ts
1389
1511
  var fs9 = __toESM(require("fs"), 1);
1390
1512
  var path7 = __toESM(require("path"), 1);
1391
- var import_core8 = require("@releasekit/core");
1513
+ var import_core9 = require("@releasekit/core");
1392
1514
 
1393
1515
  // src/monorepo/splitter.ts
1394
1516
  function splitByPackage(contexts) {
@@ -1402,7 +1524,7 @@ function splitByPackage(contexts) {
1402
1524
  // src/monorepo/aggregator.ts
1403
1525
  function writeFile(outputPath, content, dryRun) {
1404
1526
  if (dryRun) {
1405
- (0, import_core8.info)(`[DRY RUN] Would write to ${outputPath}`);
1527
+ (0, import_core9.info)(`[DRY RUN] Would write to ${outputPath}`);
1406
1528
  console.log(content);
1407
1529
  return;
1408
1530
  }
@@ -1411,7 +1533,7 @@ function writeFile(outputPath, content, dryRun) {
1411
1533
  fs9.mkdirSync(dir, { recursive: true });
1412
1534
  }
1413
1535
  fs9.writeFileSync(outputPath, content, "utf-8");
1414
- (0, import_core8.success)(`Changelog written to ${outputPath}`);
1536
+ (0, import_core9.success)(`Changelog written to ${outputPath}`);
1415
1537
  }
1416
1538
  function aggregateToRoot(contexts) {
1417
1539
  const aggregated = {
@@ -1436,7 +1558,7 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1436
1558
  if (options.mode === "root" || options.mode === "both") {
1437
1559
  const aggregated = aggregateToRoot(contexts);
1438
1560
  const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
1439
- (0, import_core8.info)(`Writing root changelog to ${rootPath}`);
1561
+ (0, import_core9.info)(`Writing root changelog to ${rootPath}`);
1440
1562
  const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
1441
1563
  writeFile(rootPath, rootContent, dryRun);
1442
1564
  }
@@ -1448,11 +1570,11 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1448
1570
  const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
1449
1571
  if (packageDir) {
1450
1572
  const changelogPath = path7.join(packageDir, "CHANGELOG.md");
1451
- (0, import_core8.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1573
+ (0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1452
1574
  const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
1453
1575
  writeFile(changelogPath, pkgContent, dryRun);
1454
1576
  } else {
1455
- (0, import_core8.info)(`Could not find directory for package ${packageName}, skipping`);
1577
+ (0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
1456
1578
  }
1457
1579
  }
1458
1580
  }
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  writeJson,
25
25
  writeMarkdown,
26
26
  writeMonorepoChangelogs
27
- } from "./chunk-W7DVGQ7D.js";
27
+ } from "./chunk-3VS3PBTN.js";
28
28
  export {
29
29
  NotesError as ChangelogCreatorError,
30
30
  ConfigError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@releasekit/notes",
3
- "version": "0.2.0-next.1",
3
+ "version": "0.2.0-next.11",
4
4
  "description": "Changelog generation with LLM-powered enhancement and flexible templating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",