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

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.
@@ -534,15 +534,18 @@ For the "Developer" category, you MUST assign a scope from this exact list: ${sc
534
534
  }
535
535
  }
536
536
  }
537
+ const scopeValidationInstructions = scopeInstructions ? `
538
+
539
+ IMPORTANT: When assigning scopes, you MUST ONLY use scopes from the predefined list above. DO NOT use scopes from conventional commit messages (like "version", "core", "api", etc.). If an entry does not fit any of the predefined scopes, leave the scope as null.` : "";
537
540
  return `You are categorizing changelog entries for a software release.
538
541
 
539
542
  Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
540
543
 
541
544
  Categories:
542
- ${categoryList}${scopeInstructions}
545
+ ${categoryList}${scopeInstructions}${scopeValidationInstructions}
543
546
  Output a JSON object with two fields:
544
547
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
545
- - "scopes": an object where keys are entry indices (as strings) and values are scope labels
548
+ - "scopes": an object where keys are entry indices (as strings) and values are scope labels. Only include entries that have a valid scope from the predefined list.
546
549
 
547
550
  Entries:
548
551
  {{entries}}
@@ -553,7 +556,8 @@ async function categorizeEntries(provider, entries, context) {
553
556
  if (entries.length === 0) {
554
557
  return [];
555
558
  }
556
- const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
559
+ const entriesCopy = entries.map((e) => ({ ...e, scope: void 0 }));
560
+ const entriesText = entriesCopy.map((e, i) => `${i}. [${e.type}]: ${e.description}`).join("\n");
557
561
  const hasCustomCategories = context.categories && context.categories.length > 0;
558
562
  const promptTemplate = hasCustomCategories ? buildCustomCategorizePrompt(context.categories) : DEFAULT_CATEGORIZE_PROMPT;
559
563
  const prompt = promptTemplate.replace("{{entries}}", entriesText);
@@ -567,13 +571,13 @@ async function categorizeEntries(provider, entries, context) {
567
571
  const scopeMap = parsed.scopes || {};
568
572
  for (const [indexStr, scope] of Object.entries(scopeMap)) {
569
573
  const idx = Number.parseInt(indexStr, 10);
570
- if (entries[idx] && scope) {
571
- entries[idx] = { ...entries[idx], scope };
574
+ if (entriesCopy[idx] && scope && scope.trim()) {
575
+ entriesCopy[idx] = { ...entriesCopy[idx], scope: scope.trim() };
572
576
  }
573
577
  }
574
578
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
575
579
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
576
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
580
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
577
581
  if (categoryEntries.length > 0) {
578
582
  result.push({ category, entries: categoryEntries });
579
583
  }
@@ -582,7 +586,7 @@ async function categorizeEntries(provider, entries, context) {
582
586
  const categoryMap = parsed;
583
587
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
584
588
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
585
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
589
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
586
590
  if (categoryEntries.length > 0) {
587
591
  result.push({ category, entries: categoryEntries });
588
592
  }
@@ -593,7 +597,7 @@ async function categorizeEntries(provider, entries, context) {
593
597
  warn(
594
598
  `LLM categorization failed, falling back to General: ${error instanceof Error ? error.message : String(error)}`
595
599
  );
596
- return [{ category: "General", entries }];
600
+ return [{ category: "General", entries: entriesCopy }];
597
601
  }
598
602
  }
599
603
 
@@ -727,7 +731,7 @@ async function enhanceAndCategorize(provider, entries, context) {
727
731
  if (!categoryMap.has(category)) {
728
732
  categoryMap.set(category, []);
729
733
  }
730
- categoryMap.get(category).push(entry);
734
+ categoryMap.get(category)?.push(entry);
731
735
  }
732
736
  const categories = [];
733
737
  for (const [category, catEntries] of categoryMap) {
@@ -1214,15 +1218,17 @@ function renderTemplate(templatePath, context, engine) {
1214
1218
  }
1215
1219
 
1216
1220
  // src/core/pipeline.ts
1217
- function extractVersionFromTag(tag) {
1218
- if (tag.includes("@") && !tag.startsWith("@")) {
1219
- return tag;
1221
+ function generateCompareUrl(repoUrl, from, to, packageName) {
1222
+ const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
1223
+ let fromVersion;
1224
+ let toVersion;
1225
+ if (isPackageSpecific) {
1226
+ fromVersion = from;
1227
+ toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
1228
+ } else {
1229
+ fromVersion = from.replace(/^v/, "");
1230
+ toVersion = to.replace(/^v/, "");
1220
1231
  }
1221
- return tag.replace(/^v/, "");
1222
- }
1223
- function generateCompareUrl(repoUrl, from, to) {
1224
- const fromVersion = extractVersionFromTag(from);
1225
- const toVersion = extractVersionFromTag(to);
1226
1232
  if (/gitlab\.com/i.test(repoUrl)) {
1227
1233
  return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
1228
1234
  }
@@ -1232,7 +1238,7 @@ function generateCompareUrl(repoUrl, from, to) {
1232
1238
  return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
1233
1239
  }
1234
1240
  function createTemplateContext(pkg) {
1235
- const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
1241
+ const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
1236
1242
  return {
1237
1243
  packageName: pkg.packageName,
1238
1244
  version: pkg.version,
package/dist/cli.cjs CHANGED
@@ -380,15 +380,18 @@ For the "Developer" category, you MUST assign a scope from this exact list: ${sc
380
380
  }
381
381
  }
382
382
  }
383
+ const scopeValidationInstructions = scopeInstructions ? `
384
+
385
+ IMPORTANT: When assigning scopes, you MUST ONLY use scopes from the predefined list above. DO NOT use scopes from conventional commit messages (like "version", "core", "api", etc.). If an entry does not fit any of the predefined scopes, leave the scope as null.` : "";
383
386
  return `You are categorizing changelog entries for a software release.
