@releasekit/notes 0.7.11 → 0.7.13
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/{chunk-FNIE2SHL.js → chunk-Y4S5UWCL.js} +243 -47
- package/dist/cli.d.ts +9 -5
- package/dist/cli.js +3 -205
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -2
- package/package.json +3 -3
|
@@ -2,8 +2,11 @@ import {
|
|
|
2
2
|
EXIT_CODES,
|
|
3
3
|
ReleaseKitError,
|
|
4
4
|
debug,
|
|
5
|
+
error,
|
|
5
6
|
formatVersion,
|
|
6
7
|
info,
|
|
8
|
+
setLogLevel,
|
|
9
|
+
setQuietMode,
|
|
7
10
|
success,
|
|
8
11
|
warn,
|
|
9
12
|
writeMarkdown
|
|
@@ -404,16 +407,16 @@ function loadConfigFile(configPath) {
|
|
|
404
407
|
const parsed = parseJsonc(content);
|
|
405
408
|
const substituted = substituteInObject(parsed);
|
|
406
409
|
return ReleaseKitConfigSchema.parse(substituted);
|
|
407
|
-
} catch (
|
|
408
|
-
if (
|
|
409
|
-
const issues =
|
|
410
|
+
} catch (error2) {
|
|
411
|
+
if (error2 instanceof z2.ZodError) {
|
|
412
|
+
const issues = error2.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
410
413
|
throw new ConfigError(`Config validation errors:
|
|
411
414
|
${issues}`);
|
|
412
415
|
}
|
|
413
|
-
if (
|
|
414
|
-
throw new ConfigError(`Invalid JSON in config file: ${
|
|
416
|
+
if (error2 instanceof SyntaxError) {
|
|
417
|
+
throw new ConfigError(`Invalid JSON in config file: ${error2.message}`);
|
|
415
418
|
}
|
|
416
|
-
throw
|
|
419
|
+
throw error2;
|
|
417
420
|
}
|
|
418
421
|
}
|
|
419
422
|
function loadConfig(options) {
|
|
@@ -466,8 +469,8 @@ var ConfigError2 = class extends NotesError {
|
|
|
466
469
|
"Run releasekit-notes init to create default config"
|
|
467
470
|
];
|
|
468
471
|
};
|
|
469
|
-
function getExitCode(
|
|
470
|
-
switch (
|
|
472
|
+
function getExitCode(error2) {
|
|
473
|
+
switch (error2.code) {
|
|
471
474
|
case "CONFIG_ERROR":
|
|
472
475
|
return EXIT_CODES.CONFIG_ERROR;
|
|
473
476
|
case "INPUT_PARSE_ERROR":
|
|
@@ -506,8 +509,8 @@ function parseVersionOutput(json) {
|
|
|
506
509
|
let data;
|
|
507
510
|
try {
|
|
508
511
|
data = JSON.parse(json);
|
|
509
|
-
} catch (
|
|
510
|
-
throw new InputParseError(`Invalid JSON input: ${
|
|
512
|
+
} catch (error2) {
|
|
513
|
+
throw new InputParseError(`Invalid JSON input: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
511
514
|
}
|
|
512
515
|
if (!data.changelogs || !Array.isArray(data.changelogs)) {
|
|
513
516
|
throw new InputParseError('Input must contain a "changelogs" array');
|
|
@@ -630,9 +633,9 @@ var AnthropicProvider = class extends BaseLLMProvider {
|
|
|
630
633
|
throw new LLMError("Unexpected response format from Anthropic");
|
|
631
634
|
}
|
|
632
635
|
return firstBlock.text;
|
|
633
|
-
} catch (
|
|
634
|
-
if (
|
|
635
|
-
throw new LLMError(`Anthropic API error: ${
|
|
636
|
+
} catch (error2) {
|
|
637
|
+
if (error2 instanceof LLMError) throw error2;
|
|
638
|
+
throw new LLMError(`Anthropic API error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
636
639
|
}
|
|
637
640
|
}
|
|
638
641
|
};
|
|
@@ -688,9 +691,9 @@ var OllamaProvider = class extends BaseLLMProvider {
|
|
|
688
691
|
throw new LLMError("Empty response from Ollama");
|
|
689
692
|
}
|
|
690
693
|
return data.message.content;
|
|
691
|
-
} catch (
|
|
692
|
-
if (
|
|
693
|
-
throw new LLMError(`Ollama error: ${
|
|
694
|
+
} catch (error2) {
|
|
695
|
+
if (error2 instanceof LLMError) throw error2;
|
|
696
|
+
throw new LLMError(`Ollama error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
694
697
|
}
|
|
695
698
|
}
|
|
696
699
|
};
|
|
@@ -726,9 +729,9 @@ var OpenAIProvider = class extends BaseLLMProvider {
|
|
|
726
729
|
throw new LLMError("Empty response from OpenAI");
|
|
727
730
|
}
|
|
728
731
|
return content;
|
|
729
|
-
} catch (
|
|
730
|
-
if (
|
|
731
|
-
throw new LLMError(`OpenAI API error: ${
|
|
732
|
+
} catch (error2) {
|
|
733
|
+
if (error2 instanceof LLMError) throw error2;
|
|
734
|
+
throw new LLMError(`OpenAI API error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
732
735
|
}
|
|
733
736
|
}
|
|
734
737
|
};
|
|
@@ -761,9 +764,9 @@ var OpenAICompatibleProvider = class extends BaseLLMProvider {
|
|
|
761
764
|
throw new LLMError("Empty response from LLM");
|
|
762
765
|
}
|
|
763
766
|
return content;
|
|
764
|
-
} catch (
|
|
765
|
-
if (
|
|
766
|
-
throw new LLMError(`LLM API error: ${
|
|
767
|
+
} catch (error2) {
|
|
768
|
+
if (error2 instanceof LLMError) throw error2;
|
|
769
|
+
throw new LLMError(`LLM API error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
767
770
|
}
|
|
768
771
|
}
|
|
769
772
|
};
|
|
@@ -938,9 +941,9 @@ async function categorizeEntries(provider, entries, context) {
|
|
|
938
941
|
}
|
|
939
942
|
}
|
|
940
943
|
return result;
|
|
941
|
-
} catch (
|
|
944
|
+
} catch (error2) {
|
|
942
945
|
warn(
|
|
943
|
-
`LLM categorization failed, falling back to General: ${
|
|
946
|
+
`LLM categorization failed, falling back to General: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
944
947
|
);
|
|
945
948
|
return [{ category: "General", entries: entriesCopy }];
|
|
946
949
|
}
|
|
@@ -1002,8 +1005,8 @@ async function withRetry(fn, options = {}) {
|
|
|
1002
1005
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1003
1006
|
try {
|
|
1004
1007
|
return await fn();
|
|
1005
|
-
} catch (
|
|
1006
|
-
lastError =
|
|
1008
|
+
} catch (error2) {
|
|
1009
|
+
lastError = error2;
|
|
1007
1010
|
if (attempt < maxAttempts - 1) {
|
|
1008
1011
|
const base = Math.min(initialDelay * backoffFactor ** attempt, maxDelay);
|
|
1009
1012
|
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
@@ -1097,9 +1100,9 @@ async function enhanceAndCategorize(provider, entries, context) {
|
|
|
1097
1100
|
}
|
|
1098
1101
|
return { enhancedEntries: validatedEntries, categories };
|
|
1099
1102
|
}, retryOpts);
|
|
1100
|
-
} catch (
|
|
1103
|
+
} catch (error2) {
|
|
1101
1104
|
warn(
|
|
1102
|
-
`Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${
|
|
1105
|
+
`Combined enhance+categorize failed after ${retryOpts.maxAttempts} attempts: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
1103
1106
|
);
|
|
1104
1107
|
return {
|
|
1105
1108
|
enhancedEntries: entries,
|
|
@@ -1214,8 +1217,8 @@ import ejs from "ejs";
|
|
|
1214
1217
|
function renderEjs(template, context) {
|
|
1215
1218
|
try {
|
|
1216
1219
|
return ejs.render(template, context);
|
|
1217
|
-
} catch (
|
|
1218
|
-
throw new TemplateError(`EJS render error: ${
|
|
1220
|
+
} catch (error2) {
|
|
1221
|
+
throw new TemplateError(`EJS render error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1219
1222
|
}
|
|
1220
1223
|
}
|
|
1221
1224
|
function renderEjsFile(filePath, context) {
|
|
@@ -1249,8 +1252,8 @@ function renderHandlebars(template, context) {
|
|
|
1249
1252
|
try {
|
|
1250
1253
|
const compiled = Handlebars.compile(template);
|
|
1251
1254
|
return compiled(context);
|
|
1252
|
-
} catch (
|
|
1253
|
-
throw new TemplateError(`Handlebars render error: ${
|
|
1255
|
+
} catch (error2) {
|
|
1256
|
+
throw new TemplateError(`Handlebars render error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1254
1257
|
}
|
|
1255
1258
|
}
|
|
1256
1259
|
function renderHandlebarsFile(filePath, context) {
|
|
@@ -1277,8 +1280,8 @@ function renderHandlebarsComposable(templateDir, context) {
|
|
|
1277
1280
|
try {
|
|
1278
1281
|
const compiled = Handlebars.compile(fs6.readFileSync(documentPath, "utf-8"));
|
|
1279
1282
|
return compiled(context);
|
|
1280
|
-
} catch (
|
|
1281
|
-
throw new TemplateError(`Handlebars render error: ${
|
|
1283
|
+
} catch (error2) {
|
|
1284
|
+
throw new TemplateError(`Handlebars render error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1282
1285
|
}
|
|
1283
1286
|
}
|
|
1284
1287
|
|
|
@@ -1297,8 +1300,8 @@ function renderLiquid(template, context) {
|
|
|
1297
1300
|
const engine = createLiquidEngine();
|
|
1298
1301
|
try {
|
|
1299
1302
|
return engine.renderSync(engine.parse(template), context);
|
|
1300
|
-
} catch (
|
|
1301
|
-
throw new TemplateError(`Liquid render error: ${
|
|
1303
|
+
} catch (error2) {
|
|
1304
|
+
throw new TemplateError(`Liquid render error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1302
1305
|
}
|
|
1303
1306
|
}
|
|
1304
1307
|
function renderLiquidFile(filePath, context) {
|
|
@@ -1316,8 +1319,8 @@ function renderLiquidComposable(templateDir, context) {
|
|
|
1316
1319
|
const engine = createLiquidEngine(templateDir);
|
|
1317
1320
|
try {
|
|
1318
1321
|
return engine.renderFileSync("document", context);
|
|
1319
|
-
} catch (
|
|
1320
|
-
throw new TemplateError(`Liquid render error: ${
|
|
1322
|
+
} catch (error2) {
|
|
1323
|
+
throw new TemplateError(`Liquid render error: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1321
1324
|
}
|
|
1322
1325
|
}
|
|
1323
1326
|
|
|
@@ -1619,8 +1622,8 @@ async function processWithLLM(context, llmConfig) {
|
|
|
1619
1622
|
...context,
|
|
1620
1623
|
enhanced
|
|
1621
1624
|
};
|
|
1622
|
-
} catch (
|
|
1623
|
-
warn(`LLM processing failed: ${
|
|
1625
|
+
} catch (error2) {
|
|
1626
|
+
warn(`LLM processing failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1624
1627
|
warn("Falling back to raw entries");
|
|
1625
1628
|
return context;
|
|
1626
1629
|
}
|
|
@@ -1699,8 +1702,8 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1699
1702
|
const monoFiles = await writeMonorepoFiles(contexts, config, dryRun, changelogConfig.file ?? "CHANGELOG.md");
|
|
1700
1703
|
files.push(...monoFiles);
|
|
1701
1704
|
}
|
|
1702
|
-
} catch (
|
|
1703
|
-
warn(`Failed to write changelog: ${
|
|
1705
|
+
} catch (error2) {
|
|
1706
|
+
warn(`Failed to write changelog: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1704
1707
|
}
|
|
1705
1708
|
}
|
|
1706
1709
|
if (releaseNotesConfig?.mode) {
|
|
@@ -1731,8 +1734,8 @@ async function runPipeline(input, config, dryRun) {
|
|
|
1731
1734
|
);
|
|
1732
1735
|
files.push(...monoFiles);
|
|
1733
1736
|
}
|
|
1734
|
-
} catch (
|
|
1735
|
-
warn(`Failed to write release notes: ${
|
|
1737
|
+
} catch (error2) {
|
|
1738
|
+
warn(`Failed to write release notes: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
1736
1739
|
}
|
|
1737
1740
|
}
|
|
1738
1741
|
const packageNotes = {};
|
|
@@ -1795,10 +1798,202 @@ async function writeMonorepoFiles(contexts, config, dryRun, fileName) {
|
|
|
1795
1798
|
return monoFiles;
|
|
1796
1799
|
}
|
|
1797
1800
|
|
|
1801
|
+
// src/command.ts
|
|
1802
|
+
import * as fs10 from "fs";
|
|
1803
|
+
import * as readline from "readline";
|
|
1804
|
+
import { Command } from "commander";
|
|
1805
|
+
function createNotesCommand() {
|
|
1806
|
+
const cmd = new Command("notes").description(
|
|
1807
|
+
"Generate changelogs with LLM-powered enhancement and flexible templating"
|
|
1808
|
+
);
|
|
1809
|
+
cmd.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("--no-changelog", "Disable changelog generation").option("--changelog-mode <mode>", "Changelog location mode (root|packages|both)").option("--changelog-file <name>", "Changelog file name override").option("--release-notes-mode <mode>", "Enable release notes and set location (root|packages|both)").option("--release-notes-file <name>", "Release notes file name override").option("--no-release-notes", "Disable release notes generation").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("--regenerate", "Regenerate entire changelog instead of prepending new entries").option("--dry-run", "Preview without writing").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
|
|
1810
|
+
setVerbosity(options.verbose);
|
|
1811
|
+
if (options.quiet) setQuietMode(true);
|
|
1812
|
+
try {
|
|
1813
|
+
const loadedConfig = loadConfig({ cwd: process.cwd(), configPath: options.config });
|
|
1814
|
+
const config = loadedConfig?.notes ?? {};
|
|
1815
|
+
if (loadedConfig?.monorepo && !config.monorepo) {
|
|
1816
|
+
config.monorepo = loadedConfig.monorepo;
|
|
1817
|
+
}
|
|
1818
|
+
if (options.changelog === false) {
|
|
1819
|
+
config.changelog = false;
|
|
1820
|
+
} else if (options.changelogMode || options.changelogFile) {
|
|
1821
|
+
const existing = config.changelog !== false ? config.changelog ?? {} : {};
|
|
1822
|
+
const mode = options.changelogMode ?? existing.mode ?? "root";
|
|
1823
|
+
config.changelog = {
|
|
1824
|
+
...existing,
|
|
1825
|
+
mode,
|
|
1826
|
+
...options.changelogFile ? { file: options.changelogFile } : {}
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
if (options.releaseNotes === false) {
|
|
1830
|
+
config.releaseNotes = false;
|
|
1831
|
+
} else if (options.releaseNotesMode || options.releaseNotesFile) {
|
|
1832
|
+
const existing = config.releaseNotes !== false ? config.releaseNotes ?? {} : {};
|
|
1833
|
+
const mode = options.releaseNotesMode ?? existing.mode ?? "root";
|
|
1834
|
+
config.releaseNotes = {
|
|
1835
|
+
...existing,
|
|
1836
|
+
mode,
|
|
1837
|
+
...options.releaseNotesFile ? { file: options.releaseNotesFile } : {}
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
if (config.changelog === false && (options.template || options.engine)) {
|
|
1841
|
+
const ignored = [options.template && "--template", options.engine && "--engine"].filter(Boolean).join(" and ");
|
|
1842
|
+
warn(`${ignored} ignored: changelog is disabled via --no-changelog`);
|
|
1843
|
+
}
|
|
1844
|
+
if (options.template && config.changelog !== false) {
|
|
1845
|
+
const existing = config.changelog ?? {};
|
|
1846
|
+
config.changelog = {
|
|
1847
|
+
...existing,
|
|
1848
|
+
templates: { ...existing.templates, path: options.template }
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
if (options.engine && config.changelog !== false) {
|
|
1852
|
+
const existing = config.changelog ?? {};
|
|
1853
|
+
config.changelog = {
|
|
1854
|
+
...existing,
|
|
1855
|
+
templates: { ...existing.templates, engine: options.engine }
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
if (options.regenerate) {
|
|
1859
|
+
config.updateStrategy = "regenerate";
|
|
1860
|
+
}
|
|
1861
|
+
if (options.llm === false) {
|
|
1862
|
+
if (config.releaseNotes && typeof config.releaseNotes !== "boolean" && config.releaseNotes.llm) {
|
|
1863
|
+
info("LLM processing disabled via --no-llm flag");
|
|
1864
|
+
config.releaseNotes = { ...config.releaseNotes, llm: void 0 };
|
|
1865
|
+
}
|
|
1866
|
+
} else if (options.llmProvider || options.llmModel || options.llmBaseUrl || options.llmTasks) {
|
|
1867
|
+
if (config.releaseNotes === false) {
|
|
1868
|
+
warn("--llm-* flags ignored: release notes are disabled via --no-release-notes");
|
|
1869
|
+
} else {
|
|
1870
|
+
const existingRn = typeof config.releaseNotes === "object" ? config.releaseNotes : {};
|
|
1871
|
+
const existingLlm = existingRn.llm;
|
|
1872
|
+
const llm = {
|
|
1873
|
+
provider: existingLlm?.provider ?? "openai-compatible",
|
|
1874
|
+
model: existingLlm?.model ?? "",
|
|
1875
|
+
...existingLlm ?? {}
|
|
1876
|
+
};
|
|
1877
|
+
if (options.llmProvider) llm.provider = options.llmProvider;
|
|
1878
|
+
if (options.llmModel) llm.model = options.llmModel;
|
|
1879
|
+
if (options.llmBaseUrl) llm.baseURL = options.llmBaseUrl;
|
|
1880
|
+
if (options.llmTasks) {
|
|
1881
|
+
const taskNames = options.llmTasks.split(",").map((t) => t.trim());
|
|
1882
|
+
llm.tasks = {
|
|
1883
|
+
enhance: taskNames.includes("enhance"),
|
|
1884
|
+
summarize: taskNames.includes("summarize"),
|
|
1885
|
+
categorize: taskNames.includes("categorize"),
|
|
1886
|
+
releaseNotes: taskNames.includes("release-notes") || taskNames.includes("releaseNotes")
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
config.releaseNotes = {
|
|
1890
|
+
...existingRn,
|
|
1891
|
+
llm
|
|
1892
|
+
};
|
|
1893
|
+
info(`LLM configured: ${llm.provider}${llm.model ? ` (${llm.model})` : ""}`);
|
|
1894
|
+
if (llm.baseURL) {
|
|
1895
|
+
info(`LLM base URL: ${llm.baseURL}`);
|
|
1896
|
+
}
|
|
1897
|
+
const taskList = Object.entries(llm.tasks || {}).filter(([, enabled]) => enabled).map(([name]) => name).join(", ");
|
|
1898
|
+
if (taskList) {
|
|
1899
|
+
info(`LLM tasks: ${taskList}`);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
let inputJson;
|
|
1904
|
+
if (options.input) {
|
|
1905
|
+
inputJson = fs10.readFileSync(options.input, "utf-8");
|
|
1906
|
+
} else {
|
|
1907
|
+
inputJson = await readStdin();
|
|
1908
|
+
}
|
|
1909
|
+
const input = parseVersionOutput(inputJson);
|
|
1910
|
+
if (options.target) {
|
|
1911
|
+
const before = input.packages.length;
|
|
1912
|
+
input.packages = input.packages.filter((p) => p.packageName === options.target);
|
|
1913
|
+
if (input.packages.length === 0) {
|
|
1914
|
+
info(`No changelog found for package "${options.target}" (had ${before} package(s))`);
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
info(`Filtered to package: ${options.target}`);
|
|
1918
|
+
}
|
|
1919
|
+
if (options.monorepo) {
|
|
1920
|
+
const monoMode = options.monorepo;
|
|
1921
|
+
config.monorepo = { ...config.monorepo, mode: monoMode };
|
|
1922
|
+
if (config.changelog !== false && !options.changelogMode) {
|
|
1923
|
+
config.changelog = { ...config.changelog ?? {}, mode: monoMode };
|
|
1924
|
+
}
|
|
1925
|
+
if (config.releaseNotes !== false && config.releaseNotes !== void 0 && !options.releaseNotesMode) {
|
|
1926
|
+
config.releaseNotes = { ...config.releaseNotes, mode: monoMode };
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
await runPipeline(input, config, options.dryRun ?? false);
|
|
1930
|
+
if (options.dryRun) {
|
|
1931
|
+
info("Dry run complete - no files were written");
|
|
1932
|
+
} else {
|
|
1933
|
+
success("Changelog generation complete");
|
|
1934
|
+
}
|
|
1935
|
+
} catch (err) {
|
|
1936
|
+
handleError(err);
|
|
1937
|
+
}
|
|
1938
|
+
});
|
|
1939
|
+
cmd.command("auth <provider>").description("Configure API key for an LLM provider").option("--key <key>", "API key (omit to be prompted)").action(async (provider, options) => {
|
|
1940
|
+
let apiKey;
|
|
1941
|
+
if (options.key) {
|
|
1942
|
+
apiKey = options.key;
|
|
1943
|
+
} else {
|
|
1944
|
+
apiKey = await promptSecret(`Enter API key for ${provider}: `);
|
|
1945
|
+
}
|
|
1946
|
+
if (!apiKey.trim()) {
|
|
1947
|
+
error("API key cannot be empty");
|
|
1948
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
1949
|
+
}
|
|
1950
|
+
saveAuth(provider, apiKey.trim());
|
|
1951
|
+
success(`API key saved for ${provider}`);
|
|
1952
|
+
});
|
|
1953
|
+
cmd.command("providers").description("List available LLM providers").action(() => {
|
|
1954
|
+
info("Available LLM providers:");
|
|
1955
|
+
console.log(" openai - OpenAI (GPT models)");
|
|
1956
|
+
console.log(" anthropic - Anthropic (Claude models)");
|
|
1957
|
+
console.log(" ollama - Ollama (local models)");
|
|
1958
|
+
console.log(" openai-compatible - Any OpenAI-compatible endpoint");
|
|
1959
|
+
});
|
|
1960
|
+
return cmd;
|
|
1961
|
+
}
|
|
1962
|
+
function increaseVerbosity(_, previous) {
|
|
1963
|
+
return previous + 1;
|
|
1964
|
+
}
|
|
1965
|
+
function setVerbosity(level) {
|
|
1966
|
+
const levels = ["info", "debug", "trace"];
|
|
1967
|
+
setLogLevel(levels[Math.min(level, levels.length - 1)] ?? "info");
|
|
1968
|
+
}
|
|
1969
|
+
async function readStdin() {
|
|
1970
|
+
const chunks = [];
|
|
1971
|
+
for await (const chunk of process.stdin) {
|
|
1972
|
+
chunks.push(chunk);
|
|
1973
|
+
}
|
|
1974
|
+
return chunks.join("");
|
|
1975
|
+
}
|
|
1976
|
+
function promptSecret(prompt) {
|
|
1977
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1978
|
+
return new Promise((resolve2) => {
|
|
1979
|
+
rl.question(prompt, (answer) => {
|
|
1980
|
+
rl.close();
|
|
1981
|
+
resolve2(answer);
|
|
1982
|
+
});
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
function handleError(err) {
|
|
1986
|
+
if (err instanceof NotesError) {
|
|
1987
|
+
err.logError();
|
|
1988
|
+
process.exit(getExitCode(err));
|
|
1989
|
+
}
|
|
1990
|
+
error(err instanceof Error ? err.message : String(err));
|
|
1991
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1798
1994
|
export {
|
|
1799
1995
|
loadAuth,
|
|
1800
1996
|
saveAuth,
|
|
1801
|
-
loadConfig,
|
|
1802
1997
|
NotesError,
|
|
1803
1998
|
InputParseError,
|
|
1804
1999
|
TemplateError,
|
|
@@ -1809,9 +2004,10 @@ export {
|
|
|
1809
2004
|
parseVersionOutput,
|
|
1810
2005
|
parseVersionOutputFile,
|
|
1811
2006
|
parseVersionOutputStdin,
|
|
1812
|
-
loadConfig2,
|
|
2007
|
+
loadConfig2 as loadConfig,
|
|
1813
2008
|
getDefaultConfig,
|
|
1814
2009
|
createTemplateContext,
|
|
1815
2010
|
runPipeline,
|
|
1816
|
-
processInput
|
|
2011
|
+
processInput,
|
|
2012
|
+
createNotesCommand
|
|
1817
2013
|
};
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
export { createNotesCommand } from './command.ts';
|
|
3
|
+
import './core/config.ts';
|
|
4
|
+
import './core/pipeline.ts';
|
|
5
|
+
import './core/types.ts';
|
|
6
|
+
import './errors/index.ts';
|
|
7
|
+
import './input/version-output.ts';
|
|
8
|
+
import './monorepo/aggregator.ts';
|
|
9
|
+
import './output/json.ts';
|
|
10
|
+
import './output/markdown.ts';
|
package/dist/cli.js
CHANGED
|
@@ -1,216 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
loadConfig,
|
|
6
|
-
parseVersionOutput,
|
|
7
|
-
runPipeline,
|
|
8
|
-
saveAuth
|
|
9
|
-
} from "./chunk-FNIE2SHL.js";
|
|
3
|
+
createNotesCommand
|
|
4
|
+
} from "./chunk-Y4S5UWCL.js";
|
|
10
5
|
import {
|
|
11
|
-
|
|
12
|
-
error,
|
|
13
|
-
info,
|
|
14
|
-
readPackageVersion,
|
|
15
|
-
setLogLevel,
|
|
16
|
-
setQuietMode,
|
|
17
|
-
success,
|
|
18
|
-
warn
|
|
6
|
+
readPackageVersion
|
|
19
7
|
} from "./chunk-7TJSPQPW.js";
|
|
20
8
|
|
|
21
9
|
// src/cli.ts
|
|
22
10
|
import * as fs from "fs";
|
|
23
|
-
import * as readline from "readline";
|
|
24
11
|
import { fileURLToPath } from "url";
|
|
25
|
-
import { Command } from "commander";
|
|
26
|
-
function createNotesCommand() {
|
|
27
|
-
const cmd = new Command("notes").description(
|
|
28
|
-
"Generate changelogs with LLM-powered enhancement and flexible templating"
|
|
29
|
-
);
|
|
30
|
-
cmd.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("--no-changelog", "Disable changelog generation").option("--changelog-mode <mode>", "Changelog location mode (root|packages|both)").option("--changelog-file <name>", "Changelog file name override").option("--release-notes-mode <mode>", "Enable release notes and set location (root|packages|both)").option("--release-notes-file <name>", "Release notes file name override").option("--no-release-notes", "Disable release notes generation").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("--regenerate", "Regenerate entire changelog instead of prepending new entries").option("--dry-run", "Preview without writing").option("-v, --verbose", "Increase verbosity", increaseVerbosity, 0).option("-q, --quiet", "Suppress non-error output").action(async (options) => {
|
|
31
|
-
setVerbosity(options.verbose);
|
|
32
|
-
if (options.quiet) setQuietMode(true);
|
|
33
|
-
try {
|
|
34
|
-
const loadedConfig = loadConfig({ cwd: process.cwd(), configPath: options.config });
|
|
35
|
-
const config = loadedConfig?.notes ?? {};
|
|
36
|
-
if (loadedConfig?.monorepo && !config.monorepo) {
|
|
37
|
-
config.monorepo = loadedConfig.monorepo;
|
|
38
|
-
}
|
|
39
|
-
if (options.changelog === false) {
|
|
40
|
-
config.changelog = false;
|
|
41
|
-
} else if (options.changelogMode || options.changelogFile) {
|
|
42
|
-
const existing = config.changelog !== false ? config.changelog ?? {} : {};
|
|
43
|
-
const mode = options.changelogMode ?? existing.mode ?? "root";
|
|
44
|
-
config.changelog = {
|
|
45
|
-
...existing,
|
|
46
|
-
mode,
|
|
47
|
-
...options.changelogFile ? { file: options.changelogFile } : {}
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (options.releaseNotes === false) {
|
|
51
|
-
config.releaseNotes = false;
|
|
52
|
-
} else if (options.releaseNotesMode || options.releaseNotesFile) {
|
|
53
|
-
const existing = config.releaseNotes !== false ? config.releaseNotes ?? {} : {};
|
|
54
|
-
const mode = options.releaseNotesMode ?? existing.mode ?? "root";
|
|
55
|
-
config.releaseNotes = {
|
|
56
|
-
...existing,
|
|
57
|
-
mode,
|
|
58
|
-
...options.releaseNotesFile ? { file: options.releaseNotesFile } : {}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
if (config.changelog === false && (options.template || options.engine)) {
|
|
62
|
-
const ignored = [options.template && "--template", options.engine && "--engine"].filter(Boolean).join(" and ");
|
|
63
|
-
warn(`${ignored} ignored: changelog is disabled via --no-changelog`);
|
|
64
|
-
}
|
|
65
|
-
if (options.template && config.changelog !== false) {
|
|
66
|
-
const existing = config.changelog ?? {};
|
|
67
|
-
config.changelog = {
|
|
68
|
-
...existing,
|
|
69
|
-
templates: { ...existing.templates, path: options.template }
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (options.engine && config.changelog !== false) {
|
|
73
|
-
const existing = config.changelog ?? {};
|
|
74
|
-
config.changelog = {
|
|
75
|
-
...existing,
|
|
76
|
-
templates: { ...existing.templates, engine: options.engine }
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
if (options.regenerate) {
|
|
80
|
-
config.updateStrategy = "regenerate";
|
|
81
|
-
}
|
|
82
|
-
if (options.llm === false) {
|
|
83
|
-
if (config.releaseNotes && typeof config.releaseNotes !== "boolean" && config.releaseNotes.llm) {
|
|
84
|
-
info("LLM processing disabled via --no-llm flag");
|
|
85
|
-
config.releaseNotes = { ...config.releaseNotes, llm: void 0 };
|
|
86
|
-
}
|
|
87
|
-
} else if (options.llmProvider || options.llmModel || options.llmBaseUrl || options.llmTasks) {
|
|
88
|
-
if (config.releaseNotes === false) {
|
|
89
|
-
warn("--llm-* flags ignored: release notes are disabled via --no-release-notes");
|
|
90
|
-
} else {
|
|
91
|
-
const existingRn = typeof config.releaseNotes === "object" ? config.releaseNotes : {};
|
|
92
|
-
const existingLlm = existingRn.llm;
|
|
93
|
-
const llm = {
|
|
94
|
-
provider: existingLlm?.provider ?? "openai-compatible",
|
|
95
|
-
model: existingLlm?.model ?? "",
|
|
96
|
-
...existingLlm ?? {}
|
|
97
|
-
};
|
|
98
|
-
if (options.llmProvider) llm.provider = options.llmProvider;
|
|
99
|
-
if (options.llmModel) llm.model = options.llmModel;
|
|
100
|
-
if (options.llmBaseUrl) llm.baseURL = options.llmBaseUrl;
|
|
101
|
-
if (options.llmTasks) {
|
|
102
|
-
const taskNames = options.llmTasks.split(",").map((t) => t.trim());
|
|
103
|
-
llm.tasks = {
|
|
104
|
-
enhance: taskNames.includes("enhance"),
|
|
105
|
-
summarize: taskNames.includes("summarize"),
|
|
106
|
-
categorize: taskNames.includes("categorize"),
|
|
107
|
-
releaseNotes: taskNames.includes("release-notes") || taskNames.includes("releaseNotes")
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
config.releaseNotes = {
|
|
111
|
-
...existingRn,
|
|
112
|
-
llm
|
|
113
|
-
};
|
|
114
|
-
info(`LLM configured: ${llm.provider}${llm.model ? ` (${llm.model})` : ""}`);
|
|
115
|
-
if (llm.baseURL) {
|
|
116
|
-
info(`LLM base URL: ${llm.baseURL}`);
|
|
117
|
-
}
|
|
118
|
-
const taskList = Object.entries(llm.tasks || {}).filter(([, enabled]) => enabled).map(([name]) => name).join(", ");
|
|
119
|
-
if (taskList) {
|
|
120
|
-
info(`LLM tasks: ${taskList}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
let inputJson;
|
|
125
|
-
if (options.input) {
|
|
126
|
-
inputJson = fs.readFileSync(options.input, "utf-8");
|
|
127
|
-
} else {
|
|
128
|
-
inputJson = await readStdin();
|
|
129
|
-
}
|
|
130
|
-
const input = parseVersionOutput(inputJson);
|
|
131
|
-
if (options.target) {
|
|
132
|
-
const before = input.packages.length;
|
|
133
|
-
input.packages = input.packages.filter((p) => p.packageName === options.target);
|
|
134
|
-
if (input.packages.length === 0) {
|
|
135
|
-
info(`No changelog found for package "${options.target}" (had ${before} package(s))`);
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
info(`Filtered to package: ${options.target}`);
|
|
139
|
-
}
|
|
140
|
-
if (options.monorepo) {
|
|
141
|
-
const monoMode = options.monorepo;
|
|
142
|
-
config.monorepo = { ...config.monorepo, mode: monoMode };
|
|
143
|
-
if (config.changelog !== false && !options.changelogMode) {
|
|
144
|
-
config.changelog = { ...config.changelog ?? {}, mode: monoMode };
|
|
145
|
-
}
|
|
146
|
-
if (config.releaseNotes !== false && config.releaseNotes !== void 0 && !options.releaseNotesMode) {
|
|
147
|
-
config.releaseNotes = { ...config.releaseNotes, mode: monoMode };
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
await runPipeline(input, config, options.dryRun ?? false);
|
|
151
|
-
if (options.dryRun) {
|
|
152
|
-
info("Dry run complete - no files were written");
|
|
153
|
-
} else {
|
|
154
|
-
success("Changelog generation complete");
|
|
155
|
-
}
|
|
156
|
-
} catch (err) {
|
|
157
|
-
handleError(err);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
cmd.command("auth <provider>").description("Configure API key for an LLM provider").option("--key <key>", "API key (omit to be prompted)").action(async (provider, options) => {
|
|
161
|
-
let apiKey;
|
|
162
|
-
if (options.key) {
|
|
163
|
-
apiKey = options.key;
|
|
164
|
-
} else {
|
|
165
|
-
apiKey = await promptSecret(`Enter API key for ${provider}: `);
|
|
166
|
-
}
|
|
167
|
-
if (!apiKey.trim()) {
|
|
168
|
-
error("API key cannot be empty");
|
|
169
|
-
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
170
|
-
}
|
|
171
|
-
saveAuth(provider, apiKey.trim());
|
|
172
|
-
success(`API key saved for ${provider}`);
|
|
173
|
-
});
|
|
174
|
-
cmd.command("providers").description("List available LLM providers").action(() => {
|
|
175
|
-
info("Available LLM providers:");
|
|
176
|
-
console.log(" openai - OpenAI (GPT models)");
|
|
177
|
-
console.log(" anthropic - Anthropic (Claude models)");
|
|
178
|
-
console.log(" ollama - Ollama (local models)");
|
|
179
|
-
console.log(" openai-compatible - Any OpenAI-compatible endpoint");
|
|
180
|
-
});
|
|
181
|
-
return cmd;
|
|
182
|
-
}
|
|
183
|
-
function increaseVerbosity(_, previous) {
|
|
184
|
-
return previous + 1;
|
|
185
|
-
}
|
|
186
|
-
function setVerbosity(level) {
|
|
187
|
-
const levels = ["info", "debug", "trace"];
|
|
188
|
-
setLogLevel(levels[Math.min(level, levels.length - 1)] ?? "info");
|
|
189
|
-
}
|
|
190
|
-
async function readStdin() {
|
|
191
|
-
const chunks = [];
|
|
192
|
-
for await (const chunk of process.stdin) {
|
|
193
|
-
chunks.push(chunk);
|
|
194
|
-
}
|
|
195
|
-
return chunks.join("");
|
|
196
|
-
}
|
|
197
|
-
function promptSecret(prompt) {
|
|
198
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
199
|
-
return new Promise((resolve) => {
|
|
200
|
-
rl.question(prompt, (answer) => {
|
|
201
|
-
rl.close();
|
|
202
|
-
resolve(answer);
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
function handleError(err) {
|
|
207
|
-
if (err instanceof NotesError) {
|
|
208
|
-
err.logError();
|
|
209
|
-
process.exit(getExitCode(err));
|
|
210
|
-
}
|
|
211
|
-
error(err instanceof Error ? err.message : String(err));
|
|
212
|
-
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
213
|
-
}
|
|
214
12
|
var isMain = (() => {
|
|
215
13
|
try {
|
|
216
14
|
return process.argv[1] ? fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url) : false;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { createNotesCommand } from './command.ts';
|
|
1
2
|
export { getDefaultConfig, loadAuth, loadConfig, saveAuth } from './core/config.ts';
|
|
2
3
|
export { PipelineResult, createTemplateContext, processInput, runPipeline } from './core/pipeline.ts';
|
|
3
4
|
export * from './core/types.ts';
|
package/dist/index.js
CHANGED
|
@@ -5,18 +5,19 @@ import {
|
|
|
5
5
|
LLMError,
|
|
6
6
|
NotesError,
|
|
7
7
|
TemplateError,
|
|
8
|
+
createNotesCommand,
|
|
8
9
|
createTemplateContext,
|
|
9
10
|
getDefaultConfig,
|
|
10
11
|
getExitCode,
|
|
11
12
|
loadAuth,
|
|
12
|
-
|
|
13
|
+
loadConfig,
|
|
13
14
|
parseVersionOutput,
|
|
14
15
|
parseVersionOutputFile,
|
|
15
16
|
parseVersionOutputStdin,
|
|
16
17
|
processInput,
|
|
17
18
|
runPipeline,
|
|
18
19
|
saveAuth
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-Y4S5UWCL.js";
|
|
20
21
|
import {
|
|
21
22
|
aggregateToRoot,
|
|
22
23
|
detectMonorepo,
|
|
@@ -74,6 +75,7 @@ export {
|
|
|
74
75
|
NotesError,
|
|
75
76
|
TemplateError,
|
|
76
77
|
aggregateToRoot,
|
|
78
|
+
createNotesCommand,
|
|
77
79
|
createTemplateContext,
|
|
78
80
|
detectMonorepo,
|
|
79
81
|
formatVersion,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@releasekit/notes",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.13",
|
|
4
4
|
"description": "Release notes and changelog generation with LLM-powered enhancement and flexible templating",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"tsup": "^8.5.1",
|
|
67
67
|
"typescript": "^5.9.3",
|
|
68
68
|
"vitest": "^4.1.2",
|
|
69
|
-
"@releasekit/
|
|
70
|
-
"@releasekit/
|
|
69
|
+
"@releasekit/core": "0.0.0",
|
|
70
|
+
"@releasekit/config": "0.0.0"
|
|
71
71
|
},
|
|
72
72
|
"engines": {
|
|
73
73
|
"node": ">=20"
|