@cullit/core 1.8.0 → 1.9.2
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 +15 -4
- package/dist/index.js +147 -17
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EnrichmentType, OutputFormat, AIConfig, RepoSource, CullConfig } from '@cullit/config';
|
|
2
|
-
export { AIConfig, AIProvider, Audience, BitbucketConfig, ConfluenceConfig, CullConfig, EnrichmentType, GitLabConfig, JiraConfig, LinearConfig, NotionConfig, OpenClawConfig, OutputFormat, PublishTarget, PublisherType, RepoSource, SourceConfig, Tone } from '@cullit/config';
|
|
2
|
+
export { AIConfig, AIProvider, Audience, BitbucketConfig, ConfluenceConfig, CullConfig, EnrichmentType, GitLabConfig, JiraConfig, LinearConfig, NotionConfig, OpenClawConfig, OutputFormat, PublishTarget, PublisherType, RepoSource, SourceConfig, TemplateConfig, TemplateProfile, Tone } from '@cullit/config';
|
|
3
3
|
|
|
4
4
|
interface GitCommit {
|
|
5
5
|
hash: string;
|
|
@@ -71,7 +71,7 @@ interface PipelineResult {
|
|
|
71
71
|
duration: number;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
declare const VERSION = "1.
|
|
74
|
+
declare const VERSION = "1.9.2";
|
|
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"];
|
|
@@ -218,7 +218,7 @@ declare function analyzeReleaseReadiness(cwd?: string): ReleaseAdvisory;
|
|
|
218
218
|
* validateLicense() performs async remote validation with caching.
|
|
219
219
|
* resolveLicense() remains sync for quick format-only checks (display).
|
|
220
220
|
*/
|
|
221
|
-
type LicenseTier = 'free' | 'pro';
|
|
221
|
+
type LicenseTier = 'free' | 'pro' | 'team' | 'enterprise';
|
|
222
222
|
interface LicenseStatus {
|
|
223
223
|
tier: LicenseTier;
|
|
224
224
|
valid: boolean;
|
|
@@ -241,6 +241,7 @@ declare function validateLicense(): Promise<LicenseStatus>;
|
|
|
241
241
|
declare function isProviderAllowed(provider: string, license: LicenseStatus): boolean;
|
|
242
242
|
/**
|
|
243
243
|
* Check whether the current license allows the requested publisher.
|
|
244
|
+
* Confluence, Notion, and Teams require Team tier or above.
|
|
244
245
|
*/
|
|
245
246
|
declare function isPublisherAllowed(publisherType: string, license: LicenseStatus): boolean;
|
|
246
247
|
/**
|
|
@@ -259,6 +260,15 @@ interface UsageLimits {
|
|
|
259
260
|
* Get usage limits for a license tier.
|
|
260
261
|
*/
|
|
261
262
|
declare function getTierLimits(tier: string): UsageLimits;
|
|
263
|
+
type TeamFeature = 'drafts' | 'approvals' | 'shared_history' | 'project_templates' | 'hosted_changelog' | 'branded_widget' | 'team_publishers' | 'org_settings' | 'audit_logs' | 'sso';
|
|
264
|
+
/**
|
|
265
|
+
* Check whether a license tier grants access to a Team/Enterprise feature.
|
|
266
|
+
*/
|
|
267
|
+
declare function isFeatureAllowed(feature: TeamFeature, tier: string): boolean;
|
|
268
|
+
/**
|
|
269
|
+
* Build a gating summary for a tier — which features are unlocked.
|
|
270
|
+
*/
|
|
271
|
+
declare function getFeatureGating(tier: string): Record<TeamFeature, boolean>;
|
|
262
272
|
/**
|
|
263
273
|
* Report a generation event to the metering service.
|
|
264
274
|
* Non-blocking — failures are logged but never block the pipeline.
|
|
@@ -308,6 +318,7 @@ declare function runPipeline(from: string, to: string, config: CullConfig, optio
|
|
|
308
318
|
format?: OutputFormat;
|
|
309
319
|
dryRun?: boolean;
|
|
310
320
|
logger?: Logger;
|
|
321
|
+
templateProfile?: string;
|
|
311
322
|
}): Promise<PipelineResult>;
|
|
312
323
|
|
|
313
|
-
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, TemplateGenerator, type UsageLimits, VERSION, analyzeReleaseReadiness, createLogger, fetchWithTimeout, formatNotes, getCollector, getEnricher, getFormatter, getGenerator, getLatestTag, getPublisher, getRecentTags, getTierLimits, hasCollector, hasEnricher, hasGenerator, hasPublisher, isEnrichmentAllowed, isProviderAllowed, isPublisherAllowed, listCollectors, listEnrichers, listFormatters, listGenerators, listPublishers, registerCollector, registerEnricher, registerFormatter, registerGenerator, registerPublisher, reportUsage, resolveLicense, runPipeline, upgradeMessage, validateLicense };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/constants.ts
|
|
2
|
-
var VERSION = "1.
|
|
2
|
+
var VERSION = "1.9.2";
|
|
3
3
|
var DEFAULT_CATEGORIES = ["features", "fixes", "breaking", "improvements", "chores"];
|
|
4
4
|
var DEFAULT_MODELS = {
|
|
5
5
|
anthropic: "claude-sonnet-4-20250514",
|
|
@@ -417,12 +417,15 @@ function formatNotes(notes, format) {
|
|
|
417
417
|
const fn = formatters.get(format) || formatters.get("markdown");
|
|
418
418
|
return fn(notes);
|
|
419
419
|
}
|
|
420
|
+
function escapeMarkdown(text) {
|
|
421
|
+
return escapeHtml(text).replace(/\r?\n/g, " ");
|
|
422
|
+
}
|
|
420
423
|
function formatMarkdown(notes) {
|
|
421
424
|
const lines = [];
|
|
422
|
-
lines.push(`## ${notes.version} \u2014 ${notes.date}`);
|
|
425
|
+
lines.push(`## ${escapeMarkdown(notes.version)} \u2014 ${escapeMarkdown(notes.date)}`);
|
|
423
426
|
lines.push("");
|
|
424
427
|
if (notes.summary) {
|
|
425
|
-
lines.push(notes.summary);
|
|
428
|
+
lines.push(escapeMarkdown(notes.summary));
|
|
426
429
|
lines.push("");
|
|
427
430
|
}
|
|
428
431
|
const grouped = groupByCategory(notes);
|
|
@@ -432,8 +435,8 @@ function formatMarkdown(notes) {
|
|
|
432
435
|
lines.push(`### ${CATEGORY_LABELS[category]}`);
|
|
433
436
|
lines.push("");
|
|
434
437
|
for (const entry of entries) {
|
|
435
|
-
let line = `- ${entry.description}`;
|
|
436
|
-
if (entry.ticketKey) line += ` (${entry.ticketKey})`;
|
|
438
|
+
let line = `- ${escapeMarkdown(entry.description)}`;
|
|
439
|
+
if (entry.ticketKey) line += ` (${escapeMarkdown(entry.ticketKey)})`;
|
|
437
440
|
lines.push(line);
|
|
438
441
|
}
|
|
439
442
|
lines.push("");
|
|
@@ -441,7 +444,7 @@ function formatMarkdown(notes) {
|
|
|
441
444
|
if (notes.contributors?.length) {
|
|
442
445
|
lines.push("### Contributors");
|
|
443
446
|
lines.push("");
|
|
444
|
-
lines.push(notes.contributors.map((c) => `@${c}`).join(", "));
|
|
447
|
+
lines.push(notes.contributors.map((c) => `@${escapeMarkdown(c)}`).join(", "));
|
|
445
448
|
lines.push("");
|
|
446
449
|
}
|
|
447
450
|
if (notes.metadata) {
|
|
@@ -713,6 +716,7 @@ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT) {
|
|
|
713
716
|
// src/gate.ts
|
|
714
717
|
var FREE_PROVIDERS = /* @__PURE__ */ new Set(["none"]);
|
|
715
718
|
var FREE_PUBLISHERS = /* @__PURE__ */ new Set(["stdout", "file"]);
|
|
719
|
+
var TEAM_ONLY_PUBLISHERS = /* @__PURE__ */ new Set(["confluence", "notion", "teams"]);
|
|
716
720
|
var LICENSE_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
717
721
|
var LICENSE_FAILURE_CACHE_TTL = 5 * 60 * 1e3;
|
|
718
722
|
var cachedValidation = null;
|
|
@@ -750,7 +754,7 @@ async function validateLicense() {
|
|
|
750
754
|
if (res.ok) {
|
|
751
755
|
const data = await res.json();
|
|
752
756
|
const status2 = {
|
|
753
|
-
tier: data.tier === "pro" ? "pro" : "free",
|
|
757
|
+
tier: data.tier === "team" || data.tier === "enterprise" ? data.tier : data.tier === "pro" ? "pro" : "free",
|
|
754
758
|
valid: data.valid !== false,
|
|
755
759
|
message: data.message
|
|
756
760
|
};
|
|
@@ -772,15 +776,18 @@ async function validateLicense() {
|
|
|
772
776
|
}
|
|
773
777
|
}
|
|
774
778
|
function isProviderAllowed(provider, license) {
|
|
775
|
-
if (license.tier
|
|
779
|
+
if (license.tier !== "free" && license.valid) return true;
|
|
776
780
|
return FREE_PROVIDERS.has(provider);
|
|
777
781
|
}
|
|
778
782
|
function isPublisherAllowed(publisherType, license) {
|
|
779
|
-
if (
|
|
783
|
+
if (TEAM_ONLY_PUBLISHERS.has(publisherType)) {
|
|
784
|
+
return (license.tier === "team" || license.tier === "enterprise") && license.valid;
|
|
785
|
+
}
|
|
786
|
+
if (license.tier !== "free" && license.valid) return true;
|
|
780
787
|
return FREE_PUBLISHERS.has(publisherType);
|
|
781
788
|
}
|
|
782
789
|
function isEnrichmentAllowed(license) {
|
|
783
|
-
return license.tier
|
|
790
|
+
return license.tier !== "free" && license.valid;
|
|
784
791
|
}
|
|
785
792
|
function upgradeMessage(feature) {
|
|
786
793
|
return `\u{1F512} ${feature} requires a Cullit Pro license.
|
|
@@ -788,14 +795,37 @@ function upgradeMessage(feature) {
|
|
|
788
795
|
Then set CULLIT_API_KEY in your environment.`;
|
|
789
796
|
}
|
|
790
797
|
var TIER_LIMITS = {
|
|
791
|
-
free: { generationsPerMonth:
|
|
792
|
-
pro: { generationsPerMonth: 500, maxProjects:
|
|
793
|
-
team: { generationsPerMonth: 2e3, maxProjects:
|
|
798
|
+
free: { generationsPerMonth: 5, maxProjects: 3 },
|
|
799
|
+
pro: { generationsPerMonth: 500, maxProjects: 100 },
|
|
800
|
+
team: { generationsPerMonth: 2e3, maxProjects: 250 },
|
|
794
801
|
enterprise: { generationsPerMonth: Infinity, maxProjects: Infinity }
|
|
795
802
|
};
|
|
796
803
|
function getTierLimits(tier) {
|
|
797
804
|
return TIER_LIMITS[tier] || TIER_LIMITS.free;
|
|
798
805
|
}
|
|
806
|
+
var FEATURE_TIERS = {
|
|
807
|
+
drafts: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
808
|
+
approvals: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
809
|
+
shared_history: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
810
|
+
project_templates: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
811
|
+
hosted_changelog: /* @__PURE__ */ new Set(["pro", "team", "enterprise"]),
|
|
812
|
+
branded_widget: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
813
|
+
team_publishers: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
814
|
+
org_settings: /* @__PURE__ */ new Set(["team", "enterprise"]),
|
|
815
|
+
audit_logs: /* @__PURE__ */ new Set(["enterprise"]),
|
|
816
|
+
sso: /* @__PURE__ */ new Set(["enterprise"])
|
|
817
|
+
};
|
|
818
|
+
function isFeatureAllowed(feature, tier) {
|
|
819
|
+
const allowed = FEATURE_TIERS[feature];
|
|
820
|
+
return allowed ? allowed.has(tier) : false;
|
|
821
|
+
}
|
|
822
|
+
function getFeatureGating(tier) {
|
|
823
|
+
const result = {};
|
|
824
|
+
for (const feature of Object.keys(FEATURE_TIERS)) {
|
|
825
|
+
result[feature] = isFeatureAllowed(feature, tier);
|
|
826
|
+
}
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
799
829
|
async function reportUsage(project = "default") {
|
|
800
830
|
const key = process.env.CULLIT_API_KEY?.trim();
|
|
801
831
|
const meterUrl = process.env.CULLIT_METER_URL?.trim();
|
|
@@ -880,9 +910,70 @@ registerCollector("multi-repo", (config) => {
|
|
|
880
910
|
registerGenerator("none", () => new TemplateGenerator());
|
|
881
911
|
registerPublisher("stdout", (_target) => new StdoutPublisher());
|
|
882
912
|
registerPublisher("file", (target) => new FilePublisher(target.path));
|
|
913
|
+
function normalizeSectionOrder(value) {
|
|
914
|
+
if (!Array.isArray(value)) return void 0;
|
|
915
|
+
const order = value.filter((v) => typeof v === "string").map((v) => v.trim()).filter(Boolean);
|
|
916
|
+
return order.length ? order : void 0;
|
|
917
|
+
}
|
|
918
|
+
function toResolvedTemplate(profile) {
|
|
919
|
+
if (!profile) return {};
|
|
920
|
+
const p = profile;
|
|
921
|
+
return {
|
|
922
|
+
format: typeof p.format === "string" ? p.format : void 0,
|
|
923
|
+
sectionOrder: normalizeSectionOrder(p.sectionOrder),
|
|
924
|
+
includeContributors: typeof p.includeContributors === "boolean" ? p.includeContributors : void 0,
|
|
925
|
+
includeMetadata: typeof p.includeMetadata === "boolean" ? p.includeMetadata : void 0,
|
|
926
|
+
summaryPrefix: typeof p.summaryPrefix === "string" ? p.summaryPrefix : void 0
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
function mergeTemplates(...templates) {
|
|
930
|
+
const merged = {};
|
|
931
|
+
for (const template of templates) {
|
|
932
|
+
if (!template) continue;
|
|
933
|
+
if (template.name) merged.name = template.name;
|
|
934
|
+
if (template.format) merged.format = template.format;
|
|
935
|
+
if (template.sectionOrder) merged.sectionOrder = template.sectionOrder;
|
|
936
|
+
if (typeof template.includeContributors === "boolean") merged.includeContributors = template.includeContributors;
|
|
937
|
+
if (typeof template.includeMetadata === "boolean") merged.includeMetadata = template.includeMetadata;
|
|
938
|
+
if (typeof template.summaryPrefix === "string") merged.summaryPrefix = template.summaryPrefix;
|
|
939
|
+
}
|
|
940
|
+
return merged;
|
|
941
|
+
}
|
|
942
|
+
function getTemplateProfileByName(config, name) {
|
|
943
|
+
if (!name) return void 0;
|
|
944
|
+
const profile = config.templates?.find((t) => t.name === name);
|
|
945
|
+
if (!profile) return void 0;
|
|
946
|
+
return { name, ...toResolvedTemplate(profile) };
|
|
947
|
+
}
|
|
948
|
+
function applyTemplateToNotes(notes, template) {
|
|
949
|
+
const next = {
|
|
950
|
+
...notes,
|
|
951
|
+
changes: [...notes.changes]
|
|
952
|
+
};
|
|
953
|
+
if (template.sectionOrder?.length) {
|
|
954
|
+
const index = /* @__PURE__ */ new Map();
|
|
955
|
+
template.sectionOrder.forEach((category, i) => index.set(category, i));
|
|
956
|
+
next.changes = next.changes.map((change, i) => ({ change, i })).sort((a, b) => {
|
|
957
|
+
const ai = index.has(a.change.category) ? index.get(a.change.category) : Number.MAX_SAFE_INTEGER;
|
|
958
|
+
const bi = index.has(b.change.category) ? index.get(b.change.category) : Number.MAX_SAFE_INTEGER;
|
|
959
|
+
if (ai !== bi) return ai - bi;
|
|
960
|
+
return a.i - b.i;
|
|
961
|
+
}).map(({ change }) => change);
|
|
962
|
+
}
|
|
963
|
+
if (template.summaryPrefix) {
|
|
964
|
+
const currentSummary = next.summary || "";
|
|
965
|
+
next.summary = `${template.summaryPrefix}${currentSummary ? ` ${currentSummary}` : ""}`.trim();
|
|
966
|
+
}
|
|
967
|
+
if (template.includeContributors === false) {
|
|
968
|
+
delete next.contributors;
|
|
969
|
+
}
|
|
970
|
+
if (template.includeMetadata === false) {
|
|
971
|
+
delete next.metadata;
|
|
972
|
+
}
|
|
973
|
+
return next;
|
|
974
|
+
}
|
|
883
975
|
async function runPipeline(from, to, config, options = {}) {
|
|
884
976
|
const startTime = Date.now();
|
|
885
|
-
const format = options.format || "markdown";
|
|
886
977
|
const log = options.logger || createLogger("normal");
|
|
887
978
|
const license = await validateLicense();
|
|
888
979
|
if (!license.valid) {
|
|
@@ -951,8 +1042,16 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
951
1042
|
}
|
|
952
1043
|
const notes = await generator.generate(context, config.ai);
|
|
953
1044
|
log.info(`\xBB Generated ${notes.changes.length} change entries`);
|
|
954
|
-
const
|
|
1045
|
+
const selectedTemplateName = options.templateProfile || config.template?.default;
|
|
1046
|
+
const baseTemplate = mergeTemplates(
|
|
1047
|
+
toResolvedTemplate(config.template),
|
|
1048
|
+
getTemplateProfileByName(config, selectedTemplateName)
|
|
1049
|
+
);
|
|
1050
|
+
const format = options.format || baseTemplate.format || "markdown";
|
|
1051
|
+
const templatedNotes = applyTemplateToNotes(notes, baseTemplate);
|
|
1052
|
+
const formatted = formatNotes(templatedNotes, format);
|
|
955
1053
|
const publishedTo = [];
|
|
1054
|
+
const renderedCache = /* @__PURE__ */ new Map();
|
|
956
1055
|
if (!options.dryRun) {
|
|
957
1056
|
for (const target of config.publish) {
|
|
958
1057
|
try {
|
|
@@ -966,7 +1065,36 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
966
1065
|
continue;
|
|
967
1066
|
}
|
|
968
1067
|
const publisher = publisherFactory(target);
|
|
969
|
-
|
|
1068
|
+
const targetTemplate = mergeTemplates(
|
|
1069
|
+
baseTemplate,
|
|
1070
|
+
getTemplateProfileByName(config, typeof target.templateProfile === "string" ? target.templateProfile : void 0),
|
|
1071
|
+
{
|
|
1072
|
+
format: typeof target.format === "string" ? target.format : void 0,
|
|
1073
|
+
sectionOrder: normalizeSectionOrder(target.sectionOrder)
|
|
1074
|
+
}
|
|
1075
|
+
);
|
|
1076
|
+
const targetFormat = targetTemplate.format || format;
|
|
1077
|
+
const cacheKey = JSON.stringify({
|
|
1078
|
+
f: targetFormat,
|
|
1079
|
+
o: targetTemplate.sectionOrder || null,
|
|
1080
|
+
c: targetTemplate.includeContributors,
|
|
1081
|
+
m: targetTemplate.includeMetadata,
|
|
1082
|
+
s: targetTemplate.summaryPrefix
|
|
1083
|
+
});
|
|
1084
|
+
let cached = renderedCache.get(cacheKey);
|
|
1085
|
+
if (!cached) {
|
|
1086
|
+
const targetNotes = applyTemplateToNotes(notes, targetTemplate);
|
|
1087
|
+
const targetOutput = cacheKey === JSON.stringify({
|
|
1088
|
+
f: format,
|
|
1089
|
+
o: baseTemplate.sectionOrder || null,
|
|
1090
|
+
c: baseTemplate.includeContributors,
|
|
1091
|
+
m: baseTemplate.includeMetadata,
|
|
1092
|
+
s: baseTemplate.summaryPrefix
|
|
1093
|
+
}) ? formatted : formatNotes(targetNotes, targetFormat);
|
|
1094
|
+
cached = { notes: targetNotes, output: targetOutput, format: targetFormat };
|
|
1095
|
+
renderedCache.set(cacheKey, cached);
|
|
1096
|
+
}
|
|
1097
|
+
await publisher.publish(cached.notes, cached.format, cached.output);
|
|
970
1098
|
publishedTo.push(target.type === "file" ? `file:${target.path}` : target.type);
|
|
971
1099
|
} catch (err) {
|
|
972
1100
|
log.error(`\u2717 Failed to publish to ${target.type}: ${err.message}`);
|
|
@@ -980,7 +1108,7 @@ async function runPipeline(from, to, config, options = {}) {
|
|
|
980
1108
|
const duration = Date.now() - startTime;
|
|
981
1109
|
log.info(`
|
|
982
1110
|
\u2713 Done in ${(duration / 1e3).toFixed(1)}s`);
|
|
983
|
-
return { notes, formatted, publishedTo, duration };
|
|
1111
|
+
return { notes: templatedNotes, formatted, publishedTo, duration };
|
|
984
1112
|
}
|
|
985
1113
|
export {
|
|
986
1114
|
AI_PROVIDERS,
|
|
@@ -1005,6 +1133,7 @@ export {
|
|
|
1005
1133
|
formatNotes,
|
|
1006
1134
|
getCollector,
|
|
1007
1135
|
getEnricher,
|
|
1136
|
+
getFeatureGating,
|
|
1008
1137
|
getFormatter,
|
|
1009
1138
|
getGenerator,
|
|
1010
1139
|
getLatestTag,
|
|
@@ -1016,6 +1145,7 @@ export {
|
|
|
1016
1145
|
hasGenerator,
|
|
1017
1146
|
hasPublisher,
|
|
1018
1147
|
isEnrichmentAllowed,
|
|
1148
|
+
isFeatureAllowed,
|
|
1019
1149
|
isProviderAllowed,
|
|
1020
1150
|
isPublisherAllowed,
|
|
1021
1151
|
listCollectors,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cullit/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core engine for Cullit — AI-powered release note generation.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"node": ">=18"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@cullit/config": "1.
|
|
34
|
+
"@cullit/config": "1.9.2"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsup src/index.ts --format esm --dts --clean",
|