@releasekit/notes 0.2.0-next.5 → 0.2.0-next.7

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.
@@ -520,15 +520,26 @@ Entries:
520
520
  Output only valid JSON, nothing else:`;
521
521
  function buildCustomCategorizePrompt(categories) {
522
522
  const categoryList = categories.map((c) => `- "${c.name}": ${c.description}`).join("\n");
523
+ const developerCategory = categories.find((c) => c.name === "Developer");
524
+ let scopeInstructions = "";
525
+ if (developerCategory) {
526
+ const scopeMatch = developerCategory.description.match(/from:\s*([^.]+)/);
527
+ if (scopeMatch?.[1]) {
528
+ const scopes = scopeMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
529
+ if (scopes.length > 0) {
530
+ scopeInstructions = `
531
+
532
+ For the "Developer" category, you MUST assign a scope from this exact list: ${scopes.join(", ")}.
533
+ `;
534
+ }
535
+ }
536
+ }
523
537
  return `You are categorizing changelog entries for a software release.
524
538
 
525
- Given the following entries, group them into the specified categories. Only use the categories listed below.
539
+ Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
526
540
 
527
541
  Categories:
528
- ${categoryList}
529
-
530
- 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").
531
-
542
+ ${categoryList}${scopeInstructions}
532
543
  Output a JSON object with two fields:
533
544
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
534
545
  - "scopes": an object where keys are entry indices (as strings) and values are scope labels
@@ -630,6 +641,33 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
630
641
 
631
642
  // src/llm/tasks/enhance-and-categorize.ts
632
643
  import { warn as warn2 } from "@releasekit/core";
