@cullit/core 1.18.1 → 2.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/dist/index.d.ts +22 -6
- package/dist/index.js +75 -6
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ interface PipelineResult {
|
|
|
71
71
|
duration: number;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
declare const VERSION = "
|
|
74
|
+
declare const VERSION = "2.0.1";
|
|
75
75
|
declare const DEFAULT_CATEGORIES: string[];
|
|
76
76
|
declare const DEFAULT_MODELS: Record<string, string>;
|
|
77
77
|
declare const AI_PROVIDERS: readonly ["anthropic", "openai", "gemini", "ollama", "none"];
|
|
@@ -82,6 +82,12 @@ declare const CHANGE_CATEGORIES: readonly ["features", "fixes", "breaking", "imp
|
|
|
82
82
|
declare const AUDIENCES: readonly ["developer", "end-user", "executive"];
|
|
83
83
|
declare const TONES: readonly ["professional", "casual", "terse", "edgy", "hype", "snarky"];
|
|
84
84
|
declare const SOURCE_TYPES: readonly ["local", "jira", "linear", "gitlab", "bitbucket", "multi-repo"];
|
|
85
|
+
declare const TIERS: readonly ["free", "basic", "pro", "team", "enterprise"];
|
|
86
|
+
declare const PAID_TIERS: readonly ["basic", "pro", "team", "enterprise"];
|
|
87
|
+
declare const TEAM_TIERS: readonly ["team", "enterprise"];
|
|
88
|
+
declare const TEAM_PLANS: readonly ["team-5", "team-10", "team-25"];
|
|
89
|
+
type TeamPlan = (typeof TEAM_PLANS)[number];
|
|
90
|
+
declare const TEAM_PLAN_SEATS: Record<TeamPlan, number>;
|
|
85
91
|
|
|
86
92
|
type LogLevel = 'quiet' | 'normal' | 'verbose';
|
|
87
93
|
interface Logger {
|
|
@@ -219,7 +225,7 @@ declare function analyzeReleaseReadiness(cwd?: string): ReleaseAdvisory;
|
|
|
219
225
|
* validateLicense() performs async remote validation with caching.
|
|
220
226
|
* resolveLicense() remains sync for quick format-only checks (display).
|
|
221
227
|
*/
|
|
222
|
-
type LicenseTier = 'free' | 'pro' | 'team' | 'enterprise';
|
|
228
|
+
type LicenseTier = 'free' | 'basic' | 'pro' | 'team' | 'enterprise';
|
|
223
229
|
interface LicenseStatus {
|
|
224
230
|
tier: LicenseTier;
|
|
225
231
|
valid: boolean;
|
|
@@ -247,8 +253,14 @@ declare function isProviderAllowed(provider: string, license: LicenseStatus): bo
|
|
|
247
253
|
declare function isPublisherAllowed(publisherType: string, license: LicenseStatus): boolean;
|
|
248
254
|
/**
|
|
249
255
|
* Check whether the current license allows enrichment (Jira/Linear).
|
|
256
|
+
* Requires Pro tier or above.
|
|
250
257
|
*/
|
|
251
258
|
declare function isEnrichmentAllowed(license: LicenseStatus): boolean;
|
|
259
|
+
/**
|
|
260
|
+
* Check whether the current license allows audience & tone control.
|
|
261
|
+
* Requires Pro tier or above.
|
|
262
|
+
*/
|
|
263
|
+
declare function isAudienceToneAllowed(license: LicenseStatus): boolean;
|
|
252
264
|
/**
|
|
253
265
|
* Build a human-readable upgrade message for a gated feature.
|
|
254
266
|
*/
|
|
@@ -315,9 +327,13 @@ declare function fetchWithTimeout(url: string, init: RequestInit, timeoutMs?: nu
|
|
|
315
327
|
/**
|
|
316
328
|
* Rate Limiter — Sliding-window rate limiter with pluggable backends.
|
|
317
329
|
*
|
|
330
|
+
* Backends:
|
|
331
|
+
* - MemoryRateLimiter (default) — in-process, single instance only
|
|
332
|
+
* - RedisRateLimiter — shared across instances via REDIS_URL
|
|
333
|
+
*
|
|
318
334
|
* Usage:
|
|
319
335
|
* const limiter = createRateLimiter({ limit: 30, windowMs: 60_000 });
|
|
320
|
-
* const result = limiter.check('user-ip-or-key');
|
|
336
|
+
* const result = await limiter.check('user-ip-or-key');
|
|
321
337
|
* if (!result.allowed) { // reject }
|
|
322
338
|
*/
|
|
323
339
|
interface RateLimitResult {
|
|
@@ -327,9 +343,9 @@ interface RateLimitResult {
|
|
|
327
343
|
resetAt: number;
|
|
328
344
|
}
|
|
329
345
|
interface RateLimiter {
|
|
330
|
-
check(key: string): RateLimitResult
|
|
346
|
+
check(key: string): RateLimitResult | Promise<RateLimitResult>;
|
|
331
347
|
/** Remove all tracked entries */
|
|
332
|
-
reset(): void
|
|
348
|
+
reset(): void | Promise<void>;
|
|
333
349
|
}
|
|
334
350
|
interface RateLimiterOptions {
|
|
335
351
|
/** Max requests per window (default: 30) */
|
|
@@ -378,4 +394,4 @@ declare function runPipeline(from: string, to: string, config: CullConfig, optio
|
|
|
378
394
|
templateProfile?: string;
|
|
379
395
|
}): Promise<PipelineResult>;
|
|
380
396
|
|
|
381
|
-
export { AI_PROVIDERS, AUDIENCES, CHANGE_CATEGORIES, type ChangeCategory, type ChangeEntry, type Collector, type CollectorFactory, CoreErrorCode, type CoreErrorCodeValue, CullitError, DEFAULT_CATEGORIES, DEFAULT_MODELS, ENRICHMENT_TYPES, 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, MultiRepoCollector, OUTPUT_FORMATS, PUBLISHER_TYPES, type PipelineResult, type Publisher, type PublisherFactory, type RateLimitResult, type RateLimiter, type RateLimiterOptions, type ReleaseAdvisory, type ReleaseNotes, SOURCE_TYPES, type SemverBump, StdoutPublisher, TONES, type TeamFeature, TemplateGenerator, type UsageLimits, VERSION, analyzeReleaseReadiness, createLogger, createRateLimiter, escapeHtml, fetchWithTimeout, formatNotes, getCollector, getEnricher, getFeatureGating, getFormatter, getGenerator, getLatestTag, getPublisher, getRecentTags, getTierLimits, hasCollector, hasEnricher, hasGenerator, hasPublisher, isEnrichmentAllowed, isFeatureAllowed, isProviderAllowed, isPublisherAllowed, listCollectors, listEnrichers, listFormatters, listGenerators, listPublishers, registerCollector, registerEnricher, registerFormatter, registerGenerator, registerPublisher, reportUsage, resolveLicense, runPipeline, upgradeMessage, validateLicense };
|
|
397
|
+
export { AI_PROVIDERS, AUDIENCES, CHANGE_CATEGORIES, type ChangeCategory, type ChangeEntry, type Collector, type CollectorFactory, CoreErrorCode, type CoreErrorCodeValue, CullitError, DEFAULT_CATEGORIES, DEFAULT_MODELS, ENRICHMENT_TYPES, 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, MultiRepoCollector, OUTPUT_FORMATS, PAID_TIERS, PUBLISHER_TYPES, type PipelineResult, type Publisher, type PublisherFactory, type RateLimitResult, type RateLimiter, type RateLimiterOptions, type ReleaseAdvisory, type ReleaseNotes, SOURCE_TYPES, type SemverBump, StdoutPublisher, TEAM_PLANS, TEAM_PLAN_SEATS, TEAM_TIERS, TIERS, TONES, type TeamFeature, type TeamPlan, TemplateGenerator, type UsageLimits, VERSION, analyzeReleaseReadiness, createLogger, createRateLimiter, escapeHtml, fetchWithTimeout, formatNotes, getCollector, getEnricher, getFeatureGating, getFormatter, getGenerator, getLatestTag, getPublisher, getRecentTags, getTierLimits, hasCollector, hasEnricher, hasGenerator, hasPublisher, isAudienceToneAllowed, isEnrichmentAllowed, isFeatureAllowed, isProviderAllowed, isPublisherAllowed, listCollectors, listEnrichers, listFormatters, listGenerators, listPublishers, registerCollector, registerEnricher, registerFormatter, registerGenerator, registerPublisher, reportUsage, resolveLicense, runPipeline, upgradeMessage, validateLicense };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
|
-
var VERSION = "
|
|
2
|
+
var VERSION = "2.0.1";
|
|
3
3
|
var DEFAULT_CATEGORIES = ["features", "fixes", "breaking", "improvements", "chores"];
|
|
4
4
|
var DEFAULT_MODELS = {
|
|
5
5
|
anthropic: "claude-sonnet-4-20250514",
|
|
@@ -15,6 +15,15 @@ var CHANGE_CATEGORIES = ["features", "fixes", "breaking", "improvements", "chore
|
|
|
15
15
|
var AUDIENCES = ["developer", "end-user", "executive"];
|
|
16
16
|
var TONES = ["professional", "casual", "terse", "edgy", "hype", "snarky"];
|
|
17
17
|
var SOURCE_TYPES = ["local", "jira", "linear", "gitlab", "bitbucket", "multi-repo"];
|
|
18
|
+
var TIERS = ["free", "basic", "pro", "team", "enterprise"];
|
|
19
|
+
var PAID_TIERS = ["basic", "pro", "team", "enterprise"];
|
|
20
|
+
var TEAM_TIERS = ["team", "enterprise"];
|
|
21
|
+
var TEAM_PLANS = ["team-5", "team-10", "team-25"];
|
|
22
|
+
var TEAM_PLAN_SEATS = {
|
|
23
|
+
"team-5": 5,
|
|
24
|
+
"team-10": 10,
|
|
25
|
+
"team-25": 25
|
|
26
|
+
};
|
|
18
27
|
|
|
19
28
|
// src/logger.ts
|
|
20
29
|
function createLogger(level = "normal") {
|
|
@@ -796,7 +805,7 @@ async function validateLicense() {
|
|
|
796
805
|
if (res.ok) {
|
|
797
806
|
const data = await res.json();
|
|
798
807
|
const status2 = {
|
|
799
|
-
tier: data.tier === "team" || data.tier === "enterprise" ? data.tier : data.tier === "pro" ? "pro" : "free",
|
|
808
|
+
tier: data.tier === "team" || data.tier === "enterprise" ? data.tier : data.tier === "pro" ? "pro" : data.tier === "basic" ? "basic" : "free",
|
|
800
809
|
valid: data.valid !== false,
|
|
801
810
|
message: data.message
|
|
802
811
|
};
|
|
@@ -829,15 +838,19 @@ function isPublisherAllowed(publisherType, license) {
|
|
|
829
838
|
return FREE_PUBLISHERS.has(publisherType);
|
|
830
839
|
}
|
|
831
840
|
function isEnrichmentAllowed(license) {
|
|
832
|
-
return license.tier
|
|
841
|
+
return (license.tier === "pro" || license.tier === "team" || license.tier === "enterprise") && license.valid;
|
|
842
|
+
}
|
|
843
|
+
function isAudienceToneAllowed(license) {
|
|
844
|
+
return (license.tier === "pro" || license.tier === "team" || license.tier === "enterprise") && license.valid;
|
|
833
845
|
}
|
|
834
846
|
function upgradeMessage(feature) {
|
|
835
|
-
return `\u{1F512} ${feature} requires a Cullit Pro
|
|
836
|
-
|
|
847
|
+
return `\u{1F512} ${feature} requires a Cullit Pro plan or above.
|
|
848
|
+
Upgrade at https://cullit.io/pricing
|
|
837
849
|
Then set CULLIT_API_KEY in your environment.`;
|
|
838
850
|
}
|
|
839
851
|
var TIER_LIMITS = {
|
|
840
852
|
free: { generationsPerMonth: 5, maxProjects: 3 },
|
|
853
|
+
basic: { generationsPerMonth: 50, maxProjects: 10 },
|
|
841
854
|
pro: { generationsPerMonth: 500, maxProjects: 100 },
|
|
842
855
|
team: { generationsPerMonth: 2e3, maxProjects: 250 },
|
|
843
856
|
enterprise: { generationsPerMonth: Infinity, maxProjects: Infinity }
|
|
@@ -850,7 +863,7 @@ var FEATURE_TIERS = {
|
|
|
850
863
|
approvals: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
851
864
|
shared_history: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
852
865
|
project_templates: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
853
|
-
hosted_changelog: /* @__PURE__ */ new Set(["pro", "team", "enterprise"]),
|
|
866
|
+
hosted_changelog: /* @__PURE__ */ new Set(["basic", "pro", "team", "enterprise"]),
|
|
854
867
|
branded_widget: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
855
868
|
team_publishers: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
856
869
|
org_settings: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
@@ -986,8 +999,58 @@ var MemoryRateLimiter = class {
|
|
|
986
999
|
}
|
|
987
1000
|
};
|
|
988
1001
|
function createRateLimiter(opts) {
|
|
1002
|
+
const redisUrl = process.env["REDIS_URL"];
|
|
1003
|
+
if (redisUrl) {
|
|
1004
|
+
return new RedisRateLimiter(redisUrl, opts);
|
|
1005
|
+
}
|
|
989
1006
|
return new MemoryRateLimiter(opts);
|
|
990
1007
|
}
|
|
1008
|
+
var RedisRateLimiter = class {
|
|
1009
|
+
limit;
|
|
1010
|
+
windowMs;
|
|
1011
|
+
redisUrl;
|
|
1012
|
+
prefix;
|
|
1013
|
+
constructor(redisUrl, opts = {}) {
|
|
1014
|
+
this.limit = opts.limit ?? 30;
|
|
1015
|
+
this.windowMs = opts.windowMs ?? 6e4;
|
|
1016
|
+
this.redisUrl = redisUrl;
|
|
1017
|
+
this.prefix = "cullit:rl:";
|
|
1018
|
+
}
|
|
1019
|
+
async check(key) {
|
|
1020
|
+
const now = Date.now();
|
|
1021
|
+
const windowStart = now - this.windowMs;
|
|
1022
|
+
const redisKey = this.prefix + key;
|
|
1023
|
+
try {
|
|
1024
|
+
const res = await fetch(this.redisUrl, {
|
|
1025
|
+
method: "POST",
|
|
1026
|
+
headers: { "Content-Type": "application/json" },
|
|
1027
|
+
body: JSON.stringify([
|
|
1028
|
+
["ZREMRANGEBYSCORE", redisKey, "0", String(windowStart)],
|
|
1029
|
+
["ZCARD", redisKey],
|
|
1030
|
+
["ZADD", redisKey, String(now), `${now}-${Math.random().toString(36).slice(2, 8)}`],
|
|
1031
|
+
["PEXPIRE", redisKey, String(this.windowMs)]
|
|
1032
|
+
]),
|
|
1033
|
+
signal: AbortSignal.timeout(3e3)
|
|
1034
|
+
});
|
|
1035
|
+
if (!res.ok) return this.fallbackAllow(now);
|
|
1036
|
+
const results = await res.json();
|
|
1037
|
+
const count = results[1]?.result ?? 0;
|
|
1038
|
+
const remaining = Math.max(0, this.limit - count);
|
|
1039
|
+
const resetAt = Math.ceil((now + this.windowMs) / 1e3);
|
|
1040
|
+
if (count >= this.limit) {
|
|
1041
|
+
return { allowed: false, remaining: 0, resetAt };
|
|
1042
|
+
}
|
|
1043
|
+
return { allowed: true, remaining: remaining - 1, resetAt };
|
|
1044
|
+
} catch {
|
|
1045
|
+
return this.fallbackAllow(now);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
fallbackAllow(now) {
|
|
1049
|
+
return { allowed: true, remaining: this.limit, resetAt: Math.ceil((now + this.windowMs) / 1e3) };
|
|
1050
|
+
}
|
|
1051
|
+
async reset() {
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
991
1054
|
|
|
992
1055
|
// src/index.ts
|
|
993
1056
|
registerCollector("local", (config) => new GitCollector(config.source?.repoPath));
|
|
@@ -1210,9 +1273,14 @@ export {
|
|
|
1210
1273
|
GitCollector,
|
|
1211
1274
|
MultiRepoCollector,
|
|
1212
1275
|
OUTPUT_FORMATS,
|
|
1276
|
+
PAID_TIERS,
|
|
1213
1277
|
PUBLISHER_TYPES,
|
|
1214
1278
|
SOURCE_TYPES,
|
|
1215
1279
|
StdoutPublisher,
|
|
1280
|
+
TEAM_PLANS,
|
|
1281
|
+
TEAM_PLAN_SEATS,
|
|
1282
|
+
TEAM_TIERS,
|
|
1283
|
+
TIERS,
|
|
1216
1284
|
TONES,
|
|
1217
1285
|
TemplateGenerator,
|
|
1218
1286
|
VERSION,
|
|
@@ -1235,6 +1303,7 @@ export {
|
|
|
1235
1303
|
hasEnricher,
|
|
1236
1304
|
hasGenerator,
|
|
1237
1305
|
hasPublisher,
|
|
1306
|
+
isAudienceToneAllowed,
|
|
1238
1307
|
isEnrichmentAllowed,
|
|
1239
1308
|
isFeatureAllowed,
|
|
1240
1309
|
isProviderAllowed,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cullit/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core engine for Cullit — AI-powered release note generation.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@cullit/config": "
|
|
41
|
+
"@cullit/config": "2.0.1"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsup src/index.ts --format esm --dts --clean",
|