@cullit/core 0.1.0 → 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.
Files changed (3) hide show
  1. package/dist/index.d.ts +105 -153
  2. package/dist/index.js +369 -824
  3. package/package.json +5 -2
package/dist/index.d.ts CHANGED
@@ -1,50 +1,6 @@
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
- }
1
+ import { EnrichmentType, OutputFormat, AIConfig, CullConfig } from '@cullit/config';
2
+ export { AIConfig, AIProvider, Audience, CullConfig, EnrichmentType, JiraConfig, LinearConfig, OpenClawConfig, OutputFormat, PublishTarget, PublisherType, SourceConfig, Tone } from '@cullit/config';
3
+
48
4
  interface GitCommit {
49
5
  hash: string;
50
6
  shortHash: string;
@@ -106,7 +62,7 @@ interface Generator {
106
62
  generate(context: EnrichedContext, config: AIConfig): Promise<ReleaseNotes>;
107
63
  }
108
64
  interface Publisher {
109
- publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
65
+ publish(notes: ReleaseNotes, format: OutputFormat, preformatted?: string): Promise<void>;
110
66
  }
111
67
  interface PipelineResult {
112
68
  notes: ReleaseNotes;
@@ -115,10 +71,19 @@ interface PipelineResult {
115
71
  duration: number;
116
72
  }
117
73
 
118
- declare const VERSION = "0.1.0";
74
+ declare const VERSION = "0.4.0";
119
75
  declare const DEFAULT_CATEGORIES: string[];
120
76
  declare const DEFAULT_MODELS: Record<string, string>;
121
77
 
78
+ type LogLevel = 'quiet' | 'normal' | 'verbose';
79
+ interface Logger {
80
+ info(msg: string): void;
81
+ verbose(msg: string): void;
82
+ warn(msg: string): void;
83
+ error(msg: string): void;
84
+ }
85
+ declare function createLogger(level?: LogLevel): Logger;
86
+
122
87
  /**
123
88
  * Collects git log data between two refs (tags, branches, or commit SHAs).
124
89
  * Extracts commits, PR numbers, and issue keys from commit messages.
@@ -150,63 +115,6 @@ declare function getRecentTags(cwd?: string, count?: number): string[];
150
115
  */
151
116
  declare function getLatestTag(cwd?: string): string | null;
152
117
 
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
118
  /**
211
119
  * Template-based release notes generator — no AI required.
212
120
  * Groups commits by conventional commit prefix and ticket type.
@@ -227,7 +135,7 @@ declare function formatNotes(notes: ReleaseNotes, format: OutputFormat): string;
227
135
  * Outputs release notes to stdout (default).
228
136
  */
229
137
  declare class StdoutPublisher implements Publisher {
230
- publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
138
+ publish(notes: ReleaseNotes, format: OutputFormat, preformatted?: string): Promise<void>;
231
139
  }
232
140
  /**
233
141
  * Writes release notes to a file.
@@ -235,65 +143,108 @@ declare class StdoutPublisher implements Publisher {
235
143
  declare class FilePublisher implements Publisher {
236
144
  private path;
237
145
  constructor(path: string);
238
- publish(notes: ReleaseNotes, format: OutputFormat): Promise<void>;
146
+ publish(notes: ReleaseNotes, format: OutputFormat, preformatted?: string): Promise<void>;
147
+ }
148
+
149
+ type SemverBump = 'patch' | 'minor' | 'major';
150
+ interface ReleaseAdvisory {
151
+ /** Whether a release is recommended now */
152
+ shouldRelease: boolean;
153
+ /** Suggested semver bump type */
154
+ suggestedBump: SemverBump;
155
+ /** Current (latest) version tag */
156
+ currentVersion: string | null;
157
+ /** What the next version would be */
158
+ nextVersion: string | null;
159
+ /** Number of unreleased commits */
160
+ commitCount: number;
161
+ /** Number of unique contributors */
162
+ contributorCount: number;
163
+ /** Days since last release */
164
+ daysSinceRelease: number | null;
165
+ /** Breakdown of commit types */
166
+ breakdown: {
167
+ features: number;
168
+ fixes: number;
169
+ breaking: number;
170
+ chores: number;
171
+ other: number;
172
+ };
173
+ /** Human-readable reasons for the recommendation */
174
+ reasons: string[];
239
175
  }
240
176
  /**
241
- * Posts release notes to a Slack channel via webhook.
177
+ * Analyzes the repo state and provides a release recommendation.
178
+ * Examines commits since the last tag, categorizes them via conventional
179
+ * commit patterns, and applies industry-standard heuristics.
242
180
  */
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
- }
181
+ declare function analyzeReleaseReadiness(cwd?: string): ReleaseAdvisory;
182
+
249
183
  /**
250
- * Posts release notes to Discord via webhook.
184
+ * Cullit License Gating
185
+ *
186
+ * Free tier (no key): provider=none, publish to stdout/file only
187
+ * Pro tier (with key): all providers, all publishers, all enrichments
251
188
  */