644
+
645
+ // src/utils/retry.ts
646
+ function sleep(ms) {
647
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
648
+ }
649
+ async function withRetry(fn, options = {}) {
650
+ const maxAttempts = options.maxAttempts ?? 3;
651
+ const initialDelay = options.initialDelay ?? 1e3;
652
+ const maxDelay = options.maxDelay ?? 3e4;
653
+ const backoffFactor = options.backoffFactor ?? 2;
654
+ let lastError;
655
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
656
+ try {
657
+ return await fn();
658
+ } catch (error) {
659
+ lastError = error;
660
+ if (attempt < maxAttempts - 1) {
661
+ const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
662
+ const jitter = base * 0.2 * (Math.random() * 2 - 1);
663
+ await sleep(Math.max(0, base + jitter));
664
+ }
665
+ }
666
+ }
667
+ throw lastError;
668
+ }
669
+
670
+ // src/llm/tasks/enhance-and-categorize.ts
633
671
  function buildPrompt(entries, categories, style) {
634
672
  const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
635
673
  const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
@@ -661,41 +699,46 @@ async function enhanceAndCategorize(provider, entries, context) {
661
699
  if (entries.length === 0) {
662
700
  return { enhancedEntries: [], categories: [] };
663
701
  }
664
- const prompt = buildPrompt(entries, context.categories, context.style);
702
+ const retryOpts = LLM_DEFAULTS.retry;
665
703
  try {
666
- const response = await provider.complete(prompt);
667
- const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
668
- const parsed = JSON.parse(cleaned);
669
- if (!Array.isArray(parsed.entries)) {
670
- throw new Error('Response missing "entries" array');
671
- }
672
- const enhancedEntries = entries.map((original, i) => {
673
- const result = parsed.entries[i];
674
- if (!result) return original;
675
- return {
676
- ...original,
677
- description: result.description || original.description,
678
- scope: result.scope || original.scope
679
- };
680
- });
681
- const categoryMap = /* @__PURE__ */ new Map();
682
- for (let i = 0; i < parsed.entries.length; i++) {
683
- const result = parsed.entries[i];
684
- const category = result?.category || "General";
685
- const entry = enhancedEntries[i];
686
- if (!entry) continue;
687
- if (!categoryMap.has(category)) {
688
- categoryMap.set(category, []);
704
+ return await withRetry(async () => {
705
+ const prompt = buildPrompt(entries, context.categories, context.style);
706
+ const response = await provider.complete(prompt);
707
+ const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
708
+ const parsed = JSON.parse(cleaned);
709
+ if (!Array.isArray(parsed.entries)) {
710
+ throw new Error('Response missing "entries" array');
689
711
  }
690
- categoryMap.get(category).push(entry);
691
- }
692
- const categories = [];
693
- for (const [category, catEntries] of categoryMap) {
694
- categories.push({ category, entries: catEntries });
695
- }
696
- return { enhancedEntries, categories };
712
+ const enhancedEntries = entries.map((original, i) => {
713
+ const result = parsed.entries[i];
714
+ if (!result) return original;
715
+ return {
716
+ ...original,
717
+ description: result.description || original.description,
718
+ scope: result.scope || original.scope
719
+ };
720
+ });
721
+ const categoryMap = /* @__PURE__ */ new Map();
722
+ for (let i = 0; i < parsed.entries.length; i++) {
723
+ const result = parsed.entries[i];
724
+ const category = result?.category || "General";
725
+ const entry = enhancedEntries[i];
726
+ if (!entry) continue;
727
+ if (!categoryMap.has(category)) {
728
+ categoryMap.set(category, []);
729
+ }
730
+ categoryMap.get(category).push(entry);
731
+ }
732
+ const categories = [];
733
+ for (const [category, catEntries] of categoryMap) {
734
+ categories.push({ category, entries: catEntries });
735
+ }
736
+ return { enhancedEntries, categories };
737
+ }, retryOpts);
697
738
  } catch (error) {
698
- warn2(`Combined enhance+categorize failed: ${error instanceof Error ? error.message : String(error)}`);
739
+ warn2(
740
+ `Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error instanceof Error ? error.message : String(error)}`
741
+ );
699
742
  return {
700
743
  enhancedEntries: entries,
701
744
  categories: [{ category: "General", entries }]
@@ -1170,31 +1213,6 @@ function renderTemplate(templatePath, context, engine) {
1170
1213
  return renderComposable(templatePath, context, engine);
1171
1214
  }
1172
1215
 
1173
- // src/utils/retry.ts
1174
- function sleep(ms) {
1175
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1176
- }
1177
- async function withRetry(fn, options = {}) {
1178
- const maxAttempts = options.maxAttempts ?? 3;
1179
- const initialDelay = options.initialDelay ?? 1e3;
1180
- const maxDelay = options.maxDelay ?? 3e4;
1181
- const backoffFactor = options.backoffFactor ?? 2;
1182
- let lastError;
1183
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1184
- try {
1185
- return await fn();
1186
- } catch (error) {
1187
- lastError = error;
1188
- if (attempt < maxAttempts - 1) {
1189
- const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
1190
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
1191
- await sleep(Math.max(0, base + jitter));
1192
- }
1193
- }
1194
- }
1195
- throw lastError;
1196
- }
1197
-
1198
1216
  // src/core/pipeline.ts
1199
1217
  function generateCompareUrl(repoUrl, from, to) {
1200
1218
  if (/gitlab\.com/i.test(repoUrl)) {
@@ -1263,7 +1281,7 @@ async function processWithLLM(context, config) {
1263
1281
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1264
1282
  info4(`Running LLM tasks: ${activeTasks.join(", ")}`);
1265
1283
  if (tasks.enhance && tasks.categorize) {
1266
- info4("Enhancing and categorizing entries with LLM (single call)...");
1284
+ info4("Enhancing and categorizing entries with LLM...");
1267
1285
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1268
1286
  enhanced.entries = result.enhancedEntries;
1269
1287
  enhanced.categories = {};
package/dist/cli.cjs CHANGED
@@ -366,15 +366,26 @@ Entries:
366
366
  Output only valid JSON, nothing else:`;
367
367
  function buildCustomCategorizePrompt(categories) {
368
368
  const categoryList = categories.map((c) => `- "${c.name}": ${c.description}`).join("\n");
369
+ const developerCategory = categories.find((c) => c.name === "Developer");
370
+ let scopeInstructions = "";
371
+ if (developerCategory) {
372
+ const scopeMatch = developerCategory.description.match(/from:\s*([^.]+)/);
373
+ if (scopeMatch?.[1]) {
374
+ const scopes = scopeMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
375
+ if (scopes.length > 0) {
376
+ scopeInstructions = `
377
+
378
+ For the "Developer" category, you MUST assign a scope from this exact list: ${scopes.join(", ")}.
379
+ `;
380
+ }
381
+ }
382
+ }
369
383
  return `You are categorizing changelog entries for a software release.
370
384
 
371
- Given the following entries, group them into the specified categories. Only use the categories listed below.
385
+ Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
372
386
 
373
387
  Categories:
374
- ${categoryList}
375
-
376
- 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").
377
-
388
+ ${categoryList}${scopeInstructions}
378
389
  Output a JSON object with two fields:
379
390
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
380
391
  - "scopes": an object where keys are entry indices (as strings) and values are scope labels
@@ -476,6 +487,33 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
476
487
 
477
488
  // src/llm/tasks/enhance-and-categorize.ts
478
489
  var import_core4 = require("@releasekit/core");
490
+
491
+ // src/utils/retry.ts
492
+ function sleep(ms) {
493
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
494
+ }
495
+ async function withRetry(fn, options = {}) {
496
+ const maxAttempts = options.maxAttempts ?? 3;
497
+ const initialDelay = options.initialDelay ?? 1e3;
498
+ const maxDelay = options.maxDelay ?? 3e4;
499
+ const backoffFactor = options.backoffFactor ?? 2;
500
+ let lastError;
501
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
502
+ try {
503
+ return await fn();
504
+ } catch (error2) {
505
+ lastError = error2;
506
+ if (attempt < maxAttempts - 1) {
507
+ const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
508
+ const jitter = base * 0.2 * (Math.random() * 2 - 1);
509
+ await sleep(Math.max(0, base + jitter));
510
+ }
511
+ }
512
+ }
513
+ throw lastError;
514
+ }
515
+
516
+ // src/llm/tasks/enhance-and-categorize.ts
479
517
  function buildPrompt(entries, categories, style) {
480
518
  const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
481
519
  const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
@@ -507,41 +545,46 @@ async function enhanceAndCategorize(provider, entries, context) {
507
545
  if (entries.length === 0) {
508
546
  return { enhancedEntries: [], categories: [] };
509
547
  }
510
- const prompt = buildPrompt(entries, context.categories, context.style);
548
+ const retryOpts = LLM_DEFAULTS.retry;
511
549
  try {
512
- const response = await provider.complete(prompt);
513
- const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
514
- const parsed = JSON.parse(cleaned);
515
- if (!Array.isArray(parsed.entries)) {
516
- throw new Error('Response missing "entries" array');
517
- }
518
- const enhancedEntries = entries.map((original, i) => {
519
- const result = parsed.entries[i];
520
- if (!result) return original;
521
- return {
522
- ...original,
523
- description: result.description || original.description,
524
- scope: result.scope || original.scope
525
- };
526
- });
527
- const categoryMap = /* @__PURE__ */ new Map();
528
- for (let i = 0; i < parsed.entries.length; i++) {
529
- const result = parsed.entries[i];
530
- const category = result?.category || "General";
531
- const entry = enhancedEntries[i];
532
- if (!entry) continue;
533
- if (!categoryMap.has(category)) {
534
- categoryMap.set(category, []);
550
+ return await withRetry(async () => {
551
+ const prompt = buildPrompt(entries, context.categories, context.style);
552
+ const response = await provider.complete(prompt);
553
+ const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
554
+ const parsed = JSON.parse(cleaned);
555
+ if (!Array.isArray(parsed.entries)) {
556
+ throw new Error('Response missing "entries" array');
535
557
  }
536
- categoryMap.get(category).push(entry);
537
- }
538
- const categories = [];
539
- for (const [category, catEntries] of categoryMap) {
540
- categories.push({ category, entries: catEntries });
541
- }
542
- return { enhancedEntries, categories };
558
+ const enhancedEntries = entries.map((original, i) => {
559
+ const result = parsed.entries[i];
560
+ if (!result) return original;
561
+ return {
562
+ ...original,
563
+ description: result.description || original.description,
564
+ scope: result.scope || original.scope
565
+ };
566
+ });
567
+ const categoryMap = /* @__PURE__ */ new Map();
568
+ for (let i = 0; i < parsed.entries.length; i++) {
569
+ const result = parsed.entries[i];
570
+ const category = result?.category || "General";
571
+ const entry = enhancedEntries[i];
572
+ if (!entry) continue;
573
+ if (!categoryMap.has(category)) {
574
+ categoryMap.set(category, []);
575
+ }
576
+ categoryMap.get(category).push(entry);
577
+ }
578
+ const categories = [];
579
+ for (const [category, catEntries] of categoryMap) {
580
+ categories.push({ category, entries: catEntries });
581
+ }
582
+ return { enhancedEntries, categories };
583
+ }, retryOpts);
543
584
  } catch (error2) {
544
- (0, import_core4.warn)(`Combined enhance+categorize failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
585
+ (0, import_core4.warn)(
586
+ `Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error2 instanceof Error ? error2.message : String(error2)}`
587
+ );
545
588
  return {
546
589
  enhancedEntries: entries,
547
590
  categories: [{ category: "General", entries }]
@@ -1181,31 +1224,6 @@ function renderTemplate(templatePath, context, engine) {
1181
1224
  return renderComposable(templatePath, context, engine);
1182
1225
  }
1183
1226
 
1184
- // src/utils/retry.ts
1185
- function sleep(ms) {
1186
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1187
- }
1188
- async function withRetry(fn, options = {}) {
1189
- const maxAttempts = options.maxAttempts ?? 3;
1190
- const initialDelay = options.initialDelay ?? 1e3;
1191
- const maxDelay = options.maxDelay ?? 3e4;
1192
- const backoffFactor = options.backoffFactor ?? 2;
1193
- let lastError;
1194
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1195
- try {
1196
- return await fn();
1197
- } catch (error2) {
1198
- lastError = error2;
1199
- if (attempt < maxAttempts - 1) {
1200
- const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
1201
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
1202
- await sleep(Math.max(0, base + jitter));
1203
- }
1204
- }
1205
- }
1206
- throw lastError;
1207
- }
1208
-
1209
1227
  // src/core/pipeline.ts
1210
1228
  var import_meta = {};
1211
1229
  function generateCompareUrl(repoUrl, from, to) {
@@ -1275,7 +1293,7 @@ async function processWithLLM(context, config) {
1275
1293
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1276
1294
  (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1277
1295
  if (tasks.enhance && tasks.categorize) {
1278
- (0, import_core8.info)("Enhancing and categorizing entries with LLM (single call)...");
1296
+ (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1279
1297
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1280
1298
  enhanced.entries = result.enhancedEntries;
1281
1299
  enhanced.categories = {};
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runPipeline,
12
12
  saveAuth,
13
13
  writeMonorepoChangelogs
14
- } from "./chunk-ADZJSWND.js";
14
+ } from "./chunk-BLWJTLRD.js";
15
15
 
16
16
  // src/cli.ts
17
17
  import * as fs from "fs";
package/dist/index.cjs CHANGED
@@ -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
@@ -526,6 +537,33 @@ async function enhanceEntries(provider, entries, context, concurrency = LLM_DEFA
526
537
 
527
538
  // src/llm/tasks/enhance-and-categorize.ts
528
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
529
567
  function buildPrompt(entries, categories, style) {
530
568
  const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
531
569
  const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
@@ -557,41 +595,46 @@ async function enhanceAndCategorize(provider, entries, context) {
557
595
  if (entries.length === 0) {
558
596
  return { enhancedEntries: [], categories: [] };
559
597
  }
560
- const prompt = buildPrompt(entries, context.categories, context.style);
598
+ const retryOpts = LLM_DEFAULTS.retry;
561
599
  try {
562
- const response = await provider.complete(prompt);
563
- const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
564
- const parsed = JSON.parse(cleaned);
565
- if (!Array.isArray(parsed.entries)) {
566
- throw new Error('Response missing "entries" array');
567
- }
568
- const enhancedEntries = entries.map((original, i) => {
569
- const result = parsed.entries[i];
570
- if (!result) return original;
571
- return {
572
- ...original,
573
- description: result.description || original.description,
574
- scope: result.scope || original.scope
575
- };
576
- });
577
- const categoryMap = /* @__PURE__ */ new Map();
578
- for (let i = 0; i < parsed.entries.length; i++) {
579
- const result = parsed.entries[i];
580
- const category = result?.category || "General";
581
- const entry = enhancedEntries[i];
582
- if (!entry) continue;
583
- if (!categoryMap.has(category)) {
584
- categoryMap.set(category, []);
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');
585
607
  }
586
- categoryMap.get(category).push(entry);
587
- }
588
- const categories = [];
589
- for (const [category, catEntries] of categoryMap) {
590
- categories.push({ category, entries: catEntries });
591
- }
592
- return { enhancedEntries, categories };
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);
593
634
  } catch (error) {
594
- (0, import_core4.warn)(`Combined enhance+categorize failed: ${error instanceof Error ? error.message : String(error)}`);
635
+ (0, import_core4.warn)(
636
+ `Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error instanceof Error ? error.message : String(error)}`
637
+ );
595
638
  return {
596
639
  enhancedEntries: entries,
597
640
  categories: [{ category: "General", entries }]
@@ -1231,31 +1274,6 @@ function renderTemplate(templatePath, context, engine) {
1231
1274
  return renderComposable(templatePath, context, engine);
1232
1275
  }
1233
1276
 
1234
- // src/utils/retry.ts
1235
- function sleep(ms) {
1236
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1237
- }
1238
- async function withRetry(fn, options = {}) {
1239
- const maxAttempts = options.maxAttempts ?? 3;
1240
- const initialDelay = options.initialDelay ?? 1e3;
1241
- const maxDelay = options.maxDelay ?? 3e4;
1242
- const backoffFactor = options.backoffFactor ?? 2;
1243
- let lastError;
1244
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
1245
- try {
1246
- return await fn();
1247
- } catch (error) {
1248
- lastError = error;
1249
- if (attempt < maxAttempts - 1) {
1250
- const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
1251
- const jitter = base * 0.2 * (Math.random() * 2 - 1);
1252
- await sleep(Math.max(0, base + jitter));
1253
- }
1254
- }
1255
- }
1256
- throw lastError;
1257
- }
1258
-
1259
1277
  // src/core/pipeline.ts
1260
1278
  var import_meta = {};
1261
1279
  function generateCompareUrl(repoUrl, from, to) {
@@ -1325,7 +1343,7 @@ async function processWithLLM(context, config) {
1325
1343
  const activeTasks = Object.entries(tasks).filter(([, enabled]) => enabled).map(([name]) => name);
1326
1344
  (0, import_core8.info)(`Running LLM tasks: ${activeTasks.join(", ")}`);
1327
1345
  if (tasks.enhance && tasks.categorize) {
1328
- (0, import_core8.info)("Enhancing and categorizing entries with LLM (single call)...");
1346
+ (0, import_core8.info)("Enhancing and categorizing entries with LLM...");
1329
1347
  const result = await enhanceAndCategorize(provider, context.entries, llmContext);
1330
1348
  enhanced.entries = result.enhancedEntries;
1331
1349
  enhanced.categories = {};
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  writeJson,
25
25
  writeMarkdown,
26
26
  writeMonorepoChangelogs
27
- } from "./chunk-ADZJSWND.js";
27
+ } from "./chunk-BLWJTLRD.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.5",
3
+ "version": "0.2.0-next.7",
4
4
  "description": "Changelog generation with LLM-powered enhancement and flexible templating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",