@releasekit/notes 0.2.0-next.0 → 0.2.0-next.10

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-NHDLQLG2.js";
14
+ } from "./chunk-ACXCEHQT.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
@@ -456,7 +467,8 @@ async function categorizeEntries(provider, entries, context) {
456
467
  entries[idx] = { ...entries[idx], scope };
457
468
  }
458
469
  }
459
- for (const [category, indices] of Object.entries(categoryMap)) {
470
+ for (const [category, rawIndices] of Object.entries(categoryMap)) {
471
+ const indices = Array.isArray(rawIndices) ? rawIndices : [];
460
472
  const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
461
473
  if (categoryEntries.length > 0) {
462
474
  result.push({ category, entries: categoryEntries });
@@ -464,7 +476,8 @@ async function categorizeEntries(provider, entries, context) {
464
476
  }
465
477
  } else {
466
478
  const categoryMap = parsed;
467
- for (const [category, indices] of Object.entries(categoryMap)) {
479
+ for (const [category, rawIndices] of Object.entries(categoryMap)) {
480
+ const indices = Array.isArray(rawIndices) ? rawIndices : [];
468
481
  const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
469
482
  if (categoryEntries.length > 0) {
470
483
  result.push({ category, entries: categoryEntries });
@@ -522,6 +535,113 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
522
535
  return results;
523
536
  }
524
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
+
525
645
  // src/llm/tasks/release-notes.ts
526
646
  var RELEASE_NOTES_PROMPT = `You are writing release notes for a software project.
527
647
 
@@ -622,12 +742,12 @@ function createProvider(config) {
622
742
 
623
743
  // src/output/github-release.ts
624
744
  var import_rest = require("@octokit/rest");
625
- var import_core5 = require("@releasekit/core");
745
+ var import_core6 = require("@releasekit/core");
626
746
 
627
747
  // src/output/markdown.ts
628
748
  var fs2 = __toESM(require("fs"), 1);
629
749
  var path = __toESM(require("path"), 1);
630
- var import_core4 = require("@releasekit/core");
750
+ var import_core5 = require("@releasekit/core");
631
751
  var TYPE_ORDER = ["added", "changed", "deprecated", "removed", "fixed", "security"];
632
752
  var TYPE_LABELS = {
633
753
  added: "Added",
@@ -726,15 +846,19 @@ ${body}`;
726
846
  function writeMarkdown(outputPath, contexts, config, dryRun) {
727
847
  const content = renderMarkdown(contexts);
728
848
  if (dryRun) {
729
- (0, import_core4.info)("--- Changelog Preview ---");
849
+ (0, import_core5.info)("--- Changelog Preview ---");
730
850
  console.log(content);
731
- (0, import_core4.info)("--- End Preview ---");
851
+ (0, import_core5.info)("--- End Preview ---");
732
852
  return;
733
853
  }
734
854
  const dir = path.dirname(outputPath);
735
855
  if (!fs2.existsSync(dir)) {
736
856
  fs2.mkdirSync(dir, { recursive: true });
737
857
  }
858
+ if (outputPath === "-") {
859
+ process.stdout.write(content);
860
+ return;
861
+ }
738
862
  if (config.updateStrategy === "prepend" && fs2.existsSync(outputPath) && contexts.length === 1) {
739
863
  const firstContext = contexts[0];
740
864
  if (firstContext) {
@@ -744,7 +868,7 @@ function writeMarkdown(outputPath, contexts, config, dryRun) {
744
868
  } else {
745
869
  fs2.writeFileSync(outputPath, content, "utf-8");
746
870
  }
747
- (0, import_core4.success)(`Changelog written to ${outputPath}`);
871
+ (0, import_core5.success)(`Changelog written to ${outputPath}`);
748
872
  }
749
873
 
750
874
  // src/output/github-release.ts
@@ -769,7 +893,7 @@ var GitHubClient = class {
769
893
  } else {
770
894
  body = renderMarkdown([context]);
771
895
  }
772
- (0, import_core5.info)(`Creating GitHub release for ${tagName}`);
896
+ (0, import_core6.info)(`Creating GitHub release for ${tagName}`);
773
897
  try {
774
898
  const response = await this.octokit.repos.createRelease({
775
899
  owner: this.owner,
@@ -781,7 +905,7 @@ var GitHubClient = class {
781
905
  prerelease: options.prerelease ?? false,
782
906
  generate_release_notes: options.generateNotes ?? false
783
907
  });
784
- (0, import_core5.success)(`Release created: ${response.data.html_url}`);
908
+ (0, import_core6.success)(`Release created: ${response.data.html_url}`);
785
909
  return {
786
910
  id: response.data.id,
787
911
  htmlUrl: response.data.html_url,
@@ -799,7 +923,7 @@ var GitHubClient = class {
799
923
  } else {
800
924
  body = renderMarkdown([context]);
801
925
  }
802
- (0, import_core5.info)(`Updating GitHub release ${releaseId}`);
926
+ (0, import_core6.info)(`Updating GitHub release ${releaseId}`);
803
927
  try {
804
928
  const response = await this.octokit.repos.updateRelease({
805
929
  owner: this.owner,
@@ -811,7 +935,7 @@ var GitHubClient = class {
811
935
  draft: options.draft ?? false,
812
936
  prerelease: options.prerelease ?? false
813
937
  });
814
- (0, import_core5.success)(`Release updated: ${response.data.html_url}`);
938
+ (0, import_core6.success)(`Release updated: ${response.data.html_url}`);
815
939
  return {
816
940
  id: response.data.id,
817
941
  htmlUrl: response.data.html_url,
@@ -863,7 +987,7 @@ async function createGitHubRelease(context, options) {
863
987
  // src/output/json.ts
864
988
  var fs3 = __toESM(require("fs"), 1);
865
989
  var path2 = __toESM(require("path"), 1);
866
- var import_core6 = require("@releasekit/core");
990
+ var import_core7 = require("@releasekit/core");
867
991
  function renderJson(contexts) {
868
992
  return JSON.stringify(
869
993
  {
@@ -883,9 +1007,9 @@ function renderJson(contexts) {
883
1007
  function writeJson(outputPath, contexts, dryRun) {
884
1008
  const content = renderJson(contexts);
885
1009
  if (dryRun) {
886
- (0, import_core6.info)("--- JSON Output Preview ---");
1010
+ (0, import_core7.info)("--- JSON Output Preview ---");
887
1011
  console.log(content);
888
- (0, import_core6.info)("--- End Preview ---");
1012
+ (0, import_core7.info)("--- End Preview ---");
889
1013
  return;
890
1014
  }
891
1015
  const dir = path2.dirname(outputPath);
@@ -893,7 +1017,7 @@ function writeJson(outputPath, contexts, dryRun) {
893
1017
  fs3.mkdirSync(dir, { recursive: true });
894
1018
  }
895
1019
  fs3.writeFileSync(outputPath, content, "utf-8");
896
- (0, import_core6.success)(`JSON output written to ${outputPath}`);
1020
+ (0, import_core7.success)(`JSON output written to ${outputPath}`);
897
1021
  }
898
1022
 
899
1023
  // src/templates/ejs.ts
@@ -1150,41 +1274,24 @@ function renderTemplate(templatePath, context, engine) {
1150
1274
  return renderComposable(templatePath, context, engine);
1151
1275
  }
1152
1276
 
1153
- // src/utils/retry.ts
1154
- function sleep(ms) {
1155
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1156
- }
1157
- async function withRetry(fn, options = {}) {
1158
- const maxAttempts = options.maxAttempts ?? 3;
1159
- const initialDelay = options.initialDelay ?? 1e3;
1160
- const maxDelay = options.maxDelay ?? 3e4;
1161
- const backoffFactor = options.backoffFactor ?? 2;
1162
- let lastError;
1163
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1164
- try {
1165
- return await fn();
1166
- } catch (error) {
1167
- lastError = error;
1168
- if (attempt < maxAttempts - 1) {
1169
- const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
1170
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
1171
- await sleep(Math.max(0, base + jitter));
1172
- }
1173
- }
1174
- }
1175
- throw lastError;
1176
- }
1177
-
1178
1277
  // src/core/pipeline.ts
1179
1278
  var import_meta = {};
1279
+ function extractVersionFromTag(tag) {
1280
+ if (tag.includes("@") && !tag.startsWith("@")) {
1281
+ return tag;
1282
+ }
1283
+ return tag.replace(/^v/, "");
1284
+ }
1180
1285
  function generateCompareUrl(repoUrl, from, to) {
1286
+ const fromVersion = extractVersionFromTag(from);
1287
+ const toVersion = extractVersionFromTag(to);
1181
1288
  if (/gitlab\.com/i.test(repoUrl)) {
1182
- return `${repoUrl}/-/compare/${from}...${to}`;
1289
+ return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
1183
1290
  }
1184
1291
  if (/bitbucket\.org/i.test(repoUrl)) {
1185
- return `${repoUrl}/branches/compare/${from}..${to}`;
1292
+ return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
1186
1293
  }
1187
- return `${repoUrl}/compare/${from}...${to}`;
1294
+ return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
1188
1295
  }
1189
1296
  function createTemplateContext(pkg) {
1190
1297
  const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
@@ -1231,9 +1338,9 @@ async function processWithLLM(context, config) {
1231
1338
  entries: context.entries
1232
1339
  };
1233
1340
  try {
1234
- (0, import_core7.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1341
+ (0, import_core8.info)(`Using LLM provider: ${config.llm.provider}${config.llm.model ? ` (${config.llm.model})` : ""}`);
1235
1342
  if (config.llm.baseURL) {
1236
- (0, import_core7.info)(`LLM base URL: ${config.llm.baseURL}`);
1343
+ (0, import_core8.info)(`LLM base URL: ${config.llm.baseURL}`);
1237
1344
  }
1238
1345
  const rawProvider = createProvider(config.llm);
1239
1346
  const retryOpts = config.llm.retry ?? LLM_DEFAULTS.retry;
@@ -1242,38 +1349,49 @@ async function processWithLLM(context, config) {
1242
1349
  complete: (prompt, opts) => withRetry(() => rawProvider.complete(prompt, opts), retryOpts)
1243
1350
  };
1244
1351
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1245
- (0, import_core7.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1246
- if (tasks.enhance) {
1247
- (0, import_core7.info)("Enhancing entries with LLM...");
1248
- enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1249
- (0, import_core7.info)(`Enhanced ${enhanced.entries.length} entries`);
1352
+ (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1353
+ if (tasks.enhance && tasks.categorize) {
1354
+ (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1355
+ const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1356
+ enhanced.entries = result.enhancedEntries;
1357
+ enhanced.categories = {};
1358
+ for (const cat of result.categories) {
1359
+ enhanced.categories[cat.category] = cat.entries;
1360
+ }
1361
+ (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries into ${result.categories.length} categories`);
1362
+ } else {
1363
+ if (tasks.enhance) {
1364
+ (0, import_core8.info)("Enhancing entries with LLM...");
1365
+ enhanced.entries = await enhanceEntries(provider, context.entries, llmContext, config.llm.concurrency);
1366
+ (0, import_core8.info)(`Enhanced ${enhanced.entries.length} entries`);
1367
+ }
1368
+ if (tasks.categorize) {
1369
+ (0, import_core8.info)("Categorizing entries with LLM...");
1370
+ const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1371
+ enhanced.categories = {};
1372
+ for (const cat of categorized) {
1373
+ enhanced.categories[cat.category] = cat.entries;
1374
+ }
1375
+ (0, import_core8.info)(`Created ${categorized.length} categories`);
1376
+ }
1250
1377
  }
1251
1378
  if (tasks.summarize) {
1252
- (0, import_core7.info)("Summarizing entries with LLM...");
1379
+ (0, import_core8.info)("Summarizing entries with LLM...");
1253
1380
  enhanced.summary = await summarizeEntries(provider, enhanced.entries, llmContext);
1254
1381
  if (enhanced.summary) {
1255
- (0, import_core7.info)("Summary generated successfully");
1256
- (0, import_core7.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1382
+ (0, import_core8.info)("Summary generated successfully");
1383
+ (0, import_core8.debug)(`Summary: ${enhanced.summary.substring(0, 100)}...`);
1257
1384
  } else {
1258
- (0, import_core7.warn)("Summary generation returned empty result");
1259
- }
1260
- }
1261
- if (tasks.categorize) {
1262
- (0, import_core7.info)("Categorizing entries with LLM...");
1263
- const categorized = await categorizeEntries(provider, enhanced.entries, llmContext);
1264
- enhanced.categories = {};
1265
- for (const cat of categorized) {
1266
- enhanced.categories[cat.category] = cat.entries;
1385
+ (0, import_core8.warn)("Summary generation returned empty result");
1267
1386
  }
1268
- (0, import_core7.info)(`Created ${categorized.length} categories`);
1269
1387
  }
1270
1388
  if (tasks.releaseNotes) {
1271
- (0, import_core7.info)("Generating release notes with LLM...");
1389
+ (0, import_core8.info)("Generating release notes with LLM...");
1272
1390
  enhanced.releaseNotes = await generateReleaseNotes(provider, enhanced.entries, llmContext);
1273
1391
  if (enhanced.releaseNotes) {
1274
- (0, import_core7.info)("Release notes generated successfully");
1392
+ (0, import_core8.info)("Release notes generated successfully");
1275
1393
  } else {
1276
- (0, import_core7.warn)("Release notes generation returned empty result");
1394
+ (0, import_core8.warn)("Release notes generation returned empty result");
1277
1395
  }
1278
1396
  }
1279
1397
  return {
@@ -1282,8 +1400,8 @@ async function processWithLLM(context, config) {
1282
1400
  enhanced
1283
1401
  };
1284
1402
  } catch (error) {
1285
- (0, import_core7.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1286
- (0, import_core7.warn)("Falling back to raw entries");
1403
+ (0, import_core8.warn)(`LLM processing failed: ${error instanceof Error ? error.message : String(error)}`);
1404
+ (0, import_core8.warn)("Falling back to raw entries");
1287
1405
  return context;
1288
1406
  }
1289
1407
  }
@@ -1311,9 +1429,13 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1311
1429
  );
1312
1430
  const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
1313
1431
  if (dryRun) {
1314
- (0, import_core7.info)("--- Changelog Preview ---");
1432
+ (0, import_core8.info)("--- Changelog Preview ---");
1315
1433
  console.log(result.content);
1316
- (0, import_core7.info)("--- End Preview ---");
1434
+ (0, import_core8.info)("--- End Preview ---");
1435
+ return;
1436
+ }
1437
+ if (outputPath === "-") {
1438
+ process.stdout.write(result.content);
1317
1439
  return;
1318
1440
  }
1319
1441
  const dir = path6.dirname(outputPath);
@@ -1321,17 +1443,17 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
1321
1443
  fs8.mkdirSync(dir, { recursive: true });
1322
1444
  }
1323
1445
  fs8.writeFileSync(outputPath, result.content, "utf-8");
1324
- (0, import_core7.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1446
+ (0, import_core8.success)(`Changelog written to ${outputPath} (using ${result.engine} template)`);
1325
1447
  }
1326
1448
  async function runPipeline(input, config, dryRun) {
1327
- (0, import_core7.debug)(`Processing ${input.packages.length} package(s)`);
1449
+ (0, import_core8.debug)(`Processing ${input.packages.length} package(s)`);
1328
1450
  let contexts = input.packages.map(createTemplateContext);
1329
1451
  if (config.llm && !process.env.CHANGELOG_NO_LLM) {
1330
- (0, import_core7.info)("Processing with LLM enhancement");
1452
+ (0, import_core8.info)("Processing with LLM enhancement");
1331
1453
  contexts = await Promise.all(contexts.map((ctx) => processWithLLM(ctx, config)));
1332
1454
  }
1333
1455
  for (const output of config.output) {
1334
- (0, import_core7.info)(`Generating ${output.format} output`);
1456
+ (0, import_core8.info)(`Generating ${output.format} output`);
1335
1457
  switch (output.format) {
1336
1458
  case "markdown": {
1337
1459
  const file = output.file ?? "CHANGELOG.md";
@@ -1349,22 +1471,22 @@ async function runPipeline(input, config, dryRun) {
1349
1471
  }
1350
1472
  case "github-release": {
1351
1473
  if (dryRun) {
1352
- (0, import_core7.info)("[DRY RUN] Would create GitHub release");
1474
+ (0, import_core8.info)("[DRY RUN] Would create GitHub release");
1353
1475
  break;
1354
1476
  }
1355
1477
  const firstContext = contexts[0];
1356
1478
  if (!firstContext) {
1357
- (0, import_core7.warn)("No context available for GitHub release");
1479
+ (0, import_core8.warn)("No context available for GitHub release");
1358
1480
  break;
1359
1481
  }
1360
1482
  const repoUrl = firstContext.repoUrl;
1361
1483
  if (!repoUrl) {
1362
- (0, import_core7.warn)("No repo URL available, cannot create GitHub release");
1484
+ (0, import_core8.warn)("No repo URL available, cannot create GitHub release");
1363
1485
  break;
1364
1486
  }
1365
1487
  const parsed = parseRepoUrl(repoUrl);
1366
1488
  if (!parsed) {
1367
- (0, import_core7.warn)(`Could not parse repo URL: ${repoUrl}`);
1489
+ (0, import_core8.warn)(`Could not parse repo URL: ${repoUrl}`);
1368
1490
  break;
1369
1491
  }
1370
1492
  await createGitHubRelease(firstContext, {
@@ -1386,7 +1508,7 @@ async function processInput(inputJson, config, dryRun) {
1386
1508
  // src/monorepo/aggregator.ts
1387
1509
  var fs9 = __toESM(require("fs"), 1);
1388
1510
  var path7 = __toESM(require("path"), 1);
1389
- var import_core8 = require("@releasekit/core");
1511
+ var import_core9 = require("@releasekit/core");
1390
1512
 
1391
1513
  // src/monorepo/splitter.ts
1392
1514
  function splitByPackage(contexts) {
@@ -1400,7 +1522,7 @@ function splitByPackage(contexts) {
1400
1522
  // src/monorepo/aggregator.ts
1401
1523
  function writeFile(outputPath, content, dryRun) {
1402
1524
  if (dryRun) {
1403
- (0, import_core8.info)(`[DRY RUN] Would write to ${outputPath}`);
1525
+ (0, import_core9.info)(`[DRY RUN] Would write to ${outputPath}`);
1404
1526
  console.log(content);
1405
1527
  return;
1406
1528
  }
@@ -1409,7 +1531,7 @@ function writeFile(outputPath, content, dryRun) {
1409
1531
  fs9.mkdirSync(dir, { recursive: true });
1410
1532
  }
1411
1533
  fs9.writeFileSync(outputPath, content, "utf-8");
1412
- (0, import_core8.success)(`Changelog written to ${outputPath}`);
1534
+ (0, import_core9.success)(`Changelog written to ${outputPath}`);
1413
1535
  }
1414
1536
  function aggregateToRoot(contexts) {
1415
1537
  const aggregated = {
@@ -1434,7 +1556,7 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1434
1556
  if (options.mode === "root" || options.mode === "both") {
1435
1557
  const aggregated = aggregateToRoot(contexts);
1436
1558
  const rootPath = path7.join(options.rootPath, "CHANGELOG.md");
1437
- (0, import_core8.info)(`Writing root changelog to ${rootPath}`);
1559
+ (0, import_core9.info)(`Writing root changelog to ${rootPath}`);
1438
1560
  const rootContent = config.updateStrategy === "prepend" && fs9.existsSync(rootPath) ? prependVersion(rootPath, aggregated) : renderMarkdown([aggregated]);
1439
1561
  writeFile(rootPath, rootContent, dryRun);
1440
1562
  }
@@ -1446,11 +1568,11 @@ function writeMonorepoChangelogs(contexts, options, config, dryRun) {
1446
1568
  const packageDir = packageDirMap.get(packageName) ?? (simpleName ? packageDirMap.get(simpleName) : void 0) ?? null;
1447
1569
  if (packageDir) {
1448
1570
  const changelogPath = path7.join(packageDir, "CHANGELOG.md");
1449
- (0, import_core8.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1571
+ (0, import_core9.info)(`Writing changelog for ${packageName} to ${changelogPath}`);
1450
1572
  const pkgContent = config.updateStrategy === "prepend" && fs9.existsSync(changelogPath) ? prependVersion(changelogPath, ctx) : renderMarkdown([ctx]);
1451
1573
  writeFile(changelogPath, pkgContent, dryRun);
1452
1574
  } else {
1453
- (0, import_core8.info)(`Could not find directory for package ${packageName}, skipping`);
1575
+ (0, import_core9.info)(`Could not find directory for package ${packageName}, skipping`);
1454
1576
  }
1455
1577
  }
1456
1578
  }
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  writeJson,
25
25
  writeMarkdown,
26
26
  writeMonorepoChangelogs
27
- } from "./chunk-NHDLQLG2.js";
27
+ } from "./chunk-ACXCEHQT.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.0",
3
+ "version": "0.2.0-next.10",
4
4
  "description": "Changelog generation with LLM-powered enhancement and flexible templating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",