252
- declare class DiscordPublisher implements Publisher {
253
- private webhookUrl;
254
- constructor(webhookUrl: string);
255
- publish(notes: ReleaseNotes, _format: OutputFormat): Promise<void>;
256
- private buildDiscordMessage;
189
+ type LicenseTier = 'free' | 'pro';
190
+ interface LicenseStatus {
191
+ tier: LicenseTier;
192
+ valid: boolean;
193
+ message?: string;
257
194
  }
258
195
  /**
259
- * Creates or updates a GitHub Release via the GitHub API.
260
- * Requires GITHUB_TOKEN env var (provided automatically in GitHub Actions).
196
+ * Resolve the user's license tier from CULLIT_API_KEY env var.
197
+ * Validates the key format and caches verification result.
261
198
  */
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
- }
199
+ declare function resolveLicense(): LicenseStatus;
200
+ /**
201
+ * Check whether the current license allows the requested provider.
202
+ */
203
+ declare function isProviderAllowed(provider: string, license: LicenseStatus): boolean;
204
+ /**
205
+ * Check whether the current license allows the requested publisher.
206
+ */
207
+ declare function isPublisherAllowed(publisherType: string, license: LicenseStatus): boolean;
208
+ /**
209
+ * Check whether the current license allows enrichment (Jira/Linear).
210
+ */
211
+ declare function isEnrichmentAllowed(license: LicenseStatus): boolean;
212
+ /**
213
+ * Build a human-readable upgrade message for a gated feature.
214
+ */
215
+ declare function upgradeMessage(feature: string): string;
273
216
 
274
217
  /**
275
- * Enriches git diff with Jira ticket details.
276
- * Extracts PROJ-123 style keys from commit messages and fetches from Jira REST API.
218
+ * Plugin Registry the seam between free (core) and pro features.
219
+ *
220
+ * Core registers: git collector, template generator, stdout/file publishers.
221
+ * Pro registers: AI generator, Jira/Linear collectors + enrichers, Slack/Discord/GitHub publishers.
222
+ *
223
+ * The CLI calls `await import('@cullit/pro')` to load pro plugins if installed.
277
224
  */
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
- }
225
+
226
+ type CollectorFactory = (...args: any[]) => Collector;
227
+ type EnricherFactory = (...args: any[]) => Enricher;
228
+ type GeneratorFactory = (...args: any[]) => Generator;
229
+ type PublisherFactory = (...args: any[]) => Publisher;
230
+ declare function registerCollector(type: string, factory: CollectorFactory): void;
231
+ declare function registerEnricher(type: string, factory: EnricherFactory): void;
232
+ declare function registerGenerator(provider: string, factory: GeneratorFactory): void;
233
+ declare function registerPublisher(type: string, factory: PublisherFactory): void;
234
+ declare function getCollector(type: string): CollectorFactory | undefined;
235
+ declare function getEnricher(type: string): EnricherFactory | undefined;
236
+ declare function getGenerator(provider: string): GeneratorFactory | undefined;
237
+ declare function getPublisher(type: string): PublisherFactory | undefined;
238
+ declare function hasGenerator(provider: string): boolean;
239
+ declare function hasCollector(type: string): boolean;
240
+ declare function hasPublisher(type: string): boolean;
241
+ declare function hasEnricher(type: string): boolean;
285
242
 
286
243
  /**
287
- * Enriches git diff with Linear issue details.
288
- * Extracts issue identifiers from commit messages and branch names.
244
+ * Shared fetch wrapper with timeout support.
245
+ * Prevents hanging on unresponsive external APIs.
289
246
  */
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
- }
247
+ declare function fetchWithTimeout(url: string, init: RequestInit, timeoutMs?: number): Promise<Response>;
297
248
 
298
249
  /**
299
250
  * Main pipeline: Collect → Enrich → Generate → Format → Publish
@@ -301,6 +252,7 @@ declare class LinearEnricher implements Enricher {
301
252
  declare function runPipeline(from: string, to: string, config: CullConfig, options?: {
302
253
  format?: OutputFormat;
303
254
  dryRun?: boolean;
255
+ logger?: Logger;
304
256
  }): Promise<PipelineResult>;
305
257
 
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 };
258
+ export { type ChangeCategory, type ChangeEntry, type Collector, type CollectorFactory, DEFAULT_CATEGORIES, DEFAULT_MODELS, type EnrichedContext, type EnrichedTicket, type Enricher, type EnricherFactory, FilePublisher, type Generator, type GeneratorFactory, GitCollector, type GitCommit, type GitDiff, type LicenseStatus, type LicenseTier, type LogLevel, type Logger, type PipelineResult, type Publisher, type PublisherFactory, type ReleaseAdvisory, type ReleaseNotes, type SemverBump, StdoutPublisher, TemplateGenerator, VERSION, analyzeReleaseReadiness, createLogger, fetchWithTimeout, formatNotes, getCollector, getEnricher, getGenerator, getLatestTag, getPublisher, getRecentTags, hasCollector, hasEnricher, hasGenerator, hasPublisher, isEnrichmentAllowed, isProviderAllowed, isPublisherAllowed, registerCollector, registerEnricher, registerGenerator, registerPublisher, resolveLicense, runPipeline, upgradeMessage };