@cullit/core 1.9.2 → 1.10.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/dist/index.d.ts +4 -3
- package/dist/index.js +19 -14
- package/package.json +10 -3
package/dist/index.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ interface PipelineResult {
|
|
|
71
71
|
duration: number;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
declare const VERSION = "1.
|
|
74
|
+
declare const VERSION = "1.10.0";
|
|
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", "openclaw", "none"];
|
|
@@ -159,6 +159,7 @@ declare function registerFormatter(format: string, fn: FormatterFn): void;
|
|
|
159
159
|
declare function getFormatter(format: string): FormatterFn | undefined;
|
|
160
160
|
declare function listFormatters(): string[];
|
|
161
161
|
declare function formatNotes(notes: ReleaseNotes, format: OutputFormat): string;
|
|
162
|
+
declare function escapeHtml(str: string): string;
|
|
162
163
|
|
|
163
164
|
/**
|
|
164
165
|
* Outputs release notes to stdout (default).
|
|
@@ -281,7 +282,7 @@ declare function reportUsage(project?: string): Promise<void>;
|
|
|
281
282
|
* Core registers: git collector, template generator, stdout/file publishers.
|
|
282
283
|
* Pro registers: AI generator, Jira/Linear collectors + enrichers, Slack/Discord/GitHub publishers.
|
|
283
284
|
*
|
|
284
|
-
*
|
|
285
|
+
* Paid plugin registration is preloaded by the licensed distribution package.
|
|
285
286
|
*/
|
|
286
287
|
|
|
287
288
|
type CollectorFactory = (...args: any[]) => Collector;
|
|
@@ -321,4 +322,4 @@ declare function runPipeline(from: string, to: string, config: CullConfig, optio
|
|
|
321
322
|
templateProfile?: string;
|
|
322
323
|
}): Promise<PipelineResult>;
|
|
323
324
|
|
|
324
|
-
export { AI_PROVIDERS, AUDIENCES, CHANGE_CATEGORIES, type ChangeCategory, type ChangeEntry, type Collector, type CollectorFactory, 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 ReleaseAdvisory, type ReleaseNotes, SOURCE_TYPES, type SemverBump, StdoutPublisher, TONES, type TeamFeature, TemplateGenerator, type UsageLimits, VERSION, analyzeReleaseReadiness, createLogger, 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 };
|
|
325
|
+
export { AI_PROVIDERS, AUDIENCES, CHANGE_CATEGORIES, type ChangeCategory, type ChangeEntry, type Collector, type CollectorFactory, 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 ReleaseAdvisory, type ReleaseNotes, SOURCE_TYPES, type SemverBump, StdoutPublisher, TONES, type TeamFeature, TemplateGenerator, type UsageLimits, VERSION, analyzeReleaseReadiness, createLogger, 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 };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
|
-
var VERSION = "1.
|
|
2
|
+
var VERSION = "1.10.0";
|
|
3
3
|
var DEFAULT_CATEGORIES = ["features", "fixes", "breaking", "improvements", "chores"];
|
|
4
4
|
var DEFAULT_MODELS = {
|
|
5
5
|
anthropic: "claude-sonnet-4-20250514",
|
|
@@ -72,7 +72,8 @@ var GitCollector = class {
|
|
|
72
72
|
{ cwd: this.cwd, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
|
|
73
73
|
);
|
|
74
74
|
} catch (error) {
|
|
75
|
-
const
|
|
75
|
+
const errWithStderr = typeof error === "object" && error !== null && "stderr" in error ? error : void 0;
|
|
76
|
+
const stderr = errWithStderr?.stderr?.toString?.() || "";
|
|
76
77
|
const hint = stderr.includes("unknown revision") ? 'Check that both refs exist (run "cullit tags" to see tags).' : stderr.includes("not a git repository") ? "Run this command inside a git repository." : `Make sure both refs exist and you're in a git repository.`;
|
|
77
78
|
throw new Error(
|
|
78
79
|
`Failed to read git log between ${from} and ${to}. ${hint}`
|
|
@@ -417,15 +418,15 @@ function formatNotes(notes, format) {
|
|
|
417
418
|
const fn = formatters.get(format) || formatters.get("markdown");
|
|
418
419
|
return fn(notes);
|
|
419
420
|
}
|
|
420
|
-
function
|
|
421
|
+
function sanitizeForMarkdown(text) {
|
|
421
422
|
return escapeHtml(text).replace(/\r?\n/g, " ");
|
|
422
423
|
}
|
|
423
424
|
function formatMarkdown(notes) {
|
|
424
425
|
const lines = [];
|
|
425
|
-
lines.push(`## ${
|
|
426
|
+
lines.push(`## ${sanitizeForMarkdown(notes.version)} \u2014 ${sanitizeForMarkdown(notes.date)}`);
|
|
426
427
|
lines.push("");
|
|
427
428
|
if (notes.summary) {
|
|
428
|
-
lines.push(
|
|
429
|
+
lines.push(sanitizeForMarkdown(notes.summary));
|
|
429
430
|
lines.push("");
|
|
430
431
|
}
|
|
431
432
|
const grouped = groupByCategory(notes);
|
|
@@ -435,8 +436,8 @@ function formatMarkdown(notes) {
|
|
|
435
436
|
lines.push(`### ${CATEGORY_LABELS[category]}`);
|
|
436
437
|
lines.push("");
|
|
437
438
|
for (const entry of entries) {
|
|
438
|
-
let line = `- ${
|
|
439
|
-
if (entry.ticketKey) line += ` (${
|
|
439
|
+
let line = `- ${sanitizeForMarkdown(entry.description)}`;
|
|
440
|
+
if (entry.ticketKey) line += ` (${sanitizeForMarkdown(entry.ticketKey)})`;
|
|
440
441
|
lines.push(line);
|
|
441
442
|
}
|
|
442
443
|
lines.push("");
|
|
@@ -444,7 +445,7 @@ function formatMarkdown(notes) {
|
|
|
444
445
|
if (notes.contributors?.length) {
|
|
445
446
|
lines.push("### Contributors");
|
|
446
447
|
lines.push("");
|
|
447
|
-
lines.push(notes.contributors.map((c) => `@${
|
|
448
|
+
lines.push(notes.contributors.map((c) => `@${sanitizeForMarkdown(c)}`).join(", "));
|
|
448
449
|
lines.push("");
|
|
449
450
|
}
|
|
450
451
|
if (notes.metadata) {
|
|
@@ -772,7 +773,7 @@ async function validateLicense() {
|
|
|
772
773
|
if (cachedValidation && cachedValidation.key === key) {
|
|
773
774
|
return cachedValidation.status;
|
|
774
775
|
}
|
|
775
|
-
return { tier: "
|
|
776
|
+
return { tier: "free", valid: true, message: "License validation unavailable offline. Run while connected to activate your Pro license." };
|
|
776
777
|
}
|
|
777
778
|
}
|
|
778
779
|
function isProviderAllowed(provider, license) {
|
|
@@ -977,7 +978,10 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
977
978
|
const log = options.logger || createLogger("normal");
|
|
978
979
|
const license = await validateLicense();
|
|
979
980
|
if (!license.valid) {
|
|
980
|
-
|
|
981
|
+
if (!isProviderAllowed(config.ai.provider, license)) {
|
|
982
|
+
throw new Error(license.message || "Invalid CULLIT_API_KEY");
|
|
983
|
+
}
|
|
984
|
+
log.warn(`\u26A0 ${license.message || "Invalid CULLIT_API_KEY \u2014 running in free mode."}`);
|
|
981
985
|
}
|
|
982
986
|
if (!isProviderAllowed(config.ai.provider, license)) {
|
|
983
987
|
throw new Error(upgradeMessage(`AI provider "${config.ai.provider}"`));
|
|
@@ -985,7 +989,7 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
985
989
|
const collectorFactory = getCollector(config.source.type);
|
|
986
990
|
if (!collectorFactory) {
|
|
987
991
|
throw new Error(
|
|
988
|
-
`Source type "${config.source.type}" is not available. ` + (config.source.type !== "local" ? "Install @cullit/
|
|
992
|
+
`Source type "${config.source.type}" is not available. ` + (config.source.type !== "local" ? "Install @cullit/licensed (private distribution) to use this source." : "Valid sources: local")
|
|
989
993
|
);
|
|
990
994
|
}
|
|
991
995
|
const sourceLabel = config.source.type === "local" ? `commits between ${from}..${to}` : `items from ${config.source.type}`;
|
|
@@ -1007,7 +1011,7 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
1007
1011
|
}
|
|
1008
1012
|
const enricherFactory = getEnricher(source);
|
|
1009
1013
|
if (!enricherFactory) {
|
|
1010
|
-
log.info(`\xBB Skipping ${source} enrichment \u2014 install @cullit/
|
|
1014
|
+
log.info(`\xBB Skipping ${source} enrichment \u2014 install @cullit/licensed to enable`);
|
|
1011
1015
|
continue;
|
|
1012
1016
|
}
|
|
1013
1017
|
log.info(`\xBB Enriching from ${source}...`);
|
|
@@ -1031,7 +1035,7 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
1031
1035
|
const generatorFactory = getGenerator(config.ai.provider);
|
|
1032
1036
|
if (!generatorFactory) {
|
|
1033
1037
|
throw new Error(
|
|
1034
|
-
`AI provider "${config.ai.provider}" is not available. ` + (config.ai.provider !== "none" ? "Install @cullit/
|
|
1038
|
+
`AI provider "${config.ai.provider}" is not available. ` + (config.ai.provider !== "none" ? "Install @cullit/licensed (private distribution) to use AI providers." : "")
|
|
1035
1039
|
);
|
|
1036
1040
|
}
|
|
1037
1041
|
let generator;
|
|
@@ -1061,7 +1065,7 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
1061
1065
|
}
|
|
1062
1066
|
const publisherFactory = getPublisher(target.type);
|
|
1063
1067
|
if (!publisherFactory) {
|
|
1064
|
-
log.info(`\xBB Skipping ${target.type} \u2014 install @cullit/
|
|
1068
|
+
log.info(`\xBB Skipping ${target.type} \u2014 install @cullit/licensed to enable`);
|
|
1065
1069
|
continue;
|
|
1066
1070
|
}
|
|
1067
1071
|
const publisher = publisherFactory(target);
|
|
@@ -1129,6 +1133,7 @@ export {
|
|
|
1129
1133
|
VERSION,
|
|
1130
1134
|
analyzeReleaseReadiness,
|
|
1131
1135
|
createLogger,
|
|
1136
|
+
escapeHtml,
|
|
1132
1137
|
fetchWithTimeout,
|
|
1133
1138
|
formatNotes,
|
|
1134
1139
|
getCollector,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cullit/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core engine for Cullit — AI-powered release note generation.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"ai",
|
|
17
17
|
"automation"
|
|
18
18
|
],
|
|
19
|
+
"homepage": "https://cullit.io",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/mttaylor/cullit/issues"
|
|
22
|
+
},
|
|
19
23
|
"main": "./dist/index.js",
|
|
20
24
|
"types": "./dist/index.d.ts",
|
|
21
25
|
"exports": {
|
|
@@ -28,10 +32,13 @@
|
|
|
28
32
|
"dist"
|
|
29
33
|
],
|
|
30
34
|
"engines": {
|
|
31
|
-
"node": ">=
|
|
35
|
+
"node": ">=22"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
32
39
|
},
|
|
33
40
|
"dependencies": {
|
|
34
|
-
"@cullit/config": "1.
|
|
41
|
+
"@cullit/config": "1.10.0"
|
|
35
42
|
},
|
|
36
43
|
"scripts": {
|
|
37
44
|
"build": "tsup src/index.ts --format esm --dts --clean",
|