@cullit/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +306 -0
- package/dist/index.js +1251 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cullit (Matt)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
type AIProvider = 'anthropic' | 'openai' | 'gemini' | 'ollama' | 'openclaw' | 'none';
|
|
2
|
+
type Audience = 'developer' | 'end-user' | 'executive';
|
|
3
|
+
type Tone = 'professional' | 'casual' | 'terse';
|
|
4
|
+
type OutputFormat = 'markdown' | 'html' | 'json';
|
|
5
|
+
type PublisherType = 'stdout' | 'github-release' | 'slack' | 'discord' | 'file';
|
|
6
|
+
type EnrichmentType = 'jira' | 'linear';
|
|
7
|
+
interface AIConfig {
|
|
8
|
+
provider: AIProvider;
|
|
9
|
+
model?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
audience: Audience;
|
|
12
|
+
tone: Tone;
|
|
13
|
+
categories: string[];
|
|
14
|
+
maxTokens?: number;
|
|
15
|
+
}
|
|
16
|
+
interface SourceConfig {
|
|
17
|
+
type: 'local' | 'jira' | 'linear';
|
|
18
|
+
owner?: string;
|
|
19
|
+
repo?: string;
|
|
20
|
+
enrichment?: EnrichmentType[];
|
|
21
|
+
}
|
|
22
|
+
interface PublishTarget {
|
|
23
|
+
type: PublisherType;
|
|
24
|
+
channel?: string;
|
|
25
|
+
webhookUrl?: string;
|
|
26
|
+
path?: string;
|
|
27
|
+
}
|
|
28
|
+
interface JiraConfig {
|
|
29
|
+
domain: string;
|
|
30
|
+
email?: string;
|
|
31
|
+
apiToken?: string;
|
|
32
|
+
}
|
|
33
|
+
interface LinearConfig {
|
|
34
|
+
apiKey?: string;
|
|
35
|
+
}
|
|
36
|
+
interface OpenClawConfig {
|
|
37
|
+
baseUrl?: string;
|
|
38
|
+
token?: string;
|
|
39
|
+
}
|
|
40
|
+
interface CullConfig {
|
|
41
|
+
ai: AIConfig;
|
|
42
|
+
source: SourceConfig;
|
|
43
|
+
publish: PublishTarget[];
|
|
44
|
+
jira?: JiraConfig;
|
|
45
|
+
linear?: LinearConfig;
|
|
46
|
+
openclaw?: OpenClawConfig;
|
|
47
|
+
}
|
|
48
|
+
interface GitCommit {
|
|
49
|
+
hash: string;
|
|
50
|
+
shortHash: string;
|
|
51
|
+
author: string;
|
|
52
|
+
date: string;
|
|
53
|
+
message: string;
|
|
54
|
+
body?: string;
|
|
55
|
+
prNumber?: number;
|
|
56
|
+
issueKeys?: string[];
|
|
57
|
+
}
|
|
58
|
+
interface GitDiff {
|
|
59
|
+
from: string;
|
|
60
|
+
to: string;
|
|
61
|
+
commits: GitCommit[];
|
|
62
|
+
filesChanged?: number;
|
|
63
|
+
}
|
|
64
|
+
interface EnrichedTicket {
|
|
65
|
+
key: string;
|
|
66
|
+
title: string;
|
|
67
|
+
description?: string;
|
|
68
|
+
type?: string;
|
|
69
|
+
labels?: string[];
|
|
70
|
+
priority?: string;
|
|
71
|
+
status?: string;
|
|
72
|
+
source: EnrichmentType;
|
|
73
|
+
}
|
|
74
|
+
interface EnrichedContext {
|
|
75
|
+
diff: GitDiff;
|
|
76
|
+
tickets: EnrichedTicket[];
|
|
77
|
+
}
|
|
78
|
+
type ChangeCategory = 'features' | 'fixes' | 'breaking' | 'improvements' | 'chores' | 'other';
|
|
79
|
+
interface ChangeEntry {
|
|
80
|
+
description: string;
|
|
81
|
+
category: ChangeCategory;
|
|
82
|
+
ticketKey?: string;
|
|
83
|
+
commits?: string[];
|
|
84
|
+
}
|
|
85
|
+
interface ReleaseNotes {
|
|
86
|
+
version: string;
|
|
87
|
+
date: string;
|
|
88
|
+
summary?: string;
|
|
89
|
+
changes: ChangeEntry[];
|
|
90
|
+
contributors?: string[];
|
|
91
|
+
metadata?: {
|
|
92
|
+
commitCount: number;
|
|
93
|
+
prCount: number;
|
|
94
|
+
ticketCount: number;
|
|
95
|
+
generatedBy: string;
|
|
96
|
+
generatedAt: string;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
interface Collector {
|
|
100
|
+
collect(from: string, to: string): Promise<GitDiff>;
|
|
101
|
+
}
|
|
102
|
+
interface Enricher {
|
|
103
|
+
enrich(diff: GitDiff): Promise<EnrichedTicket[]>;
|
|
104
|
+
}
|
|
105
|
+
interface Generator {
|
|
106
|
+
generate(context: EnrichedContext, config: AIConfig): Promise<ReleaseNotes>;
|
|
107
|
+
}
|
|
108
|
+
interface Publisher {
|
|
109
|
+
publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
interface PipelineResult {
|
|
112
|
+
notes: ReleaseNotes;
|
|
113
|
+
formatted: string;
|
|
114
|
+
publishedTo: string[];
|
|
115
|
+
duration: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
declare const VERSION = "0.1.0";
|
|
119
|
+
declare const DEFAULT_CATEGORIES: string[];
|
|
120
|
+
declare const DEFAULT_MODELS: Record<string, string>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Collects git log data between two refs (tags, branches, or commit SHAs).
|
|
124
|
+
* Extracts commits, PR numbers, and issue keys from commit messages.
|
|
125
|
+
*/
|
|
126
|
+
declare class GitCollector implements Collector {
|
|
127
|
+
private cwd;
|
|
128
|
+
constructor(cwd?: string);
|
|
129
|
+
collect(from: string, to: string): Promise<GitDiff>;
|
|
130
|
+
private getLog;
|
|
131
|
+
private parseLog;
|
|
132
|
+
/**
|
|
133
|
+
* Extracts PR number from commit messages.
|
|
134
|
+
* Matches patterns like: (#123), Merge pull request #123, PR #123
|
|
135
|
+
*/
|
|
136
|
+
private extractPRNumber;
|
|
137
|
+
/**
|
|
138
|
+
* Extracts issue keys from commit messages.
|
|
139
|
+
* Matches patterns like: PROJ-123, FIX-456, LIN-789
|
|
140
|
+
*/
|
|
141
|
+
private extractIssueKeys;
|
|
142
|
+
private getFilesChanged;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Gets list of available tags, most recent first.
|
|
146
|
+
*/
|
|
147
|
+
declare function getRecentTags(cwd?: string, count?: number): string[];
|
|
148
|
+
/**
|
|
149
|
+
* Gets the latest tag on current branch.
|
|
150
|
+
*/
|
|
151
|
+
declare function getLatestTag(cwd?: string): string | null;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Collects release data directly from Jira (no git required).
|
|
155
|
+
* Queries completed issues by JQL (project, sprint, date range, etc.)
|
|
156
|
+
* and converts them into the GitDiff format for the pipeline.
|
|
157
|
+
*
|
|
158
|
+
* Usage:
|
|
159
|
+
* --from "project = PROJ AND sprint = 'Sprint 42'"
|
|
160
|
+
* --from "project = PROJ AND resolved >= '2025-03-01'"
|
|
161
|
+
* --from "project = PROJ AND fixVersion = 'v2.0'"
|
|
162
|
+
*/
|
|
163
|
+
declare class JiraCollector implements Collector {
|
|
164
|
+
private config;
|
|
165
|
+
constructor(config: JiraConfig);
|
|
166
|
+
collect(from: string, to: string): Promise<GitDiff>;
|
|
167
|
+
private buildJQL;
|
|
168
|
+
private fetchIssues;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Collects release data directly from Linear (no git required).
|
|
173
|
+
* Queries completed issues by project, cycle, or team.
|
|
174
|
+
*
|
|
175
|
+
* Usage:
|
|
176
|
+
* --from "team:ENG" (completed issues from team ENG, last 30 days)
|
|
177
|
+
* --from "project:Project Name" (completed issues from a project)
|
|
178
|
+
* --from "cycle:current" (current cycle's completed issues)
|
|
179
|
+
* --from "label:release-v2" (issues with a specific label)
|
|
180
|
+
*/
|
|
181
|
+
declare class LinearCollector implements Collector {
|
|
182
|
+
private apiKey;
|
|
183
|
+
constructor(apiKey?: string);
|
|
184
|
+
collect(from: string, to: string): Promise<GitDiff>;
|
|
185
|
+
private parseFilter;
|
|
186
|
+
private fetchIssues;
|
|
187
|
+
private buildFilterClause;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Generates release notes using AI.
|
|
192
|
+
* Supports Anthropic, OpenAI, Gemini, Ollama, OpenClaw — BYOK.
|
|
193
|
+
*/
|
|
194
|
+
declare class AIGenerator implements Generator {
|
|
195
|
+
private openclawConfig?;
|
|
196
|
+
private timeoutMs;
|
|
197
|
+
constructor(openclawConfig?: OpenClawConfig, timeoutMs?: number);
|
|
198
|
+
private fetchWithTimeout;
|
|
199
|
+
generate(context: EnrichedContext, config: AIConfig): Promise<ReleaseNotes>;
|
|
200
|
+
private resolveApiKey;
|
|
201
|
+
private buildPrompt;
|
|
202
|
+
private callAnthropic;
|
|
203
|
+
private callOpenAI;
|
|
204
|
+
private callGemini;
|
|
205
|
+
private callOllama;
|
|
206
|
+
private callOpenClaw;
|
|
207
|
+
private parseResponse;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Template-based release notes generator — no AI required.
|
|
212
|
+
* Groups commits by conventional commit prefix and ticket type.
|
|
213
|
+
* Useful as a free demo, CI fallback, or air-gapped environments.
|
|
214
|
+
*/
|
|
215
|
+
declare class TemplateGenerator implements Generator {
|
|
216
|
+
generate(context: EnrichedContext, config: AIConfig): Promise<ReleaseNotes>;
|
|
217
|
+
private categorize;
|
|
218
|
+
private cleanMessage;
|
|
219
|
+
private isTrivial;
|
|
220
|
+
private deduplicateByTicket;
|
|
221
|
+
private buildSummary;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
declare function formatNotes(notes: ReleaseNotes, format: OutputFormat): string;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Outputs release notes to stdout (default).
|
|
228
|
+
*/
|
|
229
|
+
declare class StdoutPublisher implements Publisher {
|
|
230
|
+
publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Writes release notes to a file.
|
|
234
|
+
*/
|
|
235
|
+
declare class FilePublisher implements Publisher {
|
|
236
|
+
private path;
|
|
237
|
+
constructor(path: string);
|
|
238
|
+
publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Posts release notes to a Slack channel via webhook.
|
|
242
|
+
*/
|
|
243
|
+
declare class SlackPublisher implements Publisher {
|
|
244
|
+
private webhookUrl;
|
|
245
|
+
constructor(webhookUrl: string);
|
|
246
|
+
publish(notes: ReleaseNotes, _format: OutputFormat): Promise<void>;
|
|
247
|
+
private buildSlackMessage;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Posts release notes to Discord via webhook.
|
|
251
|
+
*/
|
|
252
|
+
declare class DiscordPublisher implements Publisher {
|
|
253
|
+
private webhookUrl;
|
|
254
|
+
constructor(webhookUrl: string);
|
|
255
|
+
publish(notes: ReleaseNotes, _format: OutputFormat): Promise<void>;
|
|
256
|
+
private buildDiscordMessage;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Creates or updates a GitHub Release via the GitHub API.
|
|
260
|
+
* Requires GITHUB_TOKEN env var (provided automatically in GitHub Actions).
|
|
261
|
+
*/
|
|
262
|
+
declare class GitHubReleasePublisher implements Publisher {
|
|
263
|
+
private token;
|
|
264
|
+
private owner;
|
|
265
|
+
private repo;
|
|
266
|
+
constructor();
|
|
267
|
+
publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
|
|
268
|
+
private getRelease;
|
|
269
|
+
private createRelease;
|
|
270
|
+
private updateRelease;
|
|
271
|
+
private headers;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Enriches git diff with Jira ticket details.
|
|
276
|
+
* Extracts PROJ-123 style keys from commit messages and fetches from Jira REST API.
|
|
277
|
+
*/
|
|
278
|
+
declare class JiraEnricher implements Enricher {
|
|
279
|
+
private config;
|
|
280
|
+
constructor(config: JiraConfig);
|
|
281
|
+
enrich(diff: GitDiff): Promise<EnrichedTicket[]>;
|
|
282
|
+
private extractUniqueKeys;
|
|
283
|
+
private fetchTicket;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Enriches git diff with Linear issue details.
|
|
288
|
+
* Extracts issue identifiers from commit messages and branch names.
|
|
289
|
+
*/
|
|
290
|
+
declare class LinearEnricher implements Enricher {
|
|
291
|
+
private apiKey;
|
|
292
|
+
constructor(apiKey?: string);
|
|
293
|
+
enrich(diff: GitDiff): Promise<EnrichedTicket[]>;
|
|
294
|
+
private extractUniqueKeys;
|
|
295
|
+
private fetchIssue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Main pipeline: Collect → Enrich → Generate → Format → Publish
|
|
300
|
+
*/
|
|
301
|
+
declare function runPipeline(from: string, to: string, config: CullConfig, options?: {
|
|
302
|
+
format?: OutputFormat;
|
|
303
|
+
dryRun?: boolean;
|
|
304
|
+
}): Promise<PipelineResult>;
|
|
305
|
+
|
|
306
|
+
export { type AIConfig, AIGenerator, type AIProvider, type Audience, type ChangeCategory, type ChangeEntry, type Collector, type CullConfig, DEFAULT_CATEGORIES, DEFAULT_MODELS, DiscordPublisher, type EnrichedContext, type EnrichedTicket, type Enricher, type EnrichmentType, FilePublisher, type Generator, GitCollector, type GitCommit, type GitDiff, GitHubReleasePublisher, JiraCollector, type JiraConfig, JiraEnricher, LinearCollector, type LinearConfig, LinearEnricher, type OpenClawConfig, type OutputFormat, type PipelineResult, type PublishTarget, type Publisher, type PublisherType, type ReleaseNotes, SlackPublisher, type SourceConfig, StdoutPublisher, TemplateGenerator, type Tone, VERSION, formatNotes, getLatestTag, getRecentTags, runPipeline };
|