@releasekit/notes 0.2.0-next.8 → 0.2.0
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/LICENSE +21 -0
- package/README.md +1 -1
- package/dist/{chunk-BLWJTLRD.js → chunk-DGZ6TM5J.js} +180 -63
- package/dist/cli.cjs +174 -57
- package/dist/cli.js +1 -1
- package/dist/index.cjs +174 -57
- package/dist/index.d.cts +31 -5
- package/dist/index.d.ts +31 -5
- package/dist/index.js +1 -1
- package/package.json +41 -30
package/dist/index.cjs
CHANGED
|
@@ -404,6 +404,83 @@ var OpenAICompatibleProvider = class extends BaseLLMProvider {
|
|
|
404
404
|
|
|
405
405
|
// src/llm/tasks/categorize.ts
|
|
406
406
|
var import_core3 = require("@releasekit/core");
|
|
407
|
+
|
|
408
|
+
// src/llm/prompts.ts
|
|
409
|
+
function resolvePrompt(taskName, defaultPrompt, promptsConfig) {
|
|
410
|
+
if (!promptsConfig) return defaultPrompt;
|
|
411
|
+
const fullTemplate = promptsConfig.templates?.[taskName];
|
|
412
|
+
if (fullTemplate) return fullTemplate;
|
|
413
|
+
const additionalInstructions = promptsConfig.instructions?.[taskName];
|
|
414
|
+
if (additionalInstructions) {
|
|
415
|
+
const insertionPoint = defaultPrompt.lastIndexOf("Output only valid JSON");
|
|
416
|
+
if (insertionPoint !== -1) {
|
|
417
|
+
return `${defaultPrompt.slice(0, insertionPoint)}Additional instructions:
|
|
418
|
+
${additionalInstructions}
|
|
419
|
+
|
|
420
|
+
${defaultPrompt.slice(insertionPoint)}`;
|
|
421
|
+
}
|
|
422
|
+
return `${defaultPrompt}
|
|
423
|
+
|
|
424
|
+
Additional instructions:
|
|
425
|
+
${additionalInstructions}`;
|
|
426
|
+
}
|
|
427
|
+
return defaultPrompt;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// src/llm/scopes.ts
|
|
431
|
+
function getAllowedScopesFromCategories(categories) {
|
|
432
|
+
const scopeMap = /* @__PURE__ */ new Map();
|
|
433
|
+
for (const cat of categories) {
|
|
434
|
+
if (cat.scopes && cat.scopes.length > 0) {
|
|
435
|
+
scopeMap.set(cat.name, cat.scopes);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return scopeMap;
|
|
439
|
+
}
|
|
440
|
+
function resolveAllowedScopes(scopeConfig, categories, packageNames) {
|
|
441
|
+
if (!scopeConfig || scopeConfig.mode === "unrestricted") return null;
|
|
442
|
+
if (scopeConfig.mode === "none") return [];
|
|
443
|
+
if (scopeConfig.mode === "packages") return packageNames ?? [];
|
|
444
|
+
if (scopeConfig.mode === "restricted") {
|
|
445
|
+
const explicit = scopeConfig.rules?.allowed ?? [];
|
|
446
|
+
const all = new Set(explicit);
|
|
447
|
+
if (categories) {
|
|
448
|
+
const fromCategories = getAllowedScopesFromCategories(categories);
|
|
449
|
+
for (const scopes of fromCategories.values()) {
|
|
450
|
+
for (const s of scopes) all.add(s);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return [...all];
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
function validateScope(scope, allowedScopes, rules) {
|
|
458
|
+
if (!scope || allowedScopes === null) return scope;
|
|
459
|
+
if (allowedScopes.length === 0) return void 0;
|
|
460
|
+
const caseSensitive = rules?.caseSensitive ?? false;
|
|
461
|
+
const normalise = (s) => caseSensitive ? s : s.toLowerCase();
|
|
462
|
+
const isAllowed = allowedScopes.some((a) => normalise(a) === normalise(scope));
|
|
463
|
+
if (isAllowed) return scope;
|
|
464
|
+
switch (rules?.invalidScopeAction ?? "remove") {
|
|
465
|
+
case "keep":
|
|
466
|
+
return scope;
|
|
467
|
+
case "fallback":
|
|
468
|
+
return rules?.fallbackScope;
|
|
469
|
+
case "remove":
|
|
470
|
+
default:
|
|
471
|
+
return void 0;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function validateEntryScopes(entries, scopeConfig, categories) {
|
|
475
|
+
const allowedScopes = resolveAllowedScopes(scopeConfig, categories);
|
|
476
|
+
if (allowedScopes === null) return entries;
|
|
477
|
+
return entries.map((entry) => ({
|
|
478
|
+
...entry,
|
|
479
|
+
scope: validateScope(entry.scope, allowedScopes, scopeConfig?.rules)
|
|
480
|
+
}));
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/llm/tasks/categorize.ts
|
|
407
484
|
var DEFAULT_CATEGORIZE_PROMPT = `You are categorizing changelog entries for a software release.
|
|
408
485
|
|
|
409
486
|
Given the following entries, group them into meaningful categories (e.g., "Core", "UI", "API", "Performance", "Bug Fixes", "Documentation").
|
|
@@ -415,20 +492,21 @@ Entries:
|
|
|
415
492
|
|
|
416
493
|
Output only valid JSON, nothing else:`;
|
|
417
494
|
function buildCustomCategorizePrompt(categories) {
|
|
418
|
-
const categoryList = categories.map((c) =>
|
|
419
|
-
|
|
495
|
+
const categoryList = categories.map((c) => {
|
|
496
|
+
const scopeInfo = c.scopes?.length ? ` Allowed scopes: ${c.scopes.join(", ")}.` : "";
|
|
497
|
+
return `- "${c.name}": ${c.description}${scopeInfo}`;
|
|
498
|
+
}).join("\n");
|
|
499
|
+
const scopeMap = getAllowedScopesFromCategories(categories);
|
|
420
500
|
let scopeInstructions = "";
|
|
421
|
-
if (
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
}
|
|
501
|
+
if (scopeMap.size > 0) {
|
|
502
|
+
const entries = [];
|
|
503
|
+
for (const [catName, scopes] of scopeMap) {
|
|
504
|
+
entries.push(`For "${catName}", assign a scope from: ${scopes.join(", ")}.`);
|
|
431
505
|
}
|
|
506
|
+
scopeInstructions = `
|
|
507
|
+
|
|
508
|
+
${entries.join("\n")}
|
|
509
|
+
Only use scopes from these predefined lists. If an entry does not fit any scope, set scope to null.`;
|
|
432
510
|
}
|
|
433
511
|
return `You are categorizing changelog entries for a software release.
|
|
434
512
|
|
|
@@ -436,9 +514,10 @@ Given the following entries, group them into the specified categories. Only use
|
|
|
436
514
|
|
|
437
515
|
Categories:
|
|
438
516
|
${categoryList}${scopeInstructions}
|
|
517
|
+
|
|
439
518
|
Output a JSON object with two fields:
|
|
440
519
|
- "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
|
|
520
|
+
- "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
521
|
|
|
443
522
|
Entries:
|
|
444
523
|
{{entries}}
|
|
@@ -449,9 +528,11 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
449
528
|
if (entries.length === 0) {
|
|
450
529
|
return [];
|
|
451
530
|
}
|
|
452
|
-
const
|
|
531
|
+
const entriesCopy = entries.map((e) => ({ ...e, scope: void 0 }));
|
|
532
|
+
const entriesText = entriesCopy.map((e, i) => `${i}. [${e.type}]: ${e.description}`).join("\n");
|
|
453
533
|
const hasCustomCategories = context.categories && context.categories.length > 0;
|
|
454
|
-
const
|
|
534
|
+
const defaultPrompt = hasCustomCategories ? buildCustomCategorizePrompt(context.categories) : DEFAULT_CATEGORIZE_PROMPT;
|
|
535
|
+
const promptTemplate = resolvePrompt("categorize", defaultPrompt, context.prompts);
|
|
455
536
|
const prompt = promptTemplate.replace("{{entries}}", entriesText);
|
|
456
537
|
try {
|
|
457
538
|
const response = await provider.complete(prompt);
|
|
@@ -463,13 +544,14 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
463
544
|
const scopeMap = parsed.scopes || {};
|
|
464
545
|
for (const [indexStr, scope] of Object.entries(scopeMap)) {
|
|
465
546
|
const idx = Number.parseInt(indexStr, 10);
|
|
466
|
-
if (
|
|
467
|
-
|
|
547
|
+
if (entriesCopy[idx] && scope && scope.trim()) {
|
|
548
|
+
entriesCopy[idx] = { ...entriesCopy[idx], scope: scope.trim() };
|
|
468
549
|
}
|
|
469
550
|
}
|
|
551
|
+
const validatedEntries = validateEntryScopes(entriesCopy, context.scopes, context.categories);
|
|
470
552
|
for (const [category, rawIndices] of Object.entries(categoryMap)) {
|
|
471
553
|
const indices = Array.isArray(rawIndices) ? rawIndices : [];
|
|
472
|
-
const categoryEntries = indices.map((i) =>
|
|
554
|
+
const categoryEntries = indices.map((i) => validatedEntries[i]).filter((e) => e !== void 0);
|
|
473
555
|
if (categoryEntries.length > 0) {
|
|
474
556
|
result.push({ category, entries: categoryEntries });
|
|
475
557
|
}
|
|
@@ -478,7 +560,7 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
478
560
|
const categoryMap = parsed;
|
|
479
561
|
for (const [category, rawIndices] of Object.entries(categoryMap)) {
|
|
480
562
|
const indices = Array.isArray(rawIndices) ? rawIndices : [];
|
|
481
|
-
const categoryEntries = indices.map((i) =>
|
|
563
|
+
const categoryEntries = indices.map((i) => entriesCopy[i]).filter((e) => e !== void 0);
|
|
482
564
|
if (categoryEntries.length > 0) {
|
|
483
565
|
result.push({ category, entries: categoryEntries });
|
|
484
566
|
}
|
|
@@ -489,12 +571,12 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
489
571
|
(0, import_core3.warn)(
|
|
490
572
|
`LLM categorization failed, falling back to General: ${error instanceof Error ? error.message : String(error)}`
|
|
491
573
|
);
|
|
492
|
-
return [{ category: "General", entries }];
|
|
574
|
+
return [{ category: "General", entries: entriesCopy }];
|
|
493
575
|
}
|
|
494
576
|
}
|
|
495
577
|
|
|
496
578
|
// src/llm/tasks/enhance.ts
|
|
497
|
-
var
|
|
579
|
+
var DEFAULT_ENHANCE_PROMPT = `You are improving changelog entries for a software project.
|
|
498
580
|
Given a technical commit message, rewrite it as a clear, user-friendly changelog entry.
|
|
499
581
|
|
|
500
582
|
Rules:
|
|
@@ -510,9 +592,10 @@ Type: {{type}}
|
|
|
510
592
|
Description: {{description}}
|
|
511
593
|
|
|
512
594
|
Rewritten description (only output the new description, nothing else):`;
|
|
513
|
-
async function enhanceEntry(provider, entry,
|
|
514
|
-
const styleText =
|
|
515
|
-
const
|
|
595
|
+
async function enhanceEntry(provider, entry, context) {
|
|
596
|
+
const styleText = context.style ? `- ${context.style}` : '- Use present tense ("Add feature" not "Added feature")';
|
|
597
|
+
const defaultPrompt = DEFAULT_ENHANCE_PROMPT.replace("{{style}}", styleText).replace("{{type}}", entry.type).replace("{{#if scope}}Scope: {{scope}}{{/if}}", entry.scope ? `Scope: ${entry.scope}` : "").replace("{{description}}", entry.description);
|
|
598
|
+
const prompt = resolvePrompt("enhance", defaultPrompt, context.prompts);
|
|
516
599
|
const response = await provider.complete(prompt);
|
|
517
600
|
return response.trim();
|
|
518
601
|
}
|
|
@@ -568,7 +651,23 @@ function buildPrompt(entries, categories, style) {
|
|
|
568
651
|
const entriesText = entries.map((e, i) => `${i}. [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
|
|
569
652
|
const styleText = style || 'Use present tense ("Add feature" not "Added feature"). Be concise.';
|
|
570
653
|
const categorySection = categories ? `Categories (use ONLY these):
|
|
571
|
-
${categories.map((c) =>
|
|
654
|
+
${categories.map((c) => {
|
|
655
|
+
const scopeInfo = c.scopes?.length ? ` Allowed scopes: ${c.scopes.join(", ")}.` : "";
|
|
656
|
+
return `- "${c.name}": ${c.description}${scopeInfo}`;
|
|
657
|
+
}).join("\n")}` : `Categories: Group into meaningful categories (e.g., "New", "Fixed", "Changed", "Removed").`;
|
|
658
|
+
let scopeInstruction = "";
|
|
659
|
+
if (categories) {
|
|
660
|
+
const scopeMap = getAllowedScopesFromCategories(categories);
|
|
661
|
+
if (scopeMap.size > 0) {
|
|
662
|
+
const parts = [];
|
|
663
|
+
for (const [catName, scopes] of scopeMap) {
|
|
664
|
+
parts.push(`For "${catName}" entries, assign a scope from: ${scopes.join(", ")}.`);
|
|
665
|
+
}
|
|
666
|
+
scopeInstruction = `
|
|
667
|
+
${parts.join("\n")}
|
|
668
|
+
Only use scopes from these predefined lists. Set scope to null if no scope applies.`;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
572
671
|
return `You are generating release notes for a software project. Given the following changelog entries, do two things:
|
|
573
672
|
|
|
574
673
|
1. **Rewrite** each entry as a clear, user-friendly description
|
|
@@ -579,9 +678,7 @@ Style guidelines:
|
|
|
579
678
|
- Be concise (1 short sentence per entry)
|
|
580
679
|
- Focus on what changed, not implementation details
|
|
581
680
|
|
|
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").' : ""}
|
|
681
|
+
${categorySection}${scopeInstruction}
|
|
585
682
|
|
|
586
683
|
Entries:
|
|
587
684
|
${entriesText}
|
|
@@ -598,7 +695,8 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
598
695
|
const retryOpts = LLM_DEFAULTS.retry;
|
|
599
696
|
try {
|
|
600
697
|
return await withRetry(async () => {
|
|
601
|
-
const
|
|
698
|
+
const defaultPrompt = buildPrompt(entries, context.categories, context.style);
|
|
699
|
+
const prompt = resolvePrompt("enhanceAndCategorize", defaultPrompt, context.prompts);
|
|
602
700
|
const response = await provider.complete(prompt);
|
|
603
701
|
const cleaned = response.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "").trim();
|
|
604
702
|
const parsed = JSON.parse(cleaned);
|
|
@@ -614,22 +712,23 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
614
712
|
scope: result.scope || original.scope
|
|
615
713
|
};
|
|
616
714
|
});
|
|
715
|
+
const validatedEntries = validateEntryScopes(enhancedEntries, context.scopes, context.categories);
|
|
617
716
|
const categoryMap = /* @__PURE__ */ new Map();
|
|
618
717
|
for (let i = 0; i < parsed.entries.length; i++) {
|
|
619
718
|
const result = parsed.entries[i];
|
|
620
719
|
const category = result?.category || "General";
|
|
621
|
-
const entry =
|
|
720
|
+
const entry = validatedEntries[i];
|
|
622
721
|
if (!entry) continue;
|
|
623
722
|
if (!categoryMap.has(category)) {
|
|
624
723
|
categoryMap.set(category, []);
|
|
625
724
|
}
|
|
626
|
-
categoryMap.get(category)
|
|
725
|
+
categoryMap.get(category)?.push(entry);
|
|
627
726
|
}
|
|
628
727
|
const categories = [];
|
|
629
728
|
for (const [category, catEntries] of categoryMap) {
|
|
630
729
|
categories.push({ category, entries: catEntries });
|
|
631
730
|
}
|
|
632
|
-
return { enhancedEntries, categories };
|
|
731
|
+
return { enhancedEntries: validatedEntries, categories };
|
|
633
732
|
}, retryOpts);
|
|
634
733
|
} catch (error) {
|
|
635
734
|
(0, import_core4.warn)(
|
|
@@ -643,7 +742,7 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
643
742
|
}
|
|
644
743
|
|
|
645
744
|
// src/llm/tasks/release-notes.ts
|
|
646
|
-
var
|
|
745
|
+
var DEFAULT_RELEASE_NOTES_PROMPT = `You are writing release notes for a software project.
|
|
647
746
|
|
|
648
747
|
Create engaging, user-friendly release notes for the following changes.
|
|
649
748
|
|
|
@@ -676,16 +775,17 @@ No notable changes in this release.`;
|
|
|
676
775
|
if (e.breaking) line += " **BREAKING**";
|
|
677
776
|
return line;
|
|
678
777
|
}).join("\n");
|
|
679
|
-
const
|
|
778
|
+
const defaultPrompt = DEFAULT_RELEASE_NOTES_PROMPT.replace("{{version}}", context.version ?? "v1.0.0").replace(
|
|
680
779
|
"{{#if previousVersion}}Previous version: {{previousVersion}}{{/if}}",
|
|
681
780
|
context.previousVersion ? `Previous version: ${context.previousVersion}` : ""
|
|
682
781
|
).replace("{{date}}", context.date ?? (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "").replace("{{entries}}", entriesText);
|
|
782
|
+
const prompt = resolvePrompt("releaseNotes", defaultPrompt, context.prompts);
|
|
683
783
|
const response = await provider.complete(prompt);
|
|
684
784
|
return response.trim();
|
|
685
785
|
}
|
|
686
786
|
|
|
687
787
|
// src/llm/tasks/summarize.ts
|
|
688
|
-
var
|
|
788
|
+
var DEFAULT_SUMMARIZE_PROMPT = `You are creating a summary of changes for a software release.
|
|
689
789
|
|
|
690
790
|
Given the following changelog entries, create a brief summary (2-3 sentences) that captures the main themes of this release.
|
|
691
791
|
|
|
@@ -693,12 +793,13 @@ Entries:
|
|
|
693
793
|
{{entries}}
|
|
694
794
|
|
|
695
795
|
Summary (only output the summary, nothing else):`;
|
|
696
|
-
async function summarizeEntries(provider, entries,
|
|
796
|
+
async function summarizeEntries(provider, entries, context) {
|
|
697
797
|
if (entries.length === 0) {
|
|
698
798
|
return "";
|
|
699
799
|
}
|
|
700
800
|
const entriesText = entries.map((e) => `- [${e.type}]${e.scope ? ` (${e.scope})` : ""}: ${e.description}`).join("\n");
|
|
701
|
-
const
|
|
801
|
+
const defaultPrompt = DEFAULT_SUMMARIZE_PROMPT.replace("{{entries}}", entriesText);
|
|
802
|
+
const prompt = resolvePrompt("summarize", defaultPrompt, context.prompts);
|
|
702
803
|
const response = await provider.complete(prompt);
|
|
703
804
|
return response.trim();
|
|
704
805
|
}
|
|
@@ -846,9 +947,10 @@ ${body}`;
|
|
|
846
947
|
function writeMarkdown(outputPath, contexts, config, dryRun) {
|
|
847
948
|
const content = renderMarkdown(contexts);
|
|
848
949
|
if (dryRun) {
|
|
849
|
-
(0, import_core5.info)(
|
|
850
|
-
|
|
851
|
-
(0, import_core5.
|
|
950
|
+
(0, import_core5.info)(`Would write changelog to ${outputPath}`);
|
|
951
|
+
(0, import_core5.debug)("--- Changelog Preview ---");
|
|
952
|
+
(0, import_core5.debug)(content);
|
|
953
|
+
(0, import_core5.debug)("--- End Preview ---");
|
|
852
954
|
return;
|
|
853
955
|
}
|
|
854
956
|
const dir = path.dirname(outputPath);
|
|
@@ -1007,9 +1109,10 @@ function renderJson(contexts) {
|
|
|
1007
1109
|
function writeJson(outputPath, contexts, dryRun) {
|
|
1008
1110
|
const content = renderJson(contexts);
|
|
1009
1111
|
if (dryRun) {
|
|
1010
|
-
(0, import_core7.info)(
|
|
1011
|
-
|
|
1012
|
-
(0, import_core7.
|
|
1112
|
+
(0, import_core7.info)(`Would write JSON output to ${outputPath}`);
|
|
1113
|
+
(0, import_core7.debug)("--- JSON Output Preview ---");
|
|
1114
|
+
(0, import_core7.debug)(content);
|
|
1115
|
+
(0, import_core7.debug)("--- End Preview ---");
|
|
1013
1116
|
return;
|
|
1014
1117
|
}
|
|
1015
1118
|
const dir = path2.dirname(outputPath);
|
|
@@ -1276,17 +1379,27 @@ function renderTemplate(templatePath, context, engine) {
|
|
|
1276
1379
|
|
|
1277
1380
|
// src/core/pipeline.ts
|
|
1278
1381
|
var import_meta = {};
|
|
1279
|
-
function generateCompareUrl(repoUrl, from, to) {
|
|
1382
|
+
function generateCompareUrl(repoUrl, from, to, packageName) {
|
|
1383
|
+
const isPackageSpecific = from.includes("@") && packageName && from.includes(packageName);
|
|
1384
|
+
let fromVersion;
|
|
1385
|
+
let toVersion;
|
|
1386
|
+
if (isPackageSpecific) {
|
|
1387
|
+
fromVersion = from;
|
|
1388
|
+
toVersion = `${packageName}@${to.startsWith("v") ? "" : "v"}${to}`;
|
|
1389
|
+
} else {
|
|
1390
|
+
fromVersion = from.replace(/^v/, "");
|
|
1391
|
+
toVersion = to.replace(/^v/, "");
|
|
1392
|
+
}
|
|
1280
1393
|
if (/gitlab\.com/i.test(repoUrl)) {
|
|
1281
|
-
return `${repoUrl}/-/compare/${
|
|
1394
|
+
return `${repoUrl}/-/compare/${fromVersion}...${toVersion}`;
|
|
1282
1395
|
}
|
|
1283
1396
|
if (/bitbucket\.org/i.test(repoUrl)) {
|
|
1284
|
-
return `${repoUrl}/branches/compare/${
|
|
1397
|
+
return `${repoUrl}/branches/compare/${fromVersion}..${toVersion}`;
|
|
1285
1398
|
}
|
|
1286
|
-
return `${repoUrl}/compare/${
|
|
1399
|
+
return `${repoUrl}/compare/${fromVersion}...${toVersion}`;
|
|
1287
1400
|
}
|
|
1288
1401
|
function createTemplateContext(pkg) {
|
|
1289
|
-
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version) : void 0;
|
|
1402
|
+
const compareUrl = pkg.repoUrl && pkg.previousVersion ? generateCompareUrl(pkg.repoUrl, pkg.previousVersion, pkg.version, pkg.packageName) : void 0;
|
|
1290
1403
|
return {
|
|
1291
1404
|
packageName: pkg.packageName,
|
|
1292
1405
|
version: pkg.version,
|
|
@@ -1324,7 +1437,9 @@ async function processWithLLM(context, config) {
|
|
|
1324
1437
|
previousVersion: context.previousVersion ?? void 0,
|
|
1325
1438
|
date: context.date,
|
|
1326
1439
|
categories: config.llm.categories,
|
|
1327
|
-
style: config.llm.style
|
|
1440
|
+
style: config.llm.style,
|
|
1441
|
+
scopes: config.llm.scopes,
|
|
1442
|
+
prompts: config.llm.prompts
|
|
1328
1443
|
};
|
|
1329
1444
|
const enhanced = {
|
|
1330
1445
|
entries: context.entries
|
|
@@ -1388,7 +1503,6 @@ async function processWithLLM(context, config) {
|
|
|
1388
1503
|
}
|
|
1389
1504
|
return {
|
|
1390
1505
|
...context,
|
|
1391
|
-
entries: enhanced.entries,
|
|
1392
1506
|
enhanced
|
|
1393
1507
|
};
|
|
1394
1508
|
} catch (error) {
|
|
@@ -1421,9 +1535,10 @@ async function generateWithTemplate(contexts, config, outputPath, dryRun) {
|
|
|
1421
1535
|
);
|
|
1422
1536
|
const result = renderTemplate(templatePath, documentContext, config.templates?.engine);
|
|
1423
1537
|
if (dryRun) {
|
|
1424
|
-
(0, import_core8.info)(
|
|
1425
|
-
|
|
1426
|
-
(0, import_core8.
|
|
1538
|
+
(0, import_core8.info)(`Would write templated output to ${outputPath}`);
|
|
1539
|
+
(0, import_core8.debug)("--- Changelog Preview ---");
|
|
1540
|
+
(0, import_core8.debug)(result.content);
|
|
1541
|
+
(0, import_core8.debug)("--- End Preview ---");
|
|
1427
1542
|
return;
|
|
1428
1543
|
}
|
|
1429
1544
|
if (outputPath === "-") {
|
|
@@ -1449,8 +1564,10 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1449
1564
|
switch (output.format) {
|
|
1450
1565
|
case "markdown": {
|
|
1451
1566
|
const file = output.file ?? "CHANGELOG.md";
|
|
1452
|
-
|
|
1453
|
-
|
|
1567
|
+
const effectiveTemplateConfig = output.templates ?? config.templates;
|
|
1568
|
+
if (effectiveTemplateConfig?.path || output.options?.template) {
|
|
1569
|
+
const configWithTemplate = { ...config, templates: effectiveTemplateConfig };
|
|
1570
|
+
await generateWithTemplate(contexts, configWithTemplate, file, dryRun);
|
|
1454
1571
|
} else {
|
|
1455
1572
|
writeMarkdown(file, contexts, config, dryRun);
|
|
1456
1573
|
}
|
|
@@ -1514,8 +1631,8 @@ function splitByPackage(contexts) {
|
|
|
1514
1631
|
// src/monorepo/aggregator.ts
|
|
1515
1632
|
function writeFile(outputPath, content, dryRun) {
|
|
1516
1633
|
if (dryRun) {
|
|
1517
|
-
(0, import_core9.info)(`
|
|
1518
|
-
|
|
1634
|
+
(0, import_core9.info)(`Would write to ${outputPath}`);
|
|
1635
|
+
(0, import_core9.debug)(content);
|
|
1519
1636
|
return;
|
|
1520
1637
|
}
|
|
1521
1638
|
const dir = path7.dirname(outputPath);
|
package/dist/index.d.cts
CHANGED
|
@@ -70,6 +70,32 @@ interface LLMOptions {
|
|
|
70
70
|
maxTokens?: number;
|
|
71
71
|
temperature?: number;
|
|
72
72
|
}
|
|
73
|
+
interface ScopeRules {
|
|
74
|
+
allowed?: string[];
|
|
75
|
+
caseSensitive?: boolean;
|
|
76
|
+
invalidScopeAction?: 'remove' | 'keep' | 'fallback';
|
|
77
|
+
fallbackScope?: string;
|
|
78
|
+
}
|
|
79
|
+
interface ScopeConfig {
|
|
80
|
+
mode?: 'restricted' | 'packages' | 'none' | 'unrestricted';
|
|
81
|
+
rules?: ScopeRules;
|
|
82
|
+
}
|
|
83
|
+
interface LLMPromptOverrides {
|
|
84
|
+
enhance?: string;
|
|
85
|
+
categorize?: string;
|
|
86
|
+
enhanceAndCategorize?: string;
|
|
87
|
+
summarize?: string;
|
|
88
|
+
releaseNotes?: string;
|
|
89
|
+
}
|
|
90
|
+
interface LLMPromptsConfig {
|
|
91
|
+
instructions?: LLMPromptOverrides;
|
|
92
|
+
templates?: LLMPromptOverrides;
|
|
93
|
+
}
|
|
94
|
+
interface LLMCategory {
|
|
95
|
+
name: string;
|
|
96
|
+
description: string;
|
|
97
|
+
scopes?: string[];
|
|
98
|
+
}
|
|
73
99
|
interface LLMConfig {
|
|
74
100
|
provider: string;
|
|
75
101
|
model: string;
|
|
@@ -84,17 +110,17 @@ interface LLMConfig {
|
|
|
84
110
|
categorize?: boolean;
|
|
85
111
|
releaseNotes?: boolean;
|
|
86
112
|
};
|
|
87
|
-
categories?:
|
|
88
|
-
name: string;
|
|
89
|
-
description: string;
|
|
90
|
-
}>;
|
|
113
|
+
categories?: LLMCategory[];
|
|
91
114
|
style?: string;
|
|
115
|
+
scopes?: ScopeConfig;
|
|
116
|
+
prompts?: LLMPromptsConfig;
|
|
92
117
|
}
|
|
93
118
|
type OutputFormat = 'markdown' | 'github-release' | 'json';
|
|
94
119
|
interface OutputConfig {
|
|
95
120
|
format: OutputFormat;
|
|
96
121
|
file?: string;
|
|
97
122
|
options?: Record<string, unknown>;
|
|
123
|
+
templates?: TemplateConfig;
|
|
98
124
|
}
|
|
99
125
|
type MonorepoMode = 'root' | 'packages' | 'both';
|
|
100
126
|
interface MonorepoConfig {
|
|
@@ -179,4 +205,4 @@ declare function writeJson(outputPath: string, contexts: TemplateContext[], dryR
|
|
|
179
205
|
declare function renderMarkdown(contexts: TemplateContext[]): string;
|
|
180
206
|
declare function writeMarkdown(outputPath: string, contexts: TemplateContext[], config: Config, dryRun: boolean): void;
|
|
181
207
|
|
|
182
|
-
export { NotesError as ChangelogCreatorError, type ChangelogEntry, type ChangelogInput, type ChangelogType, type CompleteOptions, type Config, ConfigError, type DocumentContext, type EnhancedData, GitHubError, InputParseError, type InputSource, type LLMConfig, LLMError, type LLMOptions, type MonorepoConfig, type MonorepoMode, NotesError, type OutputConfig, type OutputFormat, type PackageChangelog, type RetryOptions, type TemplateConfig, type TemplateContext, type TemplateEngine, TemplateError, type UpdateStrategy, aggregateToRoot, createTemplateContext, detectMonorepo, getDefaultConfig, getExitCode, loadConfig, parsePackageVersioner, parsePackageVersionerFile, parsePackageVersionerStdin, processInput, renderJson, renderMarkdown, runPipeline, writeJson, writeMarkdown, writeMonorepoChangelogs };
|
|
208
|
+
export { NotesError as ChangelogCreatorError, type ChangelogEntry, type ChangelogInput, type ChangelogType, type CompleteOptions, type Config, ConfigError, type DocumentContext, type EnhancedData, GitHubError, InputParseError, type InputSource, type LLMCategory, type LLMConfig, LLMError, type LLMOptions, type LLMPromptOverrides, type LLMPromptsConfig, type MonorepoConfig, type MonorepoMode, NotesError, type OutputConfig, type OutputFormat, type PackageChangelog, type RetryOptions, type ScopeConfig, type ScopeRules, type TemplateConfig, type TemplateContext, type TemplateEngine, TemplateError, type UpdateStrategy, aggregateToRoot, createTemplateContext, detectMonorepo, getDefaultConfig, getExitCode, loadConfig, parsePackageVersioner, parsePackageVersionerFile, parsePackageVersionerStdin, processInput, renderJson, renderMarkdown, runPipeline, writeJson, writeMarkdown, writeMonorepoChangelogs };
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,32 @@ interface LLMOptions {
|
|
|
70
70
|
maxTokens?: number;
|
|
71
71
|
temperature?: number;
|
|
72
72
|
}
|
|
73
|
+
interface ScopeRules {
|
|
74
|
+
allowed?: string[];
|
|
75
|
+
caseSensitive?: boolean;
|
|
76
|
+
invalidScopeAction?: 'remove' | 'keep' | 'fallback';
|
|
77
|
+
fallbackScope?: string;
|
|
78
|
+
}
|
|
79
|
+
interface ScopeConfig {
|
|
80
|
+
mode?: 'restricted' | 'packages' | 'none' | 'unrestricted';
|
|
81
|
+
rules?: ScopeRules;
|
|
82
|
+
}
|
|
83
|
+
interface LLMPromptOverrides {
|
|
84
|
+
enhance?: string;
|
|
85
|
+
categorize?: string;
|
|
86
|
+
enhanceAndCategorize?: string;
|
|
87
|
+
summarize?: string;
|
|
88
|
+
releaseNotes?: string;
|
|
89
|
+
}
|
|
90
|
+
interface LLMPromptsConfig {
|
|
91
|
+
instructions?: LLMPromptOverrides;
|
|
92
|
+
templates?: LLMPromptOverrides;
|
|
93
|
+
}
|
|
94
|
+
interface LLMCategory {
|
|
95
|
+
name: string;
|
|
96
|
+
description: string;
|
|
97
|
+
scopes?: string[];
|
|
98
|
+
}
|
|
73
99
|
interface LLMConfig {
|
|
74
100
|
provider: string;
|
|
75
101
|
model: string;
|
|
@@ -84,17 +110,17 @@ interface LLMConfig {
|
|
|
84
110
|
categorize?: boolean;
|
|
85
111
|
releaseNotes?: boolean;
|
|
86
112
|
};
|
|
87
|
-
categories?:
|
|
88
|
-
name: string;
|
|
89
|
-
description: string;
|
|
90
|
-
}>;
|
|
113
|
+
categories?: LLMCategory[];
|
|
91
114
|
style?: string;
|
|
115
|
+
scopes?: ScopeConfig;
|
|
116
|
+
prompts?: LLMPromptsConfig;
|
|
92
117
|
}
|
|
93
118
|
type OutputFormat = 'markdown' | 'github-release' | 'json';
|
|
94
119
|
interface OutputConfig {
|
|
95
120
|
format: OutputFormat;
|
|
96
121
|
file?: string;
|
|
97
122
|
options?: Record<string, unknown>;
|
|
123
|
+
templates?: TemplateConfig;
|
|
98
124
|
}
|
|
99
125
|
type MonorepoMode = 'root' | 'packages' | 'both';
|
|
100
126
|
interface MonorepoConfig {
|
|
@@ -179,4 +205,4 @@ declare function writeJson(outputPath: string, contexts: TemplateContext[], dryR
|
|
|
179
205
|
declare function renderMarkdown(contexts: TemplateContext[]): string;
|
|
180
206
|
declare function writeMarkdown(outputPath: string, contexts: TemplateContext[], config: Config, dryRun: boolean): void;
|
|
181
207
|
|
|
182
|
-
export { NotesError as ChangelogCreatorError, type ChangelogEntry, type ChangelogInput, type ChangelogType, type CompleteOptions, type Config, ConfigError, type DocumentContext, type EnhancedData, GitHubError, InputParseError, type InputSource, type LLMConfig, LLMError, type LLMOptions, type MonorepoConfig, type MonorepoMode, NotesError, type OutputConfig, type OutputFormat, type PackageChangelog, type RetryOptions, type TemplateConfig, type TemplateContext, type TemplateEngine, TemplateError, type UpdateStrategy, aggregateToRoot, createTemplateContext, detectMonorepo, getDefaultConfig, getExitCode, loadConfig, parsePackageVersioner, parsePackageVersionerFile, parsePackageVersionerStdin, processInput, renderJson, renderMarkdown, runPipeline, writeJson, writeMarkdown, writeMonorepoChangelogs };
|
|
208
|
+
export { NotesError as ChangelogCreatorError, type ChangelogEntry, type ChangelogInput, type ChangelogType, type CompleteOptions, type Config, ConfigError, type DocumentContext, type EnhancedData, GitHubError, InputParseError, type InputSource, type LLMCategory, type LLMConfig, LLMError, type LLMOptions, type LLMPromptOverrides, type LLMPromptsConfig, type MonorepoConfig, type MonorepoMode, NotesError, type OutputConfig, type OutputFormat, type PackageChangelog, type RetryOptions, type ScopeConfig, type ScopeRules, type TemplateConfig, type TemplateContext, type TemplateEngine, TemplateError, type UpdateStrategy, aggregateToRoot, createTemplateContext, detectMonorepo, getDefaultConfig, getExitCode, loadConfig, parsePackageVersioner, parsePackageVersionerFile, parsePackageVersionerStdin, processInput, renderJson, renderMarkdown, runPipeline, writeJson, writeMarkdown, writeMonorepoChangelogs };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@releasekit/notes",
|
|
3
|
-
"version": "0.2.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Changelog generation with LLM-powered enhancement and flexible templating",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -21,17 +21,13 @@
|
|
|
21
21
|
"bin": {
|
|
22
22
|
"releasekit-notes": "dist/cli.js"
|
|
23
23
|
},
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
"lint": "biome check .",
|
|
32
|
-
"typecheck": "tsc --noEmit"
|
|
33
|
-
},
|
|
34
|
-
"keywords": ["changelog", "release-notes", "llm", "template", "cli"],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"changelog",
|
|
26
|
+
"release-notes",
|
|
27
|
+
"llm",
|
|
28
|
+
"template",
|
|
29
|
+
"cli"
|
|
30
|
+
],
|
|
35
31
|
"author": "Sam Maister <goosewobbler@protonmail.com>",
|
|
36
32
|
"license": "MIT",
|
|
37
33
|
"repository": {
|
|
@@ -39,33 +35,48 @@
|
|
|
39
35
|
"url": "git+https://github.com/goosewobbler/releasekit.git",
|
|
40
36
|
"directory": "packages/notes"
|
|
41
37
|
},
|
|
42
|
-
"files": [
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"templates",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
43
44
|
"publishConfig": {
|
|
44
45
|
"access": "public"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"@anthropic-ai/sdk": "^0.
|
|
48
|
-
"@octokit/rest": "^
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"commander": "catalog:",
|
|
53
|
-
"ejs": "^3.1.10",
|
|
48
|
+
"@anthropic-ai/sdk": "^0.78.0",
|
|
49
|
+
"@octokit/rest": "^22.0.1",
|
|
50
|
+
"chalk": "^5.6.2",
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
|
+
"ejs": "^4.0.1",
|
|
54
53
|
"handlebars": "^4.7.8",
|
|
55
|
-
"liquidjs": "^10.
|
|
56
|
-
"openai": "^
|
|
57
|
-
"zod": "
|
|
54
|
+
"liquidjs": "^10.25.0",
|
|
55
|
+
"openai": "^6.27.0",
|
|
56
|
+
"zod": "^4.3.6",
|
|
57
|
+
"@releasekit/config": "0.1.0",
|
|
58
|
+
"@releasekit/core": "0.1.0"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
|
-
"@biomejs/biome": "
|
|
61
|
+
"@biomejs/biome": "^2.4.6",
|
|
61
62
|
"@types/ejs": "^3.1.5",
|
|
62
|
-
"@types/node": "
|
|
63
|
-
"@vitest/coverage-v8": "
|
|
64
|
-
"tsup": "
|
|
65
|
-
"typescript": "
|
|
66
|
-
"vitest": "
|
|
63
|
+
"@types/node": "^22.19.15",
|
|
64
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
65
|
+
"tsup": "^8.5.1",
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"vitest": "^4.1.0"
|
|
67
68
|
},
|
|
68
69
|
"engines": {
|
|
69
70
|
"node": ">=20"
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"build": "tsup src/index.ts src/cli.ts --format esm,cjs --dts",
|
|
74
|
+
"dev": "tsup src/index.ts src/cli.ts --format esm,cjs --watch --dts",
|
|
75
|
+
"clean": "rm -rf dist coverage .turbo",
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"test:unit": "vitest run --coverage",
|
|
78
|
+
"test:coverage": "vitest run --coverage",
|
|
79
|
+
"lint": "biome check .",
|
|
80
|
+
"typecheck": "tsc --noEmit"
|
|
70
81
|
}
|
|
71
|
-
}
|
|
82
|
+
}
|