@releasekit/notes 0.3.1 → 0.4.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/README.md +99 -73
- package/dist/{aggregator-XJ2EILO3.js → aggregator-IUQUAVJC.js} +2 -2
- package/dist/{chunk-E4454SIS.js → chunk-7TJSPQPW.js} +1 -1
- package/dist/{chunk-DCQ32FVH.js → chunk-F7MUVHZ2.js} +5 -5
- package/dist/{chunk-ENAWZXFG.js → chunk-QX23CBNW.js} +190 -334
- package/dist/cli.js +93 -64
- package/dist/index.js +44 -7
- package/docs/configuration.md +276 -0
- package/docs/llm-providers.md +246 -0
- package/docs/monorepo.md +124 -0
- package/docs/templates.md +204 -0
- package/package.json +5 -4
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
NotesError,
|
|
4
|
-
getDefaultConfig,
|
|
5
4
|
getExitCode,
|
|
6
5
|
loadConfig,
|
|
7
6
|
parseVersionOutput,
|
|
8
7
|
runPipeline,
|
|
9
8
|
saveAuth
|
|
10
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QX23CBNW.js";
|
|
11
10
|
import {
|
|
12
11
|
EXIT_CODES,
|
|
13
12
|
error,
|
|
@@ -15,8 +14,9 @@ import {
|
|
|
15
14
|
readPackageVersion,
|
|
16
15
|
setLogLevel,
|
|
17
16
|
setQuietMode,
|
|
18
|
-
success
|
|
19
|
-
|
|
17
|
+
success,
|
|
18
|
+
warn
|
|
19
|
+
} from "./chunk-7TJSPQPW.js";
|
|
20
20
|
|
|
21
21
|
// src/cli.ts
|
|
22
22
|
import * as fs from "fs";
|
|
@@ -27,50 +27,98 @@ function createNotesCommand() {
|
|
|
27
27
|
const cmd = new Command("notes").description(
|
|
28
28
|
"Generate changelogs with LLM-powered enhancement and flexible templating"
|
|
29
29
|
);
|
|
30
|
-
cmd.command("generate", { isDefault: true }).description("Generate changelog from input data").option("-i, --input <file>", "Input file (default: stdin)").option("-
|
|
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
31
|
setVerbosity(options.verbose);
|
|
32
32
|
if (options.quiet) setQuietMode(true);
|
|
33
33
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
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;
|
|
37
38
|
}
|
|
38
|
-
if (
|
|
39
|
-
config.
|
|
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
|
+
};
|
|
40
49
|
}
|
|
41
|
-
if (options.
|
|
42
|
-
config.
|
|
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`);
|
|
43
64
|
}
|
|
44
|
-
if (options.template) {
|
|
45
|
-
|
|
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
|
+
};
|
|
46
71
|
}
|
|
47
|
-
if (options.engine) {
|
|
48
|
-
|
|
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";
|
|
49
81
|
}
|
|
50
82
|
if (options.llm === false) {
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
}
|
|
53
87
|
} else if (options.llmProvider || options.llmModel || options.llmBaseUrl || options.llmTasks) {
|
|
54
|
-
config.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
categorize: taskNames.includes("categorize"),
|
|
64
|
-
releaseNotes: taskNames.includes("release-notes") || taskNames.includes("releaseNotes")
|
|
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 ?? {}
|
|
65
97
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
+
}
|
|
74
122
|
}
|
|
75
123
|
}
|
|
76
124
|
let inputJson;
|
|
@@ -90,7 +138,14 @@ function createNotesCommand() {
|
|
|
90
138
|
info(`Filtered to package: ${options.target}`);
|
|
91
139
|
}
|
|
92
140
|
if (options.monorepo) {
|
|
93
|
-
|
|
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
|
+
}
|
|
94
149
|
}
|
|
95
150
|
await runPipeline(input, config, options.dryRun ?? false);
|
|
96
151
|
if (options.dryRun) {
|
|
@@ -102,22 +157,6 @@ function createNotesCommand() {
|
|
|
102
157
|
handleError(err);
|
|
103
158
|
}
|
|
104
159
|
});
|
|
105
|
-
cmd.command("init").description("Create default configuration file").option("-f, --force", "Overwrite existing config").action((options) => {
|
|
106
|
-
const configPath = "releasekit.config.json";
|
|
107
|
-
if (fs.existsSync(configPath) && !options.force) {
|
|
108
|
-
error(`Config file already exists at ${configPath}. Use --force to overwrite.`);
|
|
109
|
-
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
110
|
-
}
|
|
111
|
-
const defaultConfig = {
|
|
112
|
-
$schema: "https://releasekit.dev/schema.json",
|
|
113
|
-
notes: {
|
|
114
|
-
output: [{ format: "markdown", file: "CHANGELOG.md" }],
|
|
115
|
-
updateStrategy: "prepend"
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
119
|
-
success(`Created config file at ${configPath}`);
|
|
120
|
-
});
|
|
121
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) => {
|
|
122
161
|
let apiKey;
|
|
123
162
|
if (options.key) {
|
|
@@ -141,16 +180,6 @@ function createNotesCommand() {
|
|
|
141
180
|
});
|
|
142
181
|
return cmd;
|
|
143
182
|
}
|
|
144
|
-
function collectOutputs(value, previous) {
|
|
145
|
-
const parts = value.split(":");
|
|
146
|
-
const format = parts[0] ?? "markdown";
|
|
147
|
-
const file = parts[1];
|
|
148
|
-
const spec = { format };
|
|
149
|
-
if (file) {
|
|
150
|
-
spec.file = file;
|
|
151
|
-
}
|
|
152
|
-
return [...previous, spec];
|
|
153
|
-
}
|
|
154
183
|
function increaseVerbosity(_, previous) {
|
|
155
184
|
return previous + 1;
|
|
156
185
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,26 +9,63 @@ import {
|
|
|
9
9
|
getDefaultConfig,
|
|
10
10
|
getExitCode,
|
|
11
11
|
loadAuth,
|
|
12
|
-
loadConfig,
|
|
12
|
+
loadConfig2 as loadConfig,
|
|
13
13
|
parseVersionOutput,
|
|
14
14
|
parseVersionOutputFile,
|
|
15
15
|
parseVersionOutputStdin,
|
|
16
16
|
processInput,
|
|
17
|
-
renderJson,
|
|
18
17
|
runPipeline,
|
|
19
|
-
saveAuth
|
|
20
|
-
|
|
21
|
-
} from "./chunk-ENAWZXFG.js";
|
|
18
|
+
saveAuth
|
|
19
|
+
} from "./chunk-QX23CBNW.js";
|
|
22
20
|
import {
|
|
23
21
|
aggregateToRoot,
|
|
24
22
|
detectMonorepo,
|
|
25
23
|
writeMonorepoChangelogs
|
|
26
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-F7MUVHZ2.js";
|
|
27
25
|
import {
|
|
26
|
+
debug,
|
|
28
27
|
formatVersion,
|
|
28
|
+
info,
|
|
29
29
|
renderMarkdown,
|
|
30
|
+
success,
|
|
30
31
|
writeMarkdown
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-7TJSPQPW.js";
|
|
33
|
+
|
|
34
|
+
// src/output/json.ts
|
|
35
|
+
import * as fs from "fs";
|
|
36
|
+
import * as path from "path";
|
|
37
|
+
function renderJson(contexts) {
|
|
38
|
+
return JSON.stringify(
|
|
39
|
+
{
|
|
40
|
+
versions: contexts.map((ctx) => ({
|
|
41
|
+
packageName: ctx.packageName,
|
|
42
|
+
version: ctx.version,
|
|
43
|
+
previousVersion: ctx.previousVersion,
|
|
44
|
+
date: ctx.date,
|
|
45
|
+
entries: ctx.entries,
|
|
46
|
+
compareUrl: ctx.compareUrl
|
|
47
|
+
}))
|
|
48
|
+
},
|
|
49
|
+
null,
|
|
50
|
+
2
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function writeJson(outputPath, contexts, dryRun) {
|
|
54
|
+
const content = renderJson(contexts);
|
|
55
|
+
if (dryRun) {
|
|
56
|
+
info(`Would write JSON output to ${outputPath}`);
|
|
57
|
+
debug("--- JSON Output Preview ---");
|
|
58
|
+
debug(content);
|
|
59
|
+
debug("--- End Preview ---");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const dir = path.dirname(outputPath);
|
|
63
|
+
if (!fs.existsSync(dir)) {
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
fs.writeFileSync(outputPath, content, "utf-8");
|
|
67
|
+
success(`JSON output written to ${outputPath}`);
|
|
68
|
+
}
|
|
32
69
|
export {
|
|
33
70
|
ConfigError,
|
|
34
71
|
GitHubError,
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Notes Configuration Reference
|
|
2
|
+
|
|
3
|
+
All options live under the `notes` key in `releasekit.config.json`. Add `$schema` for editor autocompletion:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"$schema": "https://goosewobbler.github.io/releasekit/schema.json",
|
|
8
|
+
"notes": {}
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## `notes.changelog`
|
|
15
|
+
|
|
16
|
+
Controls whether and where changelog files are written.
|
|
17
|
+
|
|
18
|
+
**Type:** `false | object`
|
|
19
|
+
**Default:** generates `CHANGELOG.md` at the repo root
|
|
20
|
+
|
|
21
|
+
Set to `false` to disable changelog generation entirely.
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"notes": {
|
|
26
|
+
"changelog": false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
When an object, the following properties are available:
|
|
32
|
+
|
|
33
|
+
### `notes.changelog.mode`
|
|
34
|
+
|
|
35
|
+
| Value | Behaviour |
|
|
36
|
+
|-------|-----------|
|
|
37
|
+
| `"root"` | Write a single changelog at the repo root (default) |
|
|
38
|
+
| `"packages"` | Write one changelog per package inside each package directory |
|
|
39
|
+
| `"both"` | Write both root and per-package changelogs |
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"notes": {
|
|
44
|
+
"changelog": { "mode": "packages" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `notes.changelog.file`
|
|
50
|
+
|
|
51
|
+
Override the changelog file name.
|
|
52
|
+
|
|
53
|
+
**Type:** `string`
|
|
54
|
+
**Default:** `"CHANGELOG.md"`
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"notes": {
|
|
59
|
+
"changelog": { "mode": "root", "file": "CHANGES.md" }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `notes.changelog.templates`
|
|
65
|
+
|
|
66
|
+
Custom template for changelog rendering.
|
|
67
|
+
|
|
68
|
+
| Property | Type | Description |
|
|
69
|
+
|----------|------|-------------|
|
|
70
|
+
| `path` | `string` | Path to a template file or directory |
|
|
71
|
+
| `engine` | `"handlebars" \| "liquid" \| "ejs"` | Template engine |
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"notes": {
|
|
76
|
+
"changelog": {
|
|
77
|
+
"mode": "root",
|
|
78
|
+
"templates": {
|
|
79
|
+
"path": "./templates/changelog/",
|
|
80
|
+
"engine": "liquid"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
See the [templates guide](./templates.md) for authoring details.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## `notes.releaseNotes`
|
|
92
|
+
|
|
93
|
+
Controls release notes generation. Release notes are a separate output from the changelog — typically prose-formatted and suitable for GitHub release bodies.
|
|
94
|
+
|
|
95
|
+
**Type:** `false | object`
|
|
96
|
+
**Default:** `undefined` (release notes not generated)
|
|
97
|
+
|
|
98
|
+
Set to `false` to explicitly disable when it has been enabled via config inheritance.
|
|
99
|
+
|
|
100
|
+
When an object with a `mode` or `file` property, release notes are written to a file. When only `llm` is present (no `mode`/`file`), the LLM runs but no file is written — the generated content is passed to the publish step for use as a GitHub release body.
|
|
101
|
+
|
|
102
|
+
### `notes.releaseNotes.mode`
|
|
103
|
+
|
|
104
|
+
| Value | Behaviour |
|
|
105
|
+
|-------|-----------|
|
|
106
|
+
| `"root"` | Write `RELEASE_NOTES.md` at the repo root |
|
|
107
|
+
| `"packages"` | Write one release notes file per package |
|
|
108
|
+
| `"both"` | Write both root and per-package files |
|
|
109
|
+
|
|
110
|
+
### `notes.releaseNotes.file`
|
|
111
|
+
|
|
112
|
+
Override the release notes file name.
|
|
113
|
+
|
|
114
|
+
**Type:** `string`
|
|
115
|
+
**Default:** `"RELEASE_NOTES.md"`
|
|
116
|
+
|
|
117
|
+
### `notes.releaseNotes.templates`
|
|
118
|
+
|
|
119
|
+
Same structure as `notes.changelog.templates`. See the [templates guide](./templates.md).
|
|
120
|
+
|
|
121
|
+
### `notes.releaseNotes.llm`
|
|
122
|
+
|
|
123
|
+
LLM configuration for release notes enhancement. Requires `provider` and `model`.
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"notes": {
|
|
128
|
+
"releaseNotes": {
|
|
129
|
+
"llm": {
|
|
130
|
+
"provider": "openai",
|
|
131
|
+
"model": "gpt-4o-mini",
|
|
132
|
+
"tasks": { "enhance": true, "summarize": true }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See the full LLM option reference below.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## `notes.updateStrategy`
|
|
144
|
+
|
|
145
|
+
How existing changelog files are updated when new entries are generated.
|
|
146
|
+
|
|
147
|
+
**Type:** `"prepend" | "regenerate"`
|
|
148
|
+
**Default:** `"prepend"`
|
|
149
|
+
|
|
150
|
+
| Value | Behaviour |
|
|
151
|
+
|-------|-----------|
|
|
152
|
+
| `"prepend"` | New entries are inserted at the top of the existing file |
|
|
153
|
+
| `"regenerate"` | The entire file is rewritten from scratch using all available history |
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"notes": {
|
|
158
|
+
"updateStrategy": "regenerate"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## LLM options (`notes.releaseNotes.llm`)
|
|
166
|
+
|
|
167
|
+
### Required
|
|
168
|
+
|
|
169
|
+
| Option | Type | Description |
|
|
170
|
+
|--------|------|-------------|
|
|
171
|
+
| `provider` | `string` | LLM provider key. See [LLM providers](./llm-providers.md). |
|
|
172
|
+
| `model` | `string` | Model identifier (e.g. `"gpt-4o-mini"`, `"claude-sonnet-4-5"`) |
|
|
173
|
+
|
|
174
|
+
### Connection
|
|
175
|
+
|
|
176
|
+
| Option | Type | Description |
|
|
177
|
+
|--------|------|-------------|
|
|
178
|
+
| `baseURL` | `string` | Custom API base URL (for `openai-compatible` providers) |
|
|
179
|
+
| `apiKey` | `string` | API key inline. Prefer env var or `releasekit-notes auth` over this. |
|
|
180
|
+
|
|
181
|
+
### Behaviour
|
|
182
|
+
|
|
183
|
+
| Option | Type | Default | Description |
|
|
184
|
+
|--------|------|---------|-------------|
|
|
185
|
+
| `concurrency` | `integer` | `3` | Maximum parallel LLM requests when enhancing entries |
|
|
186
|
+
|
|
187
|
+
### Model options (`options`)
|
|
188
|
+
|
|
189
|
+
| Option | Type | Description |
|
|
190
|
+
|--------|------|-------------|
|
|
191
|
+
| `timeout` | `integer` (ms) | Request timeout |
|
|
192
|
+
| `maxTokens` | `integer` | Maximum tokens to generate |
|
|
193
|
+
| `temperature` | `number` | Sampling temperature (0–2) |
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"llm": {
|
|
198
|
+
"provider": "openai",
|
|
199
|
+
"model": "gpt-4o",
|
|
200
|
+
"options": { "temperature": 0.3, "maxTokens": 1000 }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Tasks (`tasks`)
|
|
206
|
+
|
|
207
|
+
| Task | Type | Description |
|
|
208
|
+
|------|------|-------------|
|
|
209
|
+
| `enhance` | `boolean` | Rewrite each entry description to be clearer and more user-facing |
|
|
210
|
+
| `summarize` | `boolean` | Generate a one-paragraph summary of the release |
|
|
211
|
+
| `categorize` | `boolean` | Group entries into user-friendly categories (Features, Fixes, …) |
|
|
212
|
+
| `releaseNotes` | `boolean` | Generate full prose release notes suitable for a GitHub release body |
|
|
213
|
+
|
|
214
|
+
### Categories (`categories`)
|
|
215
|
+
|
|
216
|
+
Provide hints to the `categorize` task for how to group entries.
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"llm": {
|
|
221
|
+
"tasks": { "categorize": true },
|
|
222
|
+
"categories": [
|
|
223
|
+
{ "name": "Features", "description": "New user-facing functionality" },
|
|
224
|
+
{ "name": "Bug Fixes", "description": "Corrections to existing behaviour" },
|
|
225
|
+
{ "name": "Performance", "description": "Speed or resource improvements" }
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Each category object:
|
|
232
|
+
|
|
233
|
+
| Field | Required | Description |
|
|
234
|
+
|-------|----------|-------------|
|
|
235
|
+
| `name` | yes | Display name used in template rendering |
|
|
236
|
+
| `description` | yes | Hint sent to the LLM to guide grouping |
|
|
237
|
+
| `scopes` | no | Commit scopes that always map to this category |
|
|
238
|
+
|
|
239
|
+
### Style (`style`)
|
|
240
|
+
|
|
241
|
+
A brief style instruction appended to every LLM prompt.
|
|
242
|
+
|
|
243
|
+
```json
|
|
244
|
+
{
|
|
245
|
+
"llm": {
|
|
246
|
+
"style": "Use concise, non-technical language suitable for end users."
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Retry (`retry`)
|
|
252
|
+
|
|
253
|
+
| Option | Type | Default | Description |
|
|
254
|
+
|--------|------|---------|-------------|
|
|
255
|
+
| `maxAttempts` | `integer` | `3` | Maximum retries on failure |
|
|
256
|
+
| `initialDelay` | `integer` (ms) | `500` | Delay before first retry |
|
|
257
|
+
| `maxDelay` | `integer` (ms) | `10000` | Maximum delay between retries |
|
|
258
|
+
| `backoffFactor` | `number` | `2` | Exponential backoff multiplier |
|
|
259
|
+
|
|
260
|
+
### Prompt overrides (`prompts`)
|
|
261
|
+
|
|
262
|
+
Override the built-in prompt instructions or templates for any task. The key is the task name (`enhance`, `categorize`, `summarize`, `releaseNotes`).
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"llm": {
|
|
267
|
+
"prompts": {
|
|
268
|
+
"instructions": {
|
|
269
|
+
"enhance": "Rewrite the description from a developer's perspective, keeping it technical."
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
See the [LLM providers guide](./llm-providers.md) for examples.
|