384
387
 
385
388
  Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
386
389
 
387
390
  Categories:
388
- ${categoryList}${scopeInstructions}
391
+ ${categoryList}${scopeInstructions}${scopeValidationInstructions}
389
392
  Output a JSON object with two fields:
390
393
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
391
- - "scopes": an object where keys are entry indices (as strings) and values are scope labels
394
+ - "scopes": an object where keys are entry indices (as strings) and values are scope labels. Only include entries that have a valid scope from the predefined list.
392
395
 
393
396
  Entries:
394
397
  {{entries}}
@@ -399,7 +402,8 @@ async function categorizeEntries(provider, entries, context) {
399
402
  if (entries.length === 0) {
400
403
  return [];
401
404
  }
402
- const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
405
+ const entriesCopy = entries.map((e) => ({ ...e, scope: void 0 }));
406
+ const entriesText = entriesCopy.map((e, i) => `${i}. [${e.type}]: ${e.description}`).join("\n");
403
407
  const hasCustomCategories = context.categories && context.categories.length > 0;
404
408
  const promptTemplate = hasCustomCategories ? buildCustomCategorizePrompt(context.categories) : DEFAULT_CATEGORIZE_PROMPT;
405
409
  const prompt = promptTemplate.replace("{{entries}}", entriesText);
@@ -413,13 +417,13 @@ async function categorizeEntries(provider, entries, context) {
413
417
  const scopeMap = parsed.scopes || {};
414
418
  for (const [indexStr, scope] of Object.entries(scopeMap)) {
415
419
  const idx = Number.parseInt(indexStr, 10);
416
- if (entries[idx] && scope) {
417
- entries[idx] = { ...entries[idx], scope };
420
+ if (entriesCopy[idx] && scope && scope.trim()) {
421
+ entriesCopy[idx] = { ...entriesCopy[idx], scope: scope.trim() };
418
422
  }
419
423
  }
420
424
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
421
425
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
422
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
426
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
423
427
  if (categoryEntries.length > 0) {
424
428
  result.push({ category, entries: categoryEntries });
425
429
  }
@@ -428,7 +432,7 @@ async function categorizeEntries(provider, entries, context) {
428
432
  const categoryMap = parsed;
429
433
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
430
434
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
431
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
435
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
432
436
  if (categoryEntries.length > 0) {
433
437
  result.push({ category, entries: categoryEntries });
434
438
  }
@@ -439,7 +443,7 @@ async function categorizeEntries(provider, entries, context) {
439
443
  (0, import_core3.warn)(
440
444
  `LLM categorization failed, falling back to General: ${error2 instanceof Error ? error2.message : String(error2)}`
441
445
  );
442
- return [{ category: "General", entries }];
446
+ return [{ category: "General", entries: entriesCopy }];
443
447
  }
444
448
  }
445
449
 
@@ -573,7 +577,7 @@ async function enhanceAndCategorize(provider, entries, context) {
573
577
  if (!categoryMap.has(category)) {
574
578
  categoryMap.set(category, []);
575
579
  }
576
- categoryMap.get(category).push(entry);
580
+ categoryMap.get(category)?.push(entry);
577
581
  }
578
582
  const categories = [];
579
583
  for (const [category, catEntries] of categoryMap) {
@@ -1226,15 +1230,17 @@ function renderTemplate(templatePath, context, engine) {
1226
1230
 
1227
1231
  // src/core/pipeline.ts
1228
1232
  var import_meta = {};
1229
- function extractVersionFromTag(tag) {
1230
- if (tag.includes("@") && !tag.startsWith("@")) {
1231
- return tag;
1233
+ function generateCompareUrl(repoUrl, from, to, packageName) {
1234
+ const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
1235
+ let fromVersion;
1236
+ let toVersion;
1237
+ if (isPackageSpecific) {
1238
+ fromVersion = from;
1239
+ toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
1240
+ } else {
1241
+ fromVersion = from.replace(/^v/, "");
1242
+ toVersion = to.replace(/^v/, "");
1232
1243
  }
1233
- return tag.replace(/^v/, "");
1234
- }
1235
- function generateCompareUrl(repoUrl, from, to) {
1236
- const fromVersion = extractVersionFromTag(from);
1237
- const toVersion = extractVersionFromTag(to);
1238
1244
  if (/gitlab\.com/i.test(repoUrl)) {
1239
1245
  return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
1240
1246
  }
@@ -1244,7 +1250,7 @@ function generateCompareUrl(repoUrl, from, to) {
1244
1250
  return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
1245
1251
  }
1246
1252
  function createTemplateContext(pkg) {
1247
- const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
1253
+ const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
1248
1254
  return {
1249
1255
  packageName: pkg.packageName,
1250
1256
  version: pkg.version,
package/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  runPipeline,
12
12
  saveAuth,
13
13
  writeMonorepoChangelogs
14
- } from "./chunk-ACXCEHQT.js";
14
+ } from "./chunk-HARXYT65.js";
15
15
 
16
16
  // src/cli.ts
17
17
  import * as fs from "fs";
package/dist/index.cjs CHANGED
@@ -430,15 +430,18 @@ For the "Developer" category, you MUST assign a scope from this exact list: ${sc
430
430
  }
431
431
  }
432
432
  }
433
+ const scopeValidationInstructions = scopeInstructions ? `
434
+
435
+ IMPORTANT: When assigning scopes, you MUST ONLY use scopes from the predefined list above. DO NOT use scopes from conventional commit messages (like "version", "core", "api", etc.). If an entry does not fit any of the predefined scopes, leave the scope as null.` : "";
433
436
  return `You are categorizing changelog entries for a software release.
434
437
 
435
438
  Given the following entries, group them into the specified categories. Only use the categories listed below in this exact order:
436
439
 
437
440
  Categories:
438
- ${categoryList}${scopeInstructions}
441
+ ${categoryList}${scopeInstructions}${scopeValidationInstructions}
439
442
  Output a JSON object with two fields:
440
443
  - "categories": an object where keys are category names and values are arrays of entry indices (0-based)
441
- - "scopes": an object where keys are entry indices (as strings) and values are scope labels
444
+ - "scopes": an object where keys are entry indices (as strings) and values are scope labels. Only include entries that have a valid scope from the predefined list.
442
445
 
443
446
  Entries:
444
447
  {{entries}}
@@ -449,7 +452,8 @@ async function categorizeEntries(provider, entries, context) {
449
452
  if (entries.length === 0) {
450
453
  return [];
451
454
  }
452
- const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
455
+ const entriesCopy = entries.map((e) => ({ ...e, scope: void 0 }));
456
+ const entriesText = entriesCopy.map((e, i) => `${i}. [${e.type}]: ${e.description}`).join("\n");
453
457
  const hasCustomCategories = context.categories && context.categories.length > 0;
454
458
  const promptTemplate = hasCustomCategories ? buildCustomCategorizePrompt(context.categories) : DEFAULT_CATEGORIZE_PROMPT;
455
459
  const prompt = promptTemplate.replace("{{entries}}", entriesText);
@@ -463,13 +467,13 @@ async function categorizeEntries(provider, entries, context) {
463
467
  const scopeMap = parsed.scopes || {};
464
468
  for (const [indexStr, scope] of Object.entries(scopeMap)) {
465
469
  const idx = Number.parseInt(indexStr, 10);
466
- if (entries[idx] && scope) {
467
- entries[idx] = { ...entries[idx], scope };
470
+ if (entriesCopy[idx] && scope && scope.trim()) {
471
+ entriesCopy[idx] = { ...entriesCopy[idx], scope: scope.trim() };
468
472
  }
469
473
  }
470
474
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
471
475
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
472
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
476
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
473
477
  if (categoryEntries.length > 0) {
474
478
  result.push({ category, entries: categoryEntries });
475
479
  }
@@ -478,7 +482,7 @@ async function categorizeEntries(provider, entries, context) {
478
482
  const categoryMap = parsed;
479
483
  for (const [category, rawIndices] of Object.entries(categoryMap)) {
480
484
  const indices = Array.isArray(rawIndices) ? rawIndices : [];
481
- const categoryEntries = indices.map((i) => entries[i]).filter((e) => e !== void 0);
485
+ const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
482
486
  if (categoryEntries.length > 0) {
483
487
  result.push({ category, entries: categoryEntries });
484
488
  }
@@ -489,7 +493,7 @@ async function categorizeEntries(provider, entries, context) {
489
493
  (0, import_core3.warn)(
490
494
  `LLM categorization failed, falling back to General: ${error instanceof Error ? error.message : String(error)}`
491
495
  );
492
- return [{ category: "General", entries }];
496
+ return [{ category: "General", entries: entriesCopy }];
493
497
  }
494
498
  }
495
499
 
@@ -623,7 +627,7 @@ async function enhanceAndCategorize(provider, entries, context) {
623
627
  if (!categoryMap.has(category)) {
624
628
  categoryMap.set(category, []);
625
629
  }
626
- categoryMap.get(category).push(entry);
630
+ categoryMap.get(category)?.push(entry);
627
631
  }
628
632
  const categories = [];
629
633
  for (const [category, catEntries] of categoryMap) {
@@ -1276,15 +1280,17 @@ function renderTemplate(templatePath, context, engine) {
1276
1280
 
1277
1281
  // src/core/pipeline.ts
1278
1282
  var import_meta = {};
1279
- function extractVersionFromTag(tag) {
1280
- if (tag.includes("@") && !tag.startsWith("@")) {
1281
- return tag;
1283
+ function generateCompareUrl(repoUrl, from, to, packageName) {
1284
+ const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
1285
+ let fromVersion;
1286
+ let toVersion;
1287
+ if (isPackageSpecific) {
1288
+ fromVersion = from;
1289
+ toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
1290
+ } else {
1291
+ fromVersion = from.replace(/^v/, "");
1292
+ toVersion = to.replace(/^v/, "");
1282
1293
  }
1283
- return tag.replace(/^v/, "");
1284
- }
1285
- function generateCompareUrl(repoUrl, from, to) {
1286
- const fromVersion = extractVersionFromTag(from);
1287
- const toVersion = extractVersionFromTag(to);
1288
1294
  if (/gitlab\.com/i.test(repoUrl)) {
1289
1295
  return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
1290
1296
  }
@@ -1294,7 +1300,7 @@ function generateCompareUrl(repoUrl, from, to) {
1294
1300
  return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
1295
1301
  }
1296
1302
  function createTemplateContext(pkg) {
1297
- const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
1303
+ const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
1298
1304
  return {
1299
1305
  packageName: pkg.packageName,
1300
1306
  version: pkg.version,
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  writeJson,
25
25
  writeMarkdown,
26
26
  writeMonorepoChangelogs
27
- } from "./chunk-ACXCEHQT.js";
27
+ } from "./chunk-HARXYT65.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.10",
3
+ "version": "0.2.0-next.12",
4
4
  "description": "Changelog generation with LLM-powered enhancement and flexible templating",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -44,16 +44,16 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@anthropic-ai/sdk": "^0.39.0",
48
- "@octokit/rest": "^21.1.1",
47
+ "@anthropic-ai/sdk": "^0.78.0",
48
+ "@octokit/rest": "^22.0.1",
49
49
  "@releasekit/config": "workspace:*",
50
50
  "@releasekit/core": "workspace:*",
51
51
  "chalk": "catalog:",
52
52
  "commander": "catalog:",
53
- "ejs": "^3.1.10",
53
+ "ejs": "^4.0.1",
54
54
  "handlebars": "^4.7.8",
55
55
  "liquidjs": "^10.21.0",
56
- "openai": "^4.87.0",
56
+ "openai": "^6.27.0",
57
57
  "zod": "catalog:"
58
58
  },
59
59
  "devDependencies": {