release-note 0.0.0 → 0.0.1
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 +244 -1
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +37 -0
- package/dist/bin.mjs.map +1 -0
- package/dist/generate-CsLUDr-g.mjs +403 -0
- package/dist/generate-CsLUDr-g.mjs.map +1 -0
- package/dist/index.d.mts +45 -4
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +21 -6
- package/dist/index.cjs +0 -14
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -7
package/README.md
CHANGED
|
@@ -1 +1,244 @@
|
|
|
1
|
-
#
|
|
1
|
+
# release-note
|
|
2
|
+
|
|
3
|
+
AI-powered release note generator. Reads your git history between two refs, then asks an LLM to draft user-facing release notes — with the ability to inspect diffs and browse the tree at any commit for accurate, grounded output.
|
|
4
|
+
|
|
5
|
+
Works as a CLI or as a programmatic library.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Git-aware**: pick a range by tag regex (e.g. `v.*`) or explicit commit hash.
|
|
10
|
+
- **Agentic**: the model can call `check_diff` and `browse_code` tools to look up the actual changes before writing.
|
|
11
|
+
- **Multi-provider**: ships support for OpenAI, Anthropic, Google, xAI, Azure, Bedrock, Groq, Mistral, DeepSeek, Cohere, Fireworks, Perplexity, OpenRouter, TogetherAI, DeepInfra, Cerebras, Fal, Luma, Baseten, Vertex, and any OpenAI-compatible endpoint.
|
|
12
|
+
- **Configurable**: JSON / JSONC config file, CLI flags, or full programmatic control.
|
|
13
|
+
- **Audience-tuned prompts**: output is written for end users and PMs, not engineers. Internal identifiers, file paths, and implementation details are filtered out automatically.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add release-note
|
|
19
|
+
# or
|
|
20
|
+
npm install release-note
|
|
21
|
+
# or
|
|
22
|
+
yarn add release-note
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you plan to use OpenRouter, also install its peer dependency:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @openrouter/ai-sdk-provider
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For other providers, the corresponding `@ai-sdk/*` package is required at runtime and is **not** bundled with `release-note`.
|
|
32
|
+
|
|
33
|
+
## CLI
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
release-note generate [options]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
|
|
41
|
+
| Flag | Description |
|
|
42
|
+
| ----------- | ----------------------------------------------- |
|
|
43
|
+
| `--cwd` | Working directory (defaults to `process.cwd()`) |
|
|
44
|
+
| `--config` | Path to a config file |
|
|
45
|
+
| `--outFile` | Write the result to a file instead of stdout |
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Print to stdout
|
|
51
|
+
release-note generate
|
|
52
|
+
|
|
53
|
+
# Use a specific config
|
|
54
|
+
release-note generate --config ./configs/release.json
|
|
55
|
+
|
|
56
|
+
# Save the result to a file
|
|
57
|
+
release-note generate --outFile RELEASE_NOTES.md
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Programmatic API
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import releaseNote from 'release-note'
|
|
64
|
+
|
|
65
|
+
const { note, commits, provider } = await releaseNote(process.cwd(), {
|
|
66
|
+
model: 'nvidia/nemotron-3-ultra-550b-a55b:free',
|
|
67
|
+
provider: '@openrouter/ai-sdk-provider',
|
|
68
|
+
match: { tag: 'v.*' },
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
console.log(note)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The `releaseNote` named export is also available:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { releaseNote } from 'release-note'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Return value
|
|
81
|
+
|
|
82
|
+
| Field | Type | Description |
|
|
83
|
+
| ---------- | ----------------- | ------------------------------------- |
|
|
84
|
+
| `note` | `string` | The generated release note text |
|
|
85
|
+
| `commits` | `GitCommitInfo[]` | The commits included in the range |
|
|
86
|
+
| `provider` | `object` | Raw provider response and token usage |
|
|
87
|
+
|
|
88
|
+
### `GitCommitInfo`
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
type GitCommitInfo = {
|
|
92
|
+
hash: string
|
|
93
|
+
date: string
|
|
94
|
+
message: string
|
|
95
|
+
author_name: string
|
|
96
|
+
author_email: string
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
`release-note` looks for the first existing file in this order:
|
|
103
|
+
|
|
104
|
+
1. `release-note.json`
|
|
105
|
+
2. `release-note.jsonc`
|
|
106
|
+
3. `.github/release-note.json`
|
|
107
|
+
4. `.github/release-note.jsonc`
|
|
108
|
+
|
|
109
|
+
Use `--config <path>` to point at a different file. JSONC (with comments and trailing commas) is supported.
|
|
110
|
+
|
|
111
|
+
### Schema
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
{
|
|
115
|
+
// Commit range. Either a tag regex or an explicit commit.
|
|
116
|
+
// Default: { tag: '.*' }
|
|
117
|
+
match: { tag: string } | { commit: string }
|
|
118
|
+
|
|
119
|
+
// Model identifier. Required.
|
|
120
|
+
model: string
|
|
121
|
+
|
|
122
|
+
// Optional cap on agent steps. Defaults to (commits + 1) * 2.
|
|
123
|
+
steps?: number
|
|
124
|
+
|
|
125
|
+
// Provider package. Default: '@ai-sdk/openai-compatible'
|
|
126
|
+
provider: '@ai-sdk/openai'
|
|
127
|
+
| '@ai-sdk/openai-compatible'
|
|
128
|
+
| '@ai-sdk/anthropic'
|
|
129
|
+
| '@ai-sdk/google'
|
|
130
|
+
| '@ai-sdk/xai'
|
|
131
|
+
| '@ai-sdk/azure'
|
|
132
|
+
| '@ai-sdk/amazon-bedrock'
|
|
133
|
+
| '@ai-sdk/groq'
|
|
134
|
+
| '@ai-sdk/fal'
|
|
135
|
+
| '@ai-sdk/deepinfra'
|
|
136
|
+
| '@ai-sdk/google-vertex'
|
|
137
|
+
| '@ai-sdk/mistral'
|
|
138
|
+
| '@ai-sdk/togetherai'
|
|
139
|
+
| '@ai-sdk/cohere'
|
|
140
|
+
| '@ai-sdk/fireworks'
|
|
141
|
+
| '@ai-sdk/deepseek'
|
|
142
|
+
| '@ai-sdk/cerebras'
|
|
143
|
+
| '@ai-sdk/perplexity'
|
|
144
|
+
| '@ai-sdk/luma'
|
|
145
|
+
| '@ai-sdk/baseten'
|
|
146
|
+
| '@openrouter/ai-sdk-provider'
|
|
147
|
+
|
|
148
|
+
// Required when provider is '@ai-sdk/openai-compatible'.
|
|
149
|
+
apiUrl?: string
|
|
150
|
+
|
|
151
|
+
// Environment variable name(s) holding the API key.
|
|
152
|
+
// If an array is given, only the first entry is consulted.
|
|
153
|
+
apiKeyEnv?: string | string[]
|
|
154
|
+
|
|
155
|
+
// Extra HTTP headers for the provider.
|
|
156
|
+
headers?: Record<string, string>
|
|
157
|
+
|
|
158
|
+
// Extra provider options (passed through to the provider factory).
|
|
159
|
+
options?: Record<string, unknown>
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Example: OpenRouter
|
|
164
|
+
|
|
165
|
+
`release-note.json`
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"model": "nvidia/nemotron-3-ultra-550b-a55b:free",
|
|
170
|
+
"provider": "@openrouter/ai-sdk-provider",
|
|
171
|
+
"apiKeyEnv": "OPENROUTER_API_KEY",
|
|
172
|
+
"match": { "tag": "v.*" }
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Example: OpenAI-compatible endpoint (LM Studio, vLLM, etc.)
|
|
177
|
+
|
|
178
|
+
`release-note.json`
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"model": "local-model",
|
|
183
|
+
"provider": "@ai-sdk/openai-compatible",
|
|
184
|
+
"apiUrl": "http://localhost:1234/v1",
|
|
185
|
+
"apiKeyEnv": "LLM_API_KEY",
|
|
186
|
+
"headers": {
|
|
187
|
+
"X-Custom-Header": "value"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Example: explicit commit range
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"model": "gpt-4o",
|
|
197
|
+
"provider": "@ai-sdk/openai",
|
|
198
|
+
"apiKeyEnv": "OPENAI_API_KEY",
|
|
199
|
+
"match": { "commit": "HEAD" }
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
> With `match.tag`, the most recent matching tag becomes the upper bound and the next-most-recent becomes the lower bound. With `match.commit`, both bounds resolve to the same hash, so the log covers that single commit.
|
|
204
|
+
|
|
205
|
+
## How it works
|
|
206
|
+
|
|
207
|
+
1. Resolves the commit range from `match` (latest and previous matching tags, or an explicit commit).
|
|
208
|
+
2. Collects the commits in that range via `simple-git`.
|
|
209
|
+
3. Sends the commit list to the configured model, along with two tools:
|
|
210
|
+
- `check_diff(commithash)` — returns the full patch for a commit.
|
|
211
|
+
- `browse_code(commithash, path)` — returns the file content or folder listing at a path within a commit.
|
|
212
|
+
4. The model may call these tools to gather context, then produces the final release note.
|
|
213
|
+
5. Returns the text (and writes it to `--outFile` if provided).
|
|
214
|
+
|
|
215
|
+
The system prompt enforces:
|
|
216
|
+
|
|
217
|
+
- No top-level title wrapping the content as "Release Note".
|
|
218
|
+
- Section headings via `##`, not `---` separators.
|
|
219
|
+
- Grouped sections such as **New Features**, **Bug Fixes**, **Improvements**, **Breaking Changes**.
|
|
220
|
+
- No internal identifiers (paths, class/function names, env keys, etc.) and no secrets.
|
|
221
|
+
- Trivial changes (formatting, refactors, dependency bumps with no user impact) are skipped.
|
|
222
|
+
|
|
223
|
+
## Requirements
|
|
224
|
+
|
|
225
|
+
- Node.js 18+ (ES modules).
|
|
226
|
+
- A git repository to read history from.
|
|
227
|
+
- An API key for whichever provider you configure.
|
|
228
|
+
|
|
229
|
+
## Development
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
pnpm install
|
|
233
|
+
pnpm dev # build in watch mode + typecheck
|
|
234
|
+
pnpm build # produce dist/
|
|
235
|
+
pnpm typecheck # tsc --noEmit
|
|
236
|
+
pnpm lint # eslint .
|
|
237
|
+
pnpm lint:fix # eslint . --fix
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The build is driven by [tsdown](https://github.com/rolldown/tsdown) and emits ESM into `dist/`.
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
No license has been declared in `package.json` yet. Add a `LICENSE` file and a `license` field in `package.json` before publishing.
|
package/dist/bin.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/bin.mjs
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { i as _asyncToGenerator, n as resolveConfig, r as _objectSpread2, t as generateReleaseNote } from "./generate-CsLUDr-g.mjs";
|
|
3
|
+
import { Command } from "@commander-js/extra-typings";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
//#region src/args.ts
|
|
7
|
+
function createArgs() {
|
|
8
|
+
return _createArgs.apply(this, arguments);
|
|
9
|
+
}
|
|
10
|
+
function _createArgs() {
|
|
11
|
+
_createArgs = _asyncToGenerator(function* () {
|
|
12
|
+
const program = new Command("release-note");
|
|
13
|
+
program.command("generate").description("Generate release notes between two versions").option("--cwd [string]", "Current working directory").option("--config [string]", "Path to release-note config file").option("--outFile [string]", "Path to output file (defaults to stdout)").action(function() {
|
|
14
|
+
var _ref = _asyncToGenerator(function* (options) {
|
|
15
|
+
const resolvedCwd = typeof options.cwd === "string" ? options.cwd : process.cwd();
|
|
16
|
+
const result = yield generateReleaseNote(resolvedCwd, _objectSpread2({}, yield resolveConfig(resolvedCwd, typeof options.config === "string" ? [options.config] : void 0)));
|
|
17
|
+
if (typeof options.outFile === "string") {
|
|
18
|
+
const outPath = path.join(resolvedCwd, options.outFile);
|
|
19
|
+
yield fs.promises.writeFile(outPath, result.note, "utf8");
|
|
20
|
+
console.log(`Release note written to ${outPath}`);
|
|
21
|
+
} else process.stdout.write(result.note);
|
|
22
|
+
});
|
|
23
|
+
return function(_x) {
|
|
24
|
+
return _ref.apply(this, arguments);
|
|
25
|
+
};
|
|
26
|
+
}());
|
|
27
|
+
return program;
|
|
28
|
+
});
|
|
29
|
+
return _createArgs.apply(this, arguments);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/bin.ts
|
|
33
|
+
createArgs().then((p) => p.parse());
|
|
34
|
+
//#endregion
|
|
35
|
+
export {};
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=bin.mjs.map
|
package/dist/bin.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.mjs","names":[],"sources":["../src/args.ts","../src/bin.ts"],"sourcesContent":["import { Command } from '@commander-js/extra-typings'\nimport fs from 'fs'\nimport path from 'path'\nimport { resolveConfig } from './config/resolve-config.js'\nimport { generateReleaseNote } from './generate/index.js'\n\nexport async function createArgs() {\n const program = new Command('release-note')\n\n program\n .command('generate')\n .description('Generate release notes between two versions')\n .option('--cwd [string]', 'Current working directory')\n .option('--config [string]', 'Path to release-note config file')\n .option('--outFile [string]', 'Path to output file (defaults to stdout)')\n .action(async (options) => {\n const resolvedCwd =\n typeof options.cwd === 'string' ? options.cwd : process.cwd()\n\n const resolvedConfigPath =\n typeof options.config === 'string' ? [options.config] : undefined\n\n const config = await resolveConfig(resolvedCwd, resolvedConfigPath)\n const result = await generateReleaseNote(resolvedCwd, { ...config })\n\n if (typeof options.outFile === 'string') {\n const outPath = path.join(resolvedCwd, options.outFile)\n await fs.promises.writeFile(outPath, result.note, 'utf8')\n console.log(`Release note written to ${outPath}`)\n } else {\n process.stdout.write(result.note)\n }\n })\n\n return program\n}\n","#!/usr/bin/env node\n\nimport { createArgs } from './args.js'\n\nvoid createArgs().then((p) => p.parse())\n"],"mappings":";;;;;;AAMA,SAAsB,aAAA;;;;8CAAa;EACjC,MAAM,UAAU,IAAI,QAAQ,cAAc;EAE1C,QACG,QAAQ,UAAU,EAClB,YAAY,6CAA6C,EACzD,OAAO,kBAAkB,2BAA2B,EACpD,OAAO,qBAAqB,kCAAkC,EAC9D,OAAO,sBAAsB,0CAA0C,EACvE,OAAA,WAAA;2CAAc,SAAY;IACzB,MAAM,cACJ,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,QAAQ,IAAI;IAM9D,MAAM,SAAS,MAAM,oBAAoB,aAAA,eAAA,CAAA,GAAkB,MADtC,cAAc,aAFjC,OAAO,QAAQ,WAAW,WAAW,CAAC,QAAQ,MAAM,IAAI,KAAA,CAEQ,CACA,CAAC;IAEnE,IAAI,OAAO,QAAQ,YAAY,UAAU;KACvC,MAAM,UAAU,KAAK,KAAK,aAAa,QAAQ,OAAO;KACtD,MAAM,GAAG,SAAS,UAAU,SAAS,OAAO,MAAM,MAAM;KACxD,QAAQ,IAAI,2BAA2B,SAAS;IAClD,OACE,QAAQ,OAAO,MAAM,OAAO,IAAI;GAEpC,CAAA;mBAjBe,IAAA;;;IAiBf,CAAC;EAEH,OAAO;CACT,CAAA;;;;;AC/BK,WAAW,EAAE,MAAM,MAAM,EAAE,MAAM,CAAC"}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { parse } from "jsonc-parser";
|
|
5
|
+
import z$1, { z } from "zod";
|
|
6
|
+
import { objectPick } from "daily-code";
|
|
7
|
+
import { generateText, stepCountIs, tool } from "ai";
|
|
8
|
+
import { simpleGit } from "simple-git";
|
|
9
|
+
//#region src/constants/providers.ts
|
|
10
|
+
const SUPPORTED_PROVIDERS = {
|
|
11
|
+
"@ai-sdk/openai": { create: "createOpenAI" },
|
|
12
|
+
"@ai-sdk/openai-compatible": { create: "createOpenAICompatible" },
|
|
13
|
+
"@ai-sdk/anthropic": { create: "createAnthropic" },
|
|
14
|
+
"@ai-sdk/google": { create: "createGoogleGenerativeAI" },
|
|
15
|
+
"@ai-sdk/xai": { create: "createXai" },
|
|
16
|
+
"@ai-sdk/azure": { create: "createAzure" },
|
|
17
|
+
"@ai-sdk/amazon-bedrock": { create: "createAmazonBedrock" },
|
|
18
|
+
"@ai-sdk/groq": { create: "createGroq" },
|
|
19
|
+
"@ai-sdk/fal": { create: "createFal" },
|
|
20
|
+
"@ai-sdk/deepinfra": { create: "createDeepInfra" },
|
|
21
|
+
"@ai-sdk/google-vertex": { create: "createVertex" },
|
|
22
|
+
"@ai-sdk/mistral": { create: "createMistral" },
|
|
23
|
+
"@ai-sdk/togetherai": { create: "createTogetherAI" },
|
|
24
|
+
"@ai-sdk/cohere": { create: "createCohere" },
|
|
25
|
+
"@ai-sdk/fireworks": { create: "createFireworks" },
|
|
26
|
+
"@ai-sdk/deepseek": { create: "createDeepSeek" },
|
|
27
|
+
"@ai-sdk/cerebras": { create: "createCerebras" },
|
|
28
|
+
"@ai-sdk/perplexity": { create: "createPerplexity" },
|
|
29
|
+
"@ai-sdk/luma": { create: "createLuma" },
|
|
30
|
+
"@ai-sdk/baseten": { create: "createBaseten" },
|
|
31
|
+
"@openrouter/ai-sdk-provider": { create: "createOpenRouter" }
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/config/config-schema.ts
|
|
35
|
+
const gitCommitTargetSchema = z.union([z.object({ tag: z.string().describe("Git tag regex") }), z.object({ commit: z.string().describe("Git commit hash") })]);
|
|
36
|
+
const providerOptionsSchema = z.object({
|
|
37
|
+
apiUrl: z.string().optional(),
|
|
38
|
+
apiKeyEnv: z.union([z.string(), z.array(z.string())]).optional(),
|
|
39
|
+
provider: z.enum(Object.keys(SUPPORTED_PROVIDERS)).default("@ai-sdk/openai-compatible"),
|
|
40
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
41
|
+
options: z.record(z.string(), z.unknown()).optional()
|
|
42
|
+
});
|
|
43
|
+
const generateConfigSchema = z.object({
|
|
44
|
+
match: gitCommitTargetSchema.default({ tag: ".*" }),
|
|
45
|
+
model: z.string().min(1),
|
|
46
|
+
steps: z.number().int().positive().optional()
|
|
47
|
+
}).extend(providerOptionsSchema.shape);
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/asyncToGenerator.js
|
|
50
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) {
|
|
51
|
+
try {
|
|
52
|
+
var i = n[a](c), u = i.value;
|
|
53
|
+
} catch (n) {
|
|
54
|
+
e(n);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
i.done ? t(u) : Promise.resolve(u).then(r, o);
|
|
58
|
+
}
|
|
59
|
+
function _asyncToGenerator(n) {
|
|
60
|
+
return function() {
|
|
61
|
+
var t = this, e = arguments;
|
|
62
|
+
return new Promise(function(r, o) {
|
|
63
|
+
var a = n.apply(t, e);
|
|
64
|
+
function _next(n) {
|
|
65
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
|
|
66
|
+
}
|
|
67
|
+
function _throw(n) {
|
|
68
|
+
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
|
|
69
|
+
}
|
|
70
|
+
_next(void 0);
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/typeof.js
|
|
76
|
+
function _typeof(o) {
|
|
77
|
+
"@babel/helpers - typeof";
|
|
78
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
79
|
+
return typeof o;
|
|
80
|
+
} : function(o) {
|
|
81
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
82
|
+
}, _typeof(o);
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPrimitive.js
|
|
86
|
+
function toPrimitive(t, r) {
|
|
87
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
88
|
+
var e = t[Symbol.toPrimitive];
|
|
89
|
+
if (void 0 !== e) {
|
|
90
|
+
var i = e.call(t, r || "default");
|
|
91
|
+
if ("object" != _typeof(i)) return i;
|
|
92
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
93
|
+
}
|
|
94
|
+
return ("string" === r ? String : Number)(t);
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/toPropertyKey.js
|
|
98
|
+
function toPropertyKey(t) {
|
|
99
|
+
var i = toPrimitive(t, "string");
|
|
100
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/defineProperty.js
|
|
104
|
+
function _defineProperty(e, r, t) {
|
|
105
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
106
|
+
value: t,
|
|
107
|
+
enumerable: !0,
|
|
108
|
+
configurable: !0,
|
|
109
|
+
writable: !0
|
|
110
|
+
}) : e[r] = t, e;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region \0@oxc-project+runtime@0.133.0/helpers/esm/objectSpread2.js
|
|
114
|
+
function ownKeys(e, r) {
|
|
115
|
+
var t = Object.keys(e);
|
|
116
|
+
if (Object.getOwnPropertySymbols) {
|
|
117
|
+
var o = Object.getOwnPropertySymbols(e);
|
|
118
|
+
r && (o = o.filter(function(r) {
|
|
119
|
+
return Object.getOwnPropertyDescriptor(e, r).enumerable;
|
|
120
|
+
})), t.push.apply(t, o);
|
|
121
|
+
}
|
|
122
|
+
return t;
|
|
123
|
+
}
|
|
124
|
+
function _objectSpread2(e) {
|
|
125
|
+
for (var r = 1; r < arguments.length; r++) {
|
|
126
|
+
var t = null != arguments[r] ? arguments[r] : {};
|
|
127
|
+
r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
|
|
128
|
+
_defineProperty(e, r, t[r]);
|
|
129
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
|
|
130
|
+
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return e;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
//#region src/config/resolve-config.ts
|
|
137
|
+
const CONFIG_PATHS = [
|
|
138
|
+
"release-note.json",
|
|
139
|
+
"release-note.jsonc",
|
|
140
|
+
".github/release-note.json",
|
|
141
|
+
".github/release-note.jsonc"
|
|
142
|
+
];
|
|
143
|
+
function resolveConfig(_x) {
|
|
144
|
+
return _resolveConfig.apply(this, arguments);
|
|
145
|
+
}
|
|
146
|
+
function _resolveConfig() {
|
|
147
|
+
_resolveConfig = _asyncToGenerator(function* (cwd, configPaths = CONFIG_PATHS) {
|
|
148
|
+
for (const configPath of configPaths) {
|
|
149
|
+
const fullPath = path.join(cwd, configPath);
|
|
150
|
+
if (fs.existsSync(fullPath)) {
|
|
151
|
+
console.log(chalk.green(`Using config file: ${fullPath}`));
|
|
152
|
+
try {
|
|
153
|
+
const configContent = yield fs.promises.readFile(fullPath, "utf8");
|
|
154
|
+
return generateConfigSchema.parse(parse(configContent));
|
|
155
|
+
} catch (_unused) {
|
|
156
|
+
console.error(chalk.red(`Error parsing config file: ${fullPath}`));
|
|
157
|
+
throw new Error(`Invalid config file: ${fullPath}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return generateConfigSchema.parse({});
|
|
162
|
+
});
|
|
163
|
+
return _resolveConfig.apply(this, arguments);
|
|
164
|
+
}
|
|
165
|
+
const PROVIDERS_FACTORY = {
|
|
166
|
+
"@ai-sdk/openai": { create: "createOpenAI" },
|
|
167
|
+
"@ai-sdk/anthropic": { create: "createAnthropic" },
|
|
168
|
+
"@openrouter/ai-sdk-provider": { create: "createOpenRouter" }
|
|
169
|
+
};
|
|
170
|
+
function resolveApiKey(vars) {
|
|
171
|
+
let resolvedApiKey;
|
|
172
|
+
const apiKeyEnvVars = typeof vars === "string" ? [vars] : vars !== null && vars !== void 0 ? vars : [];
|
|
173
|
+
for (const envVar of apiKeyEnvVars) {
|
|
174
|
+
resolvedApiKey = process.env[envVar];
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
return resolvedApiKey;
|
|
178
|
+
}
|
|
179
|
+
function resolveProvider(_x2, _x3) {
|
|
180
|
+
return _resolveProvider.apply(this, arguments);
|
|
181
|
+
}
|
|
182
|
+
function _resolveProvider() {
|
|
183
|
+
_resolveProvider = _asyncToGenerator(function* (name, options) {
|
|
184
|
+
const resolvedApiKey = resolveApiKey(options.apiKeyEnv);
|
|
185
|
+
if (name === "@ai-sdk/openai-compatible") {
|
|
186
|
+
if (!options.apiUrl) throw new Error("\"\"apiUrl\"\" is required for openai-compatible provider");
|
|
187
|
+
if (!resolvedApiKey) throw new Error("No API key found in the specified environment variables");
|
|
188
|
+
const { createOpenAICompatible } = yield import("@ai-sdk/openai-compatible");
|
|
189
|
+
return createOpenAICompatible(_objectSpread2({
|
|
190
|
+
name,
|
|
191
|
+
apiKey: resolvedApiKey,
|
|
192
|
+
baseURL: options === null || options === void 0 ? void 0 : options.apiUrl,
|
|
193
|
+
headers: options === null || options === void 0 ? void 0 : options.headers
|
|
194
|
+
}, options === null || options === void 0 ? void 0 : options.options));
|
|
195
|
+
}
|
|
196
|
+
const provider = PROVIDERS_FACTORY[name];
|
|
197
|
+
if (provider) return (yield import(name))[provider.create](_objectSpread2({
|
|
198
|
+
apiKey: resolvedApiKey,
|
|
199
|
+
baseURL: options === null || options === void 0 ? void 0 : options.apiUrl,
|
|
200
|
+
headers: options === null || options === void 0 ? void 0 : options.headers
|
|
201
|
+
}, options === null || options === void 0 ? void 0 : options.options));
|
|
202
|
+
return null;
|
|
203
|
+
});
|
|
204
|
+
return _resolveProvider.apply(this, arguments);
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/lib/git.ts
|
|
208
|
+
function getGitCommitHash(_x, _x2) {
|
|
209
|
+
return _getGitCommitHash.apply(this, arguments);
|
|
210
|
+
}
|
|
211
|
+
function _getGitCommitHash() {
|
|
212
|
+
_getGitCommitHash = _asyncToGenerator(function* (git, target, offset = 0) {
|
|
213
|
+
if ("tag" in target) {
|
|
214
|
+
const regex = new RegExp(target.tag);
|
|
215
|
+
const { all: tags } = yield git.tags({ "--sort": "-v:refname" });
|
|
216
|
+
const matched = tags.filter((tag) => regex.test(tag));
|
|
217
|
+
if (matched.length === 0) throw new Error(`No tags matched pattern: ${target.tag}`);
|
|
218
|
+
if (offset < 0 || offset >= matched.length) throw new Error(`Offset ${offset} out of range: only ${matched.length} tag(s) matched pattern ${target.tag}`);
|
|
219
|
+
const tag = matched[offset];
|
|
220
|
+
return (yield git.revparse([tag])).trim();
|
|
221
|
+
}
|
|
222
|
+
if ("commit" in target) return (yield git.revparse([target.commit])).trim();
|
|
223
|
+
throw new Error("Invalid target: must contain either \"tag\" or \"commit\"");
|
|
224
|
+
});
|
|
225
|
+
return _getGitCommitHash.apply(this, arguments);
|
|
226
|
+
}
|
|
227
|
+
function getGitCommitsInfo(_x3, _x4) {
|
|
228
|
+
return _getGitCommitsInfo.apply(this, arguments);
|
|
229
|
+
}
|
|
230
|
+
function _getGitCommitsInfo() {
|
|
231
|
+
_getGitCommitsInfo = _asyncToGenerator(function* (git, match) {
|
|
232
|
+
const latest = yield getGitCommitHash(git, match, 1);
|
|
233
|
+
const current = yield getGitCommitHash(git, match, 0);
|
|
234
|
+
return [...(yield git.log({
|
|
235
|
+
from: latest,
|
|
236
|
+
to: current
|
|
237
|
+
})).all].map((c) => objectPick(c, [
|
|
238
|
+
"hash",
|
|
239
|
+
"date",
|
|
240
|
+
"message",
|
|
241
|
+
"author_name",
|
|
242
|
+
"author_email"
|
|
243
|
+
]));
|
|
244
|
+
});
|
|
245
|
+
return _getGitCommitsInfo.apply(this, arguments);
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/generate/prompt.ts
|
|
249
|
+
function buildSystemPrompt(maxTools) {
|
|
250
|
+
return `You are a helpful assistant for generating release notes based on git commit history.
|
|
251
|
+
The release notes should be concise, informative, and highlight the key changes, new features, bug fixes, and any important information that users should be aware of. The release note should be well-structured and easy to read. You are allowed to use up to ${maxTools} tools to gather necessary information from the git repository to generate accurate and comprehensive release notes.
|
|
252
|
+
|
|
253
|
+
**Target audience**: end users, product managers, and non-technical stakeholders. Write the release note for them, not for engineers reviewing the implementation.
|
|
254
|
+
|
|
255
|
+
## Guidelines:
|
|
256
|
+
- Summarize the key changes in a clear and concise manner, focusing on user-facing impact.
|
|
257
|
+
- Describe WHAT changed for the user and WHY it matters, not HOW it is implemented internally.
|
|
258
|
+
- DO NOT reveal internal implementation details. This includes but is not limited to: source code, code snippets, internal file names, internal file paths, class names, function names, variable names, API route paths, database table names, configuration keys, or any other internal identifiers.
|
|
259
|
+
- DO NOT include sensitive information such as credentials, secrets, tokens, internal URLs, private endpoints, or environment-specific values.
|
|
260
|
+
- Skip trivial changes that do not impact users (e.g., minor refactoring, file renames, formatting changes, internal tooling, dependency bumps with no user-visible effect).
|
|
261
|
+
- Use plain language that can be easily understood by a wide audience, including non-technical stakeholders. Avoid technical jargon, library/framework names, and implementation-specific terminology unless absolutely necessary.
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
## Output format:
|
|
265
|
+
- Group related changes together under appropriate headings (e.g., "New Features", "Bug Fixes", "Improvements", "Breaking Changes").
|
|
266
|
+
- Use bullet points to list individual changes for better readability.
|
|
267
|
+
- If there are breaking changes, clearly indicate them in a separate section and provide guidance on how to adapt to these changes from a user perspective.
|
|
268
|
+
- DO NOT use a top-level title to wrap the content as "Release Note"; just directly write the sections.
|
|
269
|
+
- DO NOT use --- to separate sections, use ## for headings instead.
|
|
270
|
+
- Output ONLY the release note content, with no preamble, explanation, or commentary.
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
function buildUserPrompt(commits) {
|
|
274
|
+
return `Here are the commits related to the release:
|
|
275
|
+
${commits.map((c) => [
|
|
276
|
+
`- Commithash: ${c.hash}`,
|
|
277
|
+
` - Timestamp: ${c.date}`,
|
|
278
|
+
` - Author: ${c.author_name} <${c.author_email}>`,
|
|
279
|
+
` > ${c.message}`
|
|
280
|
+
].join("\n")).join("\n")}
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/generate/tools.ts
|
|
285
|
+
function parseLsTree(output) {
|
|
286
|
+
return output.split("\n").filter((line) => line.length > 0).map((line) => {
|
|
287
|
+
const tabIdx = line.indexOf(" ");
|
|
288
|
+
return tabIdx >= 0 ? line.slice(tabIdx + 1) : "";
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
function generateTools(git, logger) {
|
|
292
|
+
return {
|
|
293
|
+
check_diff: tool({
|
|
294
|
+
description: "Get the full diff of a specific commit. Returns the patch showing all changes (additions, deletions, modifications) introduced by the commit.",
|
|
295
|
+
inputSchema: z$1.object({ commithash: z$1.string().describe("The commit hash, tag, branch, or any other git ref resolvable by git rev-parse.") }),
|
|
296
|
+
execute: function() {
|
|
297
|
+
var _ref = _asyncToGenerator(function* ({ commithash }) {
|
|
298
|
+
logger === null || logger === void 0 || logger(chalk.cyan(`[check_diff] fetching diff for ${commithash}`));
|
|
299
|
+
const diff = yield git.raw([
|
|
300
|
+
"show",
|
|
301
|
+
"--no-color",
|
|
302
|
+
"--pretty=format:",
|
|
303
|
+
commithash
|
|
304
|
+
]);
|
|
305
|
+
logger === null || logger === void 0 || logger(chalk.green(`[check_diff] ${commithash} -> ${diff.length} chars of diff`));
|
|
306
|
+
return diff;
|
|
307
|
+
});
|
|
308
|
+
return function execute(_x) {
|
|
309
|
+
return _ref.apply(this, arguments);
|
|
310
|
+
};
|
|
311
|
+
}()
|
|
312
|
+
}),
|
|
313
|
+
browse_code: tool({
|
|
314
|
+
description: "Browse the code at a specific commit. If the path points to a file, returns its content. If the path points to a folder, returns the list of files and sub-folders it contains. Pass an empty string for the path to browse the repository root.",
|
|
315
|
+
inputSchema: z$1.object({
|
|
316
|
+
commithash: z$1.string().describe("The commit hash, tag, branch, or any other git ref resolvable by git rev-parse."),
|
|
317
|
+
path: z$1.string().describe("Path to a file or folder within the repository, relative to the repo root. Use forward slashes. Pass an empty string for the root.")
|
|
318
|
+
}),
|
|
319
|
+
execute: function() {
|
|
320
|
+
var _ref2 = _asyncToGenerator(function* ({ commithash, path }) {
|
|
321
|
+
const normalized = path.replace(/^\/+|\/+$/g, "");
|
|
322
|
+
logger === null || logger === void 0 || logger(chalk.cyan(`[browse_code] ${commithash} @ ${normalized === "" ? "/" : normalized}`));
|
|
323
|
+
if (normalized === "") {
|
|
324
|
+
const items = parseLsTree(yield git.raw(["ls-tree", commithash]));
|
|
325
|
+
logger === null || logger === void 0 || logger(chalk.green(`[browse_code] root -> folder with ${items.length} item(s)`));
|
|
326
|
+
return {
|
|
327
|
+
type: "folder",
|
|
328
|
+
items
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const ref = `${commithash}:${normalized}`;
|
|
332
|
+
let objectType;
|
|
333
|
+
try {
|
|
334
|
+
objectType = (yield git.raw([
|
|
335
|
+
"cat-file",
|
|
336
|
+
"-t",
|
|
337
|
+
ref
|
|
338
|
+
])).trim();
|
|
339
|
+
} catch (_unused) {
|
|
340
|
+
logger === null || logger === void 0 || logger(chalk.yellow(`[browse_code] ${ref} does not exist`));
|
|
341
|
+
return { error: "doesn't exists" };
|
|
342
|
+
}
|
|
343
|
+
if (objectType === "tree") {
|
|
344
|
+
const items = parseLsTree(yield git.raw(["ls-tree", ref]));
|
|
345
|
+
logger === null || logger === void 0 || logger(chalk.green(`[browse_code] ${normalized} -> folder with ${items.length} item(s)`));
|
|
346
|
+
return {
|
|
347
|
+
type: "folder",
|
|
348
|
+
items
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (objectType === "blob") {
|
|
352
|
+
const content = yield git.show(ref);
|
|
353
|
+
logger === null || logger === void 0 || logger(chalk.green(`[browse_code] ${normalized} -> file with ${content.length} chars`));
|
|
354
|
+
return {
|
|
355
|
+
type: "file",
|
|
356
|
+
content
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
logger === null || logger === void 0 || logger(chalk.yellow(`[browse_code] ${ref} has unsupported object type "${objectType}"`));
|
|
360
|
+
return { error: "doesn't exists" };
|
|
361
|
+
});
|
|
362
|
+
return function execute(_x2) {
|
|
363
|
+
return _ref2.apply(this, arguments);
|
|
364
|
+
};
|
|
365
|
+
}()
|
|
366
|
+
})
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
//#region src/generate/index.ts
|
|
371
|
+
function generateReleaseNote(_x, _x2) {
|
|
372
|
+
return _generateReleaseNote.apply(this, arguments);
|
|
373
|
+
}
|
|
374
|
+
function _generateReleaseNote() {
|
|
375
|
+
_generateReleaseNote = _asyncToGenerator(function* (cwd, options) {
|
|
376
|
+
var _options$steps;
|
|
377
|
+
const git = simpleGit(cwd);
|
|
378
|
+
const commits = yield getGitCommitsInfo(git, options.match);
|
|
379
|
+
const provider = yield resolveProvider(options.provider, options);
|
|
380
|
+
if (!provider) throw new Error(`Unsupported provider: ${options.provider}`);
|
|
381
|
+
const maxSteps = (_options$steps = options.steps) !== null && _options$steps !== void 0 ? _options$steps : (commits.length + 1) * 2;
|
|
382
|
+
const result = yield generateText({
|
|
383
|
+
model: provider(options.model),
|
|
384
|
+
prompt: buildUserPrompt(commits).trim(),
|
|
385
|
+
system: buildSystemPrompt(maxSteps).trim(),
|
|
386
|
+
tools: generateTools(git, options.logger),
|
|
387
|
+
stopWhen: stepCountIs(maxSteps)
|
|
388
|
+
});
|
|
389
|
+
return {
|
|
390
|
+
commits,
|
|
391
|
+
note: result.text,
|
|
392
|
+
provider: {
|
|
393
|
+
usage: result.totalUsage,
|
|
394
|
+
response: result.response
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
});
|
|
398
|
+
return _generateReleaseNote.apply(this, arguments);
|
|
399
|
+
}
|
|
400
|
+
//#endregion
|
|
401
|
+
export { _asyncToGenerator as i, resolveConfig as n, _objectSpread2 as r, generateReleaseNote as t };
|
|
402
|
+
|
|
403
|
+
//# sourceMappingURL=generate-CsLUDr-g.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-CsLUDr-g.mjs","names":["z"],"sources":["../src/constants/providers.ts","../src/config/config-schema.ts","../src/config/resolve-config.ts","../src/lib/git.ts","../src/generate/prompt.ts","../src/generate/tools.ts","../src/generate/index.ts"],"sourcesContent":["type ProviderRecord = Record<string, { create: string }>\n\nexport const SUPPORTED_PROVIDERS = {\n '@ai-sdk/openai': { create: 'createOpenAI' },\n '@ai-sdk/openai-compatible': { create: 'createOpenAICompatible' },\n '@ai-sdk/anthropic': { create: 'createAnthropic' },\n '@ai-sdk/google': { create: 'createGoogleGenerativeAI' },\n '@ai-sdk/xai': { create: 'createXai' },\n '@ai-sdk/azure': { create: 'createAzure' },\n '@ai-sdk/amazon-bedrock': { create: 'createAmazonBedrock' },\n '@ai-sdk/groq': { create: 'createGroq' },\n '@ai-sdk/fal': { create: 'createFal' },\n '@ai-sdk/deepinfra': { create: 'createDeepInfra' },\n '@ai-sdk/google-vertex': { create: 'createVertex' },\n '@ai-sdk/mistral': { create: 'createMistral' },\n '@ai-sdk/togetherai': { create: 'createTogetherAI' },\n '@ai-sdk/cohere': { create: 'createCohere' },\n '@ai-sdk/fireworks': { create: 'createFireworks' },\n '@ai-sdk/deepseek': { create: 'createDeepSeek' },\n '@ai-sdk/cerebras': { create: 'createCerebras' },\n '@ai-sdk/perplexity': { create: 'createPerplexity' },\n '@ai-sdk/luma': { create: 'createLuma' },\n '@ai-sdk/baseten': { create: 'createBaseten' },\n '@openrouter/ai-sdk-provider': { create: 'createOpenRouter' },\n} as const satisfies ProviderRecord\n","import { SUPPORTED_PROVIDERS } from '@/constants/providers.js'\nimport { z } from 'zod'\n\nexport const gitCommitTargetSchema = z.union([\n z.object({ tag: z.string().describe('Git tag regex') }),\n z.object({ commit: z.string().describe('Git commit hash') }),\n])\n\nexport const providerOptionsSchema = z.object({\n apiUrl: z.string().optional(),\n apiKeyEnv: z.union([z.string(), z.array(z.string())]).optional(),\n\n provider: z\n .enum(Object.keys(SUPPORTED_PROVIDERS))\n .default('@ai-sdk/openai-compatible'),\n\n headers: z.record(z.string(), z.string()).optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const generateConfigSchema = z\n .object({\n match: gitCommitTargetSchema.default({ tag: '.*' }),\n model: z.string().min(1),\n steps: z.number().int().positive().optional(),\n })\n .extend(providerOptionsSchema.shape)\n","import { Provider } from 'ai'\nimport chalk from 'chalk'\nimport fs from 'fs'\nimport { parse } from 'jsonc-parser'\nimport path from 'path'\nimport z from 'zod'\nimport { generateConfigSchema, providerOptionsSchema } from './config-schema.js'\n\nconst CONFIG_PATHS = [\n 'release-note.json',\n 'release-note.jsonc',\n '.github/release-note.json',\n '.github/release-note.jsonc',\n]\n\nexport async function resolveConfig(\n cwd: string,\n configPaths: string[] = CONFIG_PATHS\n) {\n for (const configPath of configPaths) {\n const fullPath = path.join(cwd, configPath)\n\n if (fs.existsSync(fullPath)) {\n console.log(chalk.green(`Using config file: ${fullPath}`))\n\n try {\n const configContent = await fs.promises.readFile(fullPath, 'utf8')\n return generateConfigSchema.parse(parse(configContent))\n } catch {\n console.error(chalk.red(`Error parsing config file: ${fullPath}`))\n throw new Error(`Invalid config file: ${fullPath}`)\n }\n }\n }\n\n return generateConfigSchema.parse({})\n}\n\nconst PROVIDERS_FACTORY: Record<string, { create: string }> = {\n '@ai-sdk/openai': { create: 'createOpenAI' },\n '@ai-sdk/anthropic': { create: 'createAnthropic' },\n '@openrouter/ai-sdk-provider': { create: 'createOpenRouter' },\n}\n\nfunction resolveApiKey(\n vars: string | string[] | undefined\n): string | undefined {\n let resolvedApiKey: string | undefined\n\n const apiKeyEnvVars = typeof vars === 'string' ? [vars] : (vars ?? [])\n\n for (const envVar of apiKeyEnvVars) {\n resolvedApiKey = process.env[envVar]\n break\n }\n\n return resolvedApiKey\n}\n\nexport async function resolveProvider(\n name: string,\n options: z.infer<typeof providerOptionsSchema>\n): Promise<Provider['languageModel'] | null> {\n const resolvedApiKey = resolveApiKey(options.apiKeyEnv)\n\n if (name === '@ai-sdk/openai-compatible') {\n if (!options.apiUrl) {\n throw new Error('\"\"apiUrl\"\" is required for openai-compatible provider')\n }\n\n if (!resolvedApiKey) {\n throw new Error('No API key found in the specified environment variables')\n }\n\n const { createOpenAICompatible } = await import('@ai-sdk/openai-compatible')\n return createOpenAICompatible({\n name,\n apiKey: resolvedApiKey,\n baseURL: options?.apiUrl,\n headers: options?.headers,\n ...options?.options,\n })\n }\n\n const provider = PROVIDERS_FACTORY[name]\n if (provider) {\n const mod = await import(name)\n return mod[provider.create]({\n apiKey: resolvedApiKey,\n baseURL: options?.apiUrl,\n headers: options?.headers,\n ...options?.options,\n })\n }\n\n return null\n}\n","import { gitCommitTargetSchema } from '@/config/config-schema.js'\nimport { objectPick, Prettify } from 'daily-code'\nimport { DefaultLogFields, type SimpleGit } from 'simple-git'\nimport z from 'zod'\n\nexport type GitCommitInfo = Prettify<\n Pick<\n DefaultLogFields,\n 'hash' | 'date' | 'message' | 'author_name' | 'author_email'\n >\n>\n\nasync function getGitCommitHash(\n git: SimpleGit,\n target: z.infer<typeof gitCommitTargetSchema>,\n offset = 0\n): Promise<string> {\n if ('tag' in target) {\n const regex = new RegExp(target.tag)\n const { all: tags } = await git.tags({ '--sort': '-v:refname' })\n const matched = tags.filter((tag) => regex.test(tag))\n if (matched.length === 0) {\n throw new Error(`No tags matched pattern: ${target.tag}`)\n }\n\n if (offset < 0 || offset >= matched.length) {\n throw new Error(\n `Offset ${offset} out of range: only ${matched.length} tag(s) matched pattern ${target.tag}`\n )\n }\n\n const tag = matched[offset]\n const hash = await git.revparse([tag])\n return hash.trim()\n }\n\n if ('commit' in target) {\n const hash = await git.revparse([target.commit])\n return hash.trim()\n }\n\n throw new Error('Invalid target: must contain either \"tag\" or \"commit\"')\n}\n\nexport async function getGitCommitsInfo(\n git: SimpleGit,\n match: z.infer<typeof gitCommitTargetSchema>\n): Promise<GitCommitInfo[]> {\n const latest = await getGitCommitHash(git, match, 1)\n const current = await getGitCommitHash(git, match, 0)\n const log = await git.log({ from: latest, to: current })\n return [...log.all].map((c) =>\n objectPick(c, ['hash', 'date', 'message', 'author_name', 'author_email'])\n )\n}\n","import { GitCommitInfo } from '@/lib/git.js'\n\nexport function buildSystemPrompt(maxTools: number) {\n return `You are a helpful assistant for generating release notes based on git commit history.\nThe release notes should be concise, informative, and highlight the key changes, new features, bug fixes, and any important information that users should be aware of. The release note should be well-structured and easy to read. You are allowed to use up to ${maxTools} tools to gather necessary information from the git repository to generate accurate and comprehensive release notes.\n\n**Target audience**: end users, product managers, and non-technical stakeholders. Write the release note for them, not for engineers reviewing the implementation.\n\n## Guidelines:\n- Summarize the key changes in a clear and concise manner, focusing on user-facing impact.\n- Describe WHAT changed for the user and WHY it matters, not HOW it is implemented internally.\n- DO NOT reveal internal implementation details. This includes but is not limited to: source code, code snippets, internal file names, internal file paths, class names, function names, variable names, API route paths, database table names, configuration keys, or any other internal identifiers.\n- DO NOT include sensitive information such as credentials, secrets, tokens, internal URLs, private endpoints, or environment-specific values.\n- Skip trivial changes that do not impact users (e.g., minor refactoring, file renames, formatting changes, internal tooling, dependency bumps with no user-visible effect).\n- Use plain language that can be easily understood by a wide audience, including non-technical stakeholders. Avoid technical jargon, library/framework names, and implementation-specific terminology unless absolutely necessary.\n\n\n## Output format:\n- Group related changes together under appropriate headings (e.g., \"New Features\", \"Bug Fixes\", \"Improvements\", \"Breaking Changes\").\n- Use bullet points to list individual changes for better readability.\n- If there are breaking changes, clearly indicate them in a separate section and provide guidance on how to adapt to these changes from a user perspective.\n- DO NOT use a top-level title to wrap the content as \"Release Note\"; just directly write the sections.\n- DO NOT use --- to separate sections, use ## for headings instead.\n- Output ONLY the release note content, with no preamble, explanation, or commentary.\n`\n}\n\nexport function buildUserPrompt(commits: GitCommitInfo[]) {\n const commitsList = commits.map((c) =>\n [\n `- Commithash: ${c.hash}`,\n ` - Timestamp: ${c.date}`,\n ` - Author: ${c.author_name} <${c.author_email}>`,\n ` > ${c.message}`,\n ].join('\\n')\n )\n\n return `Here are the commits related to the release:\n${commitsList.join('\\n')}\n`\n}\n","import { tool, ToolSet } from 'ai'\nimport chalk from 'chalk'\nimport { SimpleGit } from 'simple-git'\nimport z from 'zod'\n\nfunction parseLsTree(output: string): string[] {\n return output\n .split('\\n')\n .filter((line) => line.length > 0)\n .map((line) => {\n const tabIdx = line.indexOf('\\t')\n return tabIdx >= 0 ? line.slice(tabIdx + 1) : ''\n })\n}\n\nexport function generateTools(\n git: SimpleGit,\n logger?: (...args: unknown[]) => void\n): ToolSet {\n return {\n check_diff: tool({\n description:\n 'Get the full diff of a specific commit. Returns the patch showing all changes (additions, deletions, modifications) introduced by the commit.',\n inputSchema: z.object({\n commithash: z\n .string()\n .describe(\n 'The commit hash, tag, branch, or any other git ref resolvable by git rev-parse.'\n ),\n }),\n execute: async ({ commithash }) => {\n logger?.(chalk.cyan(`[check_diff] fetching diff for ${commithash}`))\n const diff = await git.raw([\n 'show',\n '--no-color',\n '--pretty=format:',\n commithash,\n ])\n logger?.(\n chalk.green(\n `[check_diff] ${commithash} -> ${diff.length} chars of diff`\n )\n )\n return diff\n },\n }),\n browse_code: tool({\n description:\n 'Browse the code at a specific commit. If the path points to a file, returns its content. If the path points to a folder, returns the list of files and sub-folders it contains. Pass an empty string for the path to browse the repository root.',\n inputSchema: z.object({\n commithash: z\n .string()\n .describe(\n 'The commit hash, tag, branch, or any other git ref resolvable by git rev-parse.'\n ),\n path: z\n .string()\n .describe(\n 'Path to a file or folder within the repository, relative to the repo root. Use forward slashes. Pass an empty string for the root.'\n ),\n }),\n execute: async ({ commithash, path }) => {\n const normalized = path.replace(/^\\/+|\\/+$/g, '')\n logger?.(\n chalk.cyan(\n `[browse_code] ${commithash} @ ${normalized === '' ? '/' : normalized}`\n )\n )\n\n if (normalized === '') {\n const output = await git.raw(['ls-tree', commithash])\n const items = parseLsTree(output)\n logger?.(\n chalk.green(\n `[browse_code] root -> folder with ${items.length} item(s)`\n )\n )\n return { type: 'folder', items }\n }\n\n const ref = `${commithash}:${normalized}`\n let objectType: string\n try {\n objectType = (await git.raw(['cat-file', '-t', ref])).trim()\n } catch {\n logger?.(chalk.yellow(`[browse_code] ${ref} does not exist`))\n return { error: \"doesn't exists\" }\n }\n\n if (objectType === 'tree') {\n const output = await git.raw(['ls-tree', ref])\n const items = parseLsTree(output)\n logger?.(\n chalk.green(\n `[browse_code] ${normalized} -> folder with ${items.length} item(s)`\n )\n )\n return { type: 'folder', items }\n }\n\n if (objectType === 'blob') {\n const content = await git.show(ref)\n logger?.(\n chalk.green(\n `[browse_code] ${normalized} -> file with ${content.length} chars`\n )\n )\n return { type: 'file', content }\n }\n\n logger?.(\n chalk.yellow(\n `[browse_code] ${ref} has unsupported object type \"${objectType}\"`\n )\n )\n return { error: \"doesn't exists\" }\n },\n }),\n }\n}\n","import { generateConfigSchema } from '@/config/config-schema.js'\nimport { resolveProvider } from '@/config/resolve-config.js'\nimport { getGitCommitsInfo } from '@/lib/git.js'\nimport { generateText, stepCountIs } from 'ai'\nimport { simpleGit } from 'simple-git'\nimport z from 'zod'\nimport { buildSystemPrompt, buildUserPrompt } from './prompt.js'\nimport { generateTools } from './tools.js'\n\ntype GenerateOptions = z.infer<typeof generateConfigSchema> & {\n logger?: (...args: unknown[]) => void\n}\n\nexport async function generateReleaseNote(\n cwd: string,\n options: GenerateOptions\n) {\n const git = simpleGit(cwd)\n const commits = await getGitCommitsInfo(git, options.match)\n\n const provider = await resolveProvider(options.provider, options)\n if (!provider) {\n throw new Error(`Unsupported provider: ${options.provider}`)\n }\n\n const maxSteps = options.steps ?? (commits.length + 1) * 2\n const result = await generateText({\n model: provider(options.model),\n\n prompt: buildUserPrompt(commits).trim(),\n system: buildSystemPrompt(maxSteps).trim(),\n\n tools: generateTools(git, options.logger),\n stopWhen: stepCountIs(maxSteps),\n })\n\n return {\n commits,\n note: result.text,\n\n provider: {\n usage: result.totalUsage,\n response: result.response,\n },\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,48 @@
|
|
|
1
|
+
import z$1, { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/config/config-schema.d.ts
|
|
4
|
+
declare const generateConfigSchema: z.ZodObject<{
|
|
5
|
+
match: z.ZodDefault<z.ZodUnion<readonly [z.ZodObject<{
|
|
6
|
+
tag: z.ZodString;
|
|
7
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
|
+
commit: z.ZodString;
|
|
9
|
+
}, z.core.$strip>]>>;
|
|
10
|
+
model: z.ZodString;
|
|
11
|
+
steps: z.ZodOptional<z.ZodNumber>;
|
|
12
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
13
|
+
apiKeyEnv: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
14
|
+
provider: z.ZodDefault<z.ZodEnum<{
|
|
15
|
+
[x: string]: string;
|
|
16
|
+
}>>;
|
|
17
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
18
|
+
options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/generate/index.d.ts
|
|
22
|
+
type GenerateOptions = z$1.infer<typeof generateConfigSchema> & {
|
|
23
|
+
logger?: (...args: unknown[]) => void;
|
|
24
|
+
};
|
|
25
|
+
declare function generateReleaseNote(cwd: string, options: GenerateOptions): Promise<{
|
|
26
|
+
commits: {
|
|
27
|
+
hash: string;
|
|
28
|
+
date: string;
|
|
29
|
+
message: string;
|
|
30
|
+
author_name: string;
|
|
31
|
+
author_email: string;
|
|
32
|
+
}[];
|
|
33
|
+
note: string;
|
|
34
|
+
provider: {
|
|
35
|
+
usage: import("ai").LanguageModelUsage;
|
|
36
|
+
response: import("ai").LanguageModelResponseMetadata & {
|
|
37
|
+
messages: Array<import("ai").AssistantModelMessage | import("ai").ToolModelMessage>;
|
|
38
|
+
body?: unknown;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}>;
|
|
42
|
+
//#endregion
|
|
1
43
|
//#region src/index.d.ts
|
|
2
|
-
declare const _default:
|
|
3
|
-
declare const
|
|
4
|
-
declare const baz = 42;
|
|
44
|
+
declare const _default: typeof generateReleaseNote;
|
|
45
|
+
declare const releaseNote: typeof generateReleaseNote;
|
|
5
46
|
//#endregion
|
|
6
|
-
export {
|
|
47
|
+
export { _default as default, releaseNote };
|
|
7
48
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { t as generateReleaseNote } from "./generate-CsLUDr-g.mjs";
|
|
1
2
|
//#region src/index.ts
|
|
2
|
-
var src_default =
|
|
3
|
-
const
|
|
4
|
-
const baz = 42;
|
|
3
|
+
var src_default = generateReleaseNote;
|
|
4
|
+
const releaseNote = generateReleaseNote;
|
|
5
5
|
//#endregion
|
|
6
|
-
export {
|
|
6
|
+
export { src_default as default, releaseNote };
|
|
7
7
|
|
|
8
8
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["generate.generateReleaseNote"],"sources":["../src/index.ts"],"sourcesContent":["import * as generate from './generate/index.js'\n\nexport default generate.generateReleaseNote\nexport const releaseNote = generate.generateReleaseNote\n"],"mappings":";;AAEA,IAAA,cAAeA;AACf,MAAa,cAAcA"}
|
package/package.json
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "release-note",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"sideEffects": false,
|
|
3
|
+
"version": "0.0.1",
|
|
5
4
|
"scripts": {
|
|
6
5
|
"lint": "eslint .",
|
|
7
6
|
"lint:fix": "eslint . --fix",
|
|
8
7
|
"typecheck": "tsc --noEmit",
|
|
9
8
|
"typecheck:watch": "tsc --noEmit --watch",
|
|
10
|
-
"
|
|
9
|
+
"start": "tsx ./src/start.ts",
|
|
11
10
|
"build": "tsdown --config ./tsdown.config.ts",
|
|
12
|
-
"dev": "concurrently --names \"R,T\" --prefix-colors \"blue.dim,magenta.dim\" \"tsdown --config ./tsdown.config.ts --watch\" \"tsc --noEmit --watch\""
|
|
13
|
-
"start": "tsx --watch ./src/index.ts"
|
|
11
|
+
"dev": "concurrently --names \"R,T\" --prefix-colors \"blue.dim,magenta.dim\" \"tsdown --config ./tsdown.config.ts --watch\" \"tsc --noEmit --watch\""
|
|
14
12
|
},
|
|
13
|
+
"type": "module",
|
|
15
14
|
"main": "./dist/index.cjs",
|
|
16
15
|
"module": "./dist/index.mjs",
|
|
16
|
+
"bin": {
|
|
17
|
+
"release-note": "./dist/bin.mjs"
|
|
18
|
+
},
|
|
17
19
|
"exports": {
|
|
18
20
|
".": {
|
|
19
21
|
"import": "./dist/index.mjs",
|
|
@@ -28,27 +30,40 @@
|
|
|
28
30
|
]
|
|
29
31
|
}
|
|
30
32
|
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@openrouter/ai-sdk-provider": "^2.9.0"
|
|
35
|
+
},
|
|
31
36
|
"devDependencies": {
|
|
37
|
+
"@ai-sdk/openai-compatible": "^2.0.48",
|
|
38
|
+
"@commander-js/extra-typings": "^15.0.0",
|
|
32
39
|
"@eslint/compat": "^1.4.1",
|
|
33
40
|
"@eslint/eslintrc": "^3.3.5",
|
|
34
41
|
"@eslint/js": "^9.39.4",
|
|
35
42
|
"@types/node": "^25.9.1",
|
|
36
43
|
"@typescript-eslint/eslint-plugin": "^8.60.1",
|
|
37
44
|
"@typescript-eslint/parser": "^8.60.1",
|
|
45
|
+
"ai": "^6.0.195",
|
|
46
|
+
"chalk": "^5.6.2",
|
|
47
|
+
"commander": "^15.0.0",
|
|
38
48
|
"concurrently": "^10.0.3",
|
|
49
|
+
"cross-spawn": "^7.0.6",
|
|
50
|
+
"daily-code": "^1.1.16",
|
|
39
51
|
"eslint": "^9.39.4",
|
|
40
52
|
"eslint-config-prettier": "^10.1.8",
|
|
41
53
|
"eslint-plugin-check-file": "^3.3.1",
|
|
42
54
|
"eslint-plugin-import": "^2.32.0",
|
|
43
55
|
"eslint-plugin-prettier": "^5.5.6",
|
|
44
56
|
"husky": "^9.1.7",
|
|
57
|
+
"jsonc-parser": "^3.3.1",
|
|
45
58
|
"prettier": "^3.8.3",
|
|
46
59
|
"prettier-plugin-organize-imports": "^4.3.0",
|
|
47
60
|
"rolldown": "^1.0.3",
|
|
61
|
+
"simple-git": "^3.36.0",
|
|
48
62
|
"tsdown": "^0.22.1",
|
|
49
63
|
"tslib": "^2.8.1",
|
|
50
64
|
"tsx": "^4.22.4",
|
|
51
65
|
"typescript": "^5.9.3",
|
|
52
|
-
"typescript-eslint": "^8.60.1"
|
|
66
|
+
"typescript-eslint": "^8.60.1",
|
|
67
|
+
"zod": "^4.4.3"
|
|
53
68
|
}
|
|
54
69
|
}
|
package/dist/index.cjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
Object.defineProperties(exports, {
|
|
2
|
-
__esModule: { value: true },
|
|
3
|
-
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
-
});
|
|
5
|
-
//#region src/index.ts
|
|
6
|
-
var src_default = "Hello World";
|
|
7
|
-
const foo = "bar";
|
|
8
|
-
const baz = 42;
|
|
9
|
-
//#endregion
|
|
10
|
-
exports.baz = baz;
|
|
11
|
-
exports.default = src_default;
|
|
12
|
-
exports.foo = foo;
|
|
13
|
-
|
|
14
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export default 'Hello World'\nexport const foo = 'bar'\nexport const baz = 42\n"],"mappings":";;;;;AAAA,IAAA,cAAe;AACf,MAAa,MAAM;AACnB,MAAa,MAAM"}
|