@hyperfrontend/versioning 0.2.0 → 0.3.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 (70) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +8 -6
  3. package/changelog/index.cjs.js +15 -4
  4. package/changelog/index.cjs.js.map +1 -1
  5. package/changelog/index.esm.js +15 -4
  6. package/changelog/index.esm.js.map +1 -1
  7. package/changelog/parse/index.cjs.js +62 -4
  8. package/changelog/parse/index.cjs.js.map +1 -1
  9. package/changelog/parse/index.esm.js +62 -4
  10. package/changelog/parse/index.esm.js.map +1 -1
  11. package/changelog/parse/parser.d.ts +0 -6
  12. package/changelog/parse/parser.d.ts.map +1 -1
  13. package/commits/classify/index.cjs.js +8 -6
  14. package/commits/classify/index.cjs.js.map +1 -1
  15. package/commits/classify/index.d.ts +1 -1
  16. package/commits/classify/index.d.ts.map +1 -1
  17. package/commits/classify/index.esm.js +8 -7
  18. package/commits/classify/index.esm.js.map +1 -1
  19. package/commits/classify/project-scopes.d.ts +10 -0
  20. package/commits/classify/project-scopes.d.ts.map +1 -1
  21. package/commits/index.cjs.js +8 -6
  22. package/commits/index.cjs.js.map +1 -1
  23. package/commits/index.esm.js +8 -7
  24. package/commits/index.esm.js.map +1 -1
  25. package/flow/executor/index.cjs.js +12 -0
  26. package/flow/executor/index.cjs.js.map +1 -1
  27. package/flow/executor/index.esm.js +12 -0
  28. package/flow/executor/index.esm.js.map +1 -1
  29. package/flow/index.cjs.js +89 -36
  30. package/flow/index.cjs.js.map +1 -1
  31. package/flow/index.esm.js +88 -37
  32. package/flow/index.esm.js.map +1 -1
  33. package/flow/models/index.cjs.js +13 -0
  34. package/flow/models/index.cjs.js.map +1 -1
  35. package/flow/models/index.d.ts +1 -1
  36. package/flow/models/index.d.ts.map +1 -1
  37. package/flow/models/index.esm.js +13 -1
  38. package/flow/models/index.esm.js.map +1 -1
  39. package/flow/models/types.d.ts +33 -1
  40. package/flow/models/types.d.ts.map +1 -1
  41. package/flow/presets/index.cjs.js +84 -36
  42. package/flow/presets/index.cjs.js.map +1 -1
  43. package/flow/presets/index.esm.js +84 -36
  44. package/flow/presets/index.esm.js.map +1 -1
  45. package/flow/steps/analyze-commits.d.ts.map +1 -1
  46. package/flow/steps/generate-changelog.d.ts +5 -0
  47. package/flow/steps/generate-changelog.d.ts.map +1 -1
  48. package/flow/steps/index.cjs.js +85 -36
  49. package/flow/steps/index.cjs.js.map +1 -1
  50. package/flow/steps/index.d.ts +1 -1
  51. package/flow/steps/index.d.ts.map +1 -1
  52. package/flow/steps/index.esm.js +85 -37
  53. package/flow/steps/index.esm.js.map +1 -1
  54. package/index.cjs.js +9223 -9172
  55. package/index.cjs.js.map +1 -1
  56. package/index.d.ts +3 -1
  57. package/index.d.ts.map +1 -1
  58. package/index.esm.js +9220 -9173
  59. package/index.esm.js.map +1 -1
  60. package/package.json +14 -1
  61. package/workspace/discovery/changelog-path.d.ts +3 -7
  62. package/workspace/discovery/changelog-path.d.ts.map +1 -1
  63. package/workspace/discovery/index.cjs.js +84 -5
  64. package/workspace/discovery/index.cjs.js.map +1 -1
  65. package/workspace/discovery/index.esm.js +84 -5
  66. package/workspace/discovery/index.esm.js.map +1 -1
  67. package/workspace/index.cjs.js +84 -5
  68. package/workspace/index.cjs.js.map +1 -1
  69. package/workspace/index.esm.js +84 -5
  70. package/workspace/index.esm.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"analyze-commits.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/versioning/src/flow/steps/analyze-commits.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAkB9C,eAAO,MAAM,uBAAuB,oBAAoB,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,CAqJnD"}
1
+ {"version":3,"file":"analyze-commits.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/versioning/src/flow/steps/analyze-commits.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAkB9C,eAAO,MAAM,uBAAuB,oBAAoB,CAAA;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,CAwJnD"}
@@ -1,5 +1,10 @@
1
+ import type { ChangelogSectionType } from '../../changelog/models/section';
1
2
  import type { FlowStep } from '../models/step';
2
3
  export declare const GENERATE_CHANGELOG_STEP_ID = "generate-changelog";
4
+ /**
5
+ * Maps conventional commit types to changelog section types.
6
+ */
7
+ export declare const DEFAULT_COMMIT_TYPE_TO_SECTION: Record<string, ChangelogSectionType>;
3
8
  /**
4
9
  * Creates the generate-changelog step.
5
10
  *
@@ -1 +1 @@
1
- {"version":3,"file":"generate-changelog.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/versioning/src/flow/steps/generate-changelog.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAU9C,eAAO,MAAM,0BAA0B,uBAAuB,CAAA;AA6H9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,IAAI,QAAQ,CA+LtD;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,CA+FnD"}
1
+ {"version":3,"file":"generate-changelog.d.ts","sourceRoot":"","sources":["../../../../../../../../libs/versioning/src/flow/steps/generate-changelog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAA;AAG1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAW9C,eAAO,MAAM,0BAA0B,uBAAuB,CAAA;AAE9D;;GAEG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAY/E,CAAA;AA2ID;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,IAAI,QAAQ,CAkMtD;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,QAAQ,CAgGnD"}
@@ -2312,12 +2312,12 @@ function shouldPreserveScope(source) {
2312
2312
  * // Returns: ['app-demo', 'demo']
2313
2313
  */
2314
2314
  function deriveProjectScopes(options) {
2315
- const { projectName, packageName, additionalScopes = [] } = options;
2315
+ const { projectName, packageName, additionalScopes = [], prefixes = DEFAULT_PROJECT_PREFIXES } = options;
2316
2316
  const scopes = createSet();
2317
2317
  // Always include the full project name
2318
2318
  scopes.add(projectName);
2319
2319
  // Add variations based on common prefixes
2320
- const prefixVariations = extractPrefixVariations(projectName);
2320
+ const prefixVariations = extractPrefixVariations(projectName, prefixes);
2321
2321
  for (const variation of prefixVariations) {
2322
2322
  scopes.add(variation);
2323
2323
  }
@@ -2337,18 +2337,19 @@ function deriveProjectScopes(options) {
2337
2337
  return [...scopes];
2338
2338
  }
2339
2339
  /**
2340
- * Recognized project name prefixes that can be stripped for scope matching.
2340
+ * Default project name prefixes that can be stripped for scope matching.
2341
2341
  */
2342
- const PROJECT_PREFIXES = ['lib-', 'app-', 'e2e-', 'tool-', 'plugin-', 'feature-', 'package-'];
2342
+ const DEFAULT_PROJECT_PREFIXES = ['lib-', 'app-', 'e2e-', 'tool-', 'plugin-', 'feature-', 'package-'];
2343
2343
  /**
2344
2344
  * Generates scope variations by stripping recognized project prefixes.
2345
2345
  *
2346
2346
  * @param projectName - The project name to extract variations from
2347
+ * @param prefixes - Prefixes to check and strip
2347
2348
  * @returns Array of scope name variations
2348
2349
  */
2349
- function extractPrefixVariations(projectName) {
2350
+ function extractPrefixVariations(projectName, prefixes) {
2350
2351
  const variations = [];
2351
- for (const prefix of PROJECT_PREFIXES) {
2352
+ for (const prefix of prefixes) {
2352
2353
  if (projectName.startsWith(prefix)) {
2353
2354
  const withoutPrefix = projectName.slice(prefix.length);
2354
2355
  if (withoutPrefix) {
@@ -3192,6 +3193,10 @@ function splitLines(message) {
3192
3193
  return lines;
3193
3194
  }
3194
3195
 
3196
+ /**
3197
+ * Default changelog filename.
3198
+ */
3199
+ const DEFAULT_CHANGELOG_FILENAME = 'CHANGELOG.md';
3195
3200
  /**
3196
3201
  * Default scope filtering configuration.
3197
3202
  *
@@ -3203,6 +3208,7 @@ const DEFAULT_SCOPE_FILTERING_CONFIG = {
3203
3208
  includeScopes: [],
3204
3209
  excludeScopes: DEFAULT_EXCLUDE_SCOPES,
3205
3210
  trackDependencyChanges: false,
3211
+ projectPrefixes: DEFAULT_PROJECT_PREFIXES,
3206
3212
  infrastructure: undefined,
3207
3213
  infrastructureMatcher: undefined,
3208
3214
  };
@@ -3229,6 +3235,7 @@ const ANALYZE_COMMITS_STEP_ID = 'analyze-commits';
3229
3235
  function createAnalyzeCommitsStep() {
3230
3236
  return createStep(ANALYZE_COMMITS_STEP_ID, 'Analyze Commits', async (ctx) => {
3231
3237
  const { git, projectName, projectRoot, packageName, workspaceRoot, config, logger, state } = ctx;
3238
+ const maxFallback = config.maxCommitFallback ?? 500;
3232
3239
  // Use publishedCommit from registry (set by fetch-registry step)
3233
3240
  const { publishedCommit, isFirstRelease } = state;
3234
3241
  let rawCommits;
@@ -3245,13 +3252,13 @@ function createAnalyzeCommitsStep() {
3245
3252
  logger.warn(`Published commit ${publishedCommit.slice(0, 7)} not found in history. ` +
3246
3253
  `This may indicate a rebase or force push occurred after publishing v${state.publishedVersion}. ` +
3247
3254
  `Falling back to recent commit analysis.`);
3248
- rawCommits = git.getCommitLog({ maxCount: 100 });
3255
+ rawCommits = git.getCommitLog({ maxCount: maxFallback });
3249
3256
  // effectiveBaseCommit stays null - no compare URL will be generated
3250
3257
  }
3251
3258
  }
3252
3259
  else {
3253
3260
  // First release or no published version
3254
- rawCommits = git.getCommitLog({ maxCount: 100 });
3261
+ rawCommits = git.getCommitLog({ maxCount: maxFallback });
3255
3262
  logger.debug(`First release - analyzing up to ${rawCommits.length} commits`);
3256
3263
  }
3257
3264
  // Get scope filtering configuration
@@ -3293,7 +3300,7 @@ function createAnalyzeCommitsStep() {
3293
3300
  const relativePath = getRelativePath(workspaceRoot, projectRoot);
3294
3301
  const pathFilteredCommits = effectiveBaseCommit
3295
3302
  ? git.getCommitsSince(effectiveBaseCommit, { path: relativePath })
3296
- : git.getCommitLog({ maxCount: 100, path: relativePath });
3303
+ : git.getCommitLog({ maxCount: maxFallback, path: relativePath });
3297
3304
  fileCommitHashes = createSet(pathFilteredCommits.map((c) => c.hash));
3298
3305
  logger.debug(`Found ${fileCommitHashes.size} commits touching ${relativePath}`);
3299
3306
  }
@@ -3302,14 +3309,15 @@ function createAnalyzeCommitsStep() {
3302
3309
  projectName,
3303
3310
  packageName,
3304
3311
  additionalScopes: scopeFilteringConfig.includeScopes,
3312
+ prefixes: scopeFilteringConfig.projectPrefixes,
3305
3313
  });
3306
3314
  logger.debug(`Project scopes: ${projectScopes.join(', ')}`);
3307
3315
  // Build infrastructure commit hashes for file-based infrastructure detection
3308
- const infrastructureCommitHashes = buildInfrastructureCommitHashes(git, effectiveBaseCommit, rawCommits, parsedCommits, scopeFilteringConfig, logger);
3316
+ const infrastructureCommitHashes = buildInfrastructureCommitHashes(git, effectiveBaseCommit, rawCommits, parsedCommits, scopeFilteringConfig, logger, maxFallback);
3309
3317
  // Build dependency commit map if tracking is enabled (Phase 4)
3310
3318
  let dependencyCommitMap;
3311
3319
  if (scopeFilteringConfig.trackDependencyChanges) {
3312
- dependencyCommitMap = buildDependencyCommitMap(git, workspaceRoot, projectName, effectiveBaseCommit, logger);
3320
+ dependencyCommitMap = buildDependencyCommitMap(git, workspaceRoot, projectName, effectiveBaseCommit, logger, maxFallback);
3313
3321
  }
3314
3322
  // Create classification context
3315
3323
  const classificationContext = createClassificationContext(projectScopes, fileCommitHashes, {
@@ -3442,9 +3450,10 @@ function buildSummaryMessage(includedCount, totalCount, summary, strategy) {
3442
3450
  * @param config - Scope filtering configuration
3443
3451
  * @param logger - Logger with debug method for output
3444
3452
  * @param logger.debug - Debug logging function
3453
+ * @param maxFallback - Maximum commits to query when baseCommit is null
3445
3454
  * @returns Set of commit hashes classified as infrastructure
3446
3455
  */
3447
- function buildInfrastructureCommitHashes(git, baseCommit, rawCommits, parsedCommits, config, logger) {
3456
+ function buildInfrastructureCommitHashes(git, baseCommit, rawCommits, parsedCommits, config, logger, maxFallback) {
3448
3457
  // Collect all infrastructure commit hashes
3449
3458
  let infraHashes = createSet();
3450
3459
  // Method 1: Path-based detection (query git for commits touching infra paths)
@@ -3453,7 +3462,7 @@ function buildInfrastructureCommitHashes(git, baseCommit, rawCommits, parsedComm
3453
3462
  for (const infraPath of infraPaths) {
3454
3463
  const pathCommits = baseCommit
3455
3464
  ? git.getCommitsSince(baseCommit, { path: infraPath })
3456
- : git.getCommitLog({ maxCount: 100, path: infraPath });
3465
+ : git.getCommitLog({ maxCount: maxFallback, path: infraPath });
3457
3466
  for (const commit of pathCommits) {
3458
3467
  infraHashes = infraHashes.add(commit.hash);
3459
3468
  }
@@ -3521,9 +3530,10 @@ function combineMatcher(a, b) {
3521
3530
  * @param baseCommit - Base commit hash for commit range (null for first release/fallback)
3522
3531
  * @param logger - Logger with debug method for output
3523
3532
  * @param logger.debug - Debug logging function
3533
+ * @param maxFallback - Maximum commits to query when baseCommit is null
3524
3534
  * @returns Map of dependency names to commit hashes touching that dependency
3525
3535
  */
3526
- function buildDependencyCommitMap(git, workspaceRoot, projectName, baseCommit, logger) {
3536
+ function buildDependencyCommitMap(git, workspaceRoot, projectName, baseCommit, logger, maxFallback) {
3527
3537
  let dependencyMap = createMap();
3528
3538
  try {
3529
3539
  // Discover all projects in workspace using lib-project-scope
@@ -3548,7 +3558,7 @@ function buildDependencyCommitMap(git, workspaceRoot, projectName, baseCommit, l
3548
3558
  // Query git for commits touching this dependency's path
3549
3559
  const depCommits = baseCommit
3550
3560
  ? git.getCommitsSince(baseCommit, { path: depRoot })
3551
- : git.getCommitLog({ maxCount: 100, path: depRoot });
3561
+ : git.getCommitLog({ maxCount: maxFallback, path: depRoot });
3552
3562
  if (depCommits.length > 0) {
3553
3563
  const hashSet = createSet(depCommits.map((c) => c.hash));
3554
3564
  dependencyMap = dependencyMap.set(dep.target, hashSet);
@@ -5215,11 +5225,22 @@ function isWhitespace(char) {
5215
5225
  }
5216
5226
 
5217
5227
  /**
5218
- * Changelog Parser
5228
+ * Validates that a URL is actually a GitHub URL by parsing it properly.
5229
+ * This prevents SSRF attacks where 'github.com' could appear in path/query.
5219
5230
  *
5220
- * Parses a changelog markdown string into a structured Changelog object.
5221
- * Uses a state machine tokenizer for ReDoS-safe parsing.
5231
+ * @param url - The URL string to validate
5232
+ * @returns True if the URL host is github.com or a subdomain
5222
5233
  */
5234
+ function isGitHubUrl(url) {
5235
+ try {
5236
+ const parsed = createURL(url);
5237
+ // Check that the host is exactly github.com or ends with .github.com
5238
+ return parsed.host === 'github.com' || parsed.host.endsWith('.github.com');
5239
+ }
5240
+ catch {
5241
+ return false;
5242
+ }
5243
+ }
5223
5244
  /**
5224
5245
  * Parses a changelog markdown string into a Changelog object.
5225
5246
  *
@@ -5287,7 +5308,7 @@ function parseHeader(state) {
5287
5308
  description.push(`[${token.value}](${nextToken.value})`);
5288
5309
  links.push({ label: token.value, url: nextToken.value });
5289
5310
  // Try to detect repository URL
5290
- if (!state.repositoryUrl && nextToken.value.includes('github.com')) {
5311
+ if (!state.repositoryUrl && isGitHubUrl(nextToken.value)) {
5291
5312
  state.repositoryUrl = extractRepoUrl(nextToken.value);
5292
5313
  }
5293
5314
  advance(state); // skip link-text
@@ -6089,7 +6110,7 @@ const GENERATE_CHANGELOG_STEP_ID = 'generate-changelog';
6089
6110
  /**
6090
6111
  * Maps conventional commit types to changelog section types.
6091
6112
  */
6092
- const COMMIT_TYPE_TO_SECTION = {
6113
+ const DEFAULT_COMMIT_TYPE_TO_SECTION = {
6093
6114
  feat: 'features',
6094
6115
  fix: 'fixes',
6095
6116
  perf: 'performance',
@@ -6102,6 +6123,18 @@ const COMMIT_TYPE_TO_SECTION = {
6102
6123
  chore: 'chores',
6103
6124
  style: 'other',
6104
6125
  };
6126
+ /**
6127
+ * Resolves the commit type to section mapping by merging config with defaults.
6128
+ *
6129
+ * @param configMapping - User-provided partial mapping from FlowConfig
6130
+ * @returns Resolved mapping with user overrides applied
6131
+ */
6132
+ function resolveCommitTypeMapping(configMapping) {
6133
+ if (!configMapping) {
6134
+ return DEFAULT_COMMIT_TYPE_TO_SECTION;
6135
+ }
6136
+ return { ...DEFAULT_COMMIT_TYPE_TO_SECTION, ...configMapping };
6137
+ }
6105
6138
  /**
6106
6139
  * Checks if a commit source represents an indirect change.
6107
6140
  *
@@ -6115,16 +6148,22 @@ function isIndirectSource(source) {
6115
6148
  * Groups classified commits by their section type.
6116
6149
  *
6117
6150
  * @param commits - Array of classified commits
6151
+ * @param mapping - Commit type to section mapping
6118
6152
  * @returns Record of section type to classified commits
6119
6153
  */
6120
- function groupClassifiedCommitsBySection(commits) {
6154
+ function groupClassifiedCommitsBySection(commits, mapping) {
6121
6155
  const groups = {};
6122
6156
  for (const classified of commits) {
6123
- const sectionType = COMMIT_TYPE_TO_SECTION[classified.commit.type ?? 'chore'] ?? 'chores';
6124
- if (!groups[sectionType]) {
6125
- groups[sectionType] = [];
6157
+ const sectionType = mapping[classified.commit.type ?? 'chore'];
6158
+ // Skip if explicitly excluded (null)
6159
+ if (sectionType === null)
6160
+ continue;
6161
+ // Fallback to 'chores' for unmapped types
6162
+ const resolvedSection = sectionType ?? 'chores';
6163
+ if (!groups[resolvedSection]) {
6164
+ groups[resolvedSection] = [];
6126
6165
  }
6127
- groups[sectionType].push(classified);
6166
+ groups[resolvedSection].push(classified);
6128
6167
  }
6129
6168
  return groups;
6130
6169
  }
@@ -6132,16 +6171,22 @@ function groupClassifiedCommitsBySection(commits) {
6132
6171
  * Groups commits by their section type.
6133
6172
  *
6134
6173
  * @param commits - Array of conventional commits
6174
+ * @param mapping - Commit type to section mapping
6135
6175
  * @returns Record of section type to commits
6136
6176
  */
6137
- function groupCommitsBySection(commits) {
6177
+ function groupCommitsBySection(commits, mapping) {
6138
6178
  const groups = {};
6139
6179
  for (const commit of commits) {
6140
- const sectionType = COMMIT_TYPE_TO_SECTION[commit.type ?? 'chore'] ?? 'chores';
6141
- if (!groups[sectionType]) {
6142
- groups[sectionType] = [];
6180
+ const sectionType = mapping[commit.type ?? 'chore'];
6181
+ // Skip if explicitly excluded (null)
6182
+ if (sectionType === null)
6183
+ continue;
6184
+ // Fallback to 'chores' for unmapped types
6185
+ const resolvedSection = sectionType ?? 'chores';
6186
+ if (!groups[resolvedSection]) {
6187
+ groups[resolvedSection] = [];
6143
6188
  }
6144
- groups[sectionType].push(commit);
6189
+ groups[resolvedSection].push(commit);
6145
6190
  }
6146
6191
  return groups;
6147
6192
  }
@@ -6209,6 +6254,8 @@ function createGenerateChangelogStep() {
6209
6254
  return createStep(GENERATE_CHANGELOG_STEP_ID, 'Generate Changelog Entry', async (ctx) => {
6210
6255
  const { config, state } = ctx;
6211
6256
  const { commits, nextVersion, bumpType } = state;
6257
+ // Resolve commit type to section mapping
6258
+ const commitTypeMapping = resolveCommitTypeMapping(config.commitTypeToSection);
6212
6259
  // Skip if no bump needed
6213
6260
  if (!nextVersion || bumpType === 'none') {
6214
6261
  return createSkippedResult('No version bump, skipping changelog generation');
@@ -6270,7 +6317,7 @@ function createGenerateChangelogStep() {
6270
6317
  })));
6271
6318
  }
6272
6319
  // Group direct commits by section
6273
- const groupedDirect = groupClassifiedCommitsBySection(directCommits);
6320
+ const groupedDirect = groupClassifiedCommitsBySection(directCommits, commitTypeMapping);
6274
6321
  // Add other sections in conventional order (direct commits only)
6275
6322
  const sectionOrder = [
6276
6323
  { type: 'features', heading: 'Features' },
@@ -6298,7 +6345,7 @@ function createGenerateChangelogStep() {
6298
6345
  }
6299
6346
  else {
6300
6347
  // Fallback: use commits without classification (backward compatibility)
6301
- const grouped = groupCommitsBySection(commits);
6348
+ const grouped = groupCommitsBySection(commits, commitTypeMapping);
6302
6349
  // Add breaking changes section first if any
6303
6350
  const breakingCommits = commits.filter((c) => c.breaking);
6304
6351
  if (breakingCommits.length > 0) {
@@ -6374,14 +6421,15 @@ function createWriteChangelogStep() {
6374
6421
  if (!nextVersion || bumpType === 'none' || !changelogEntry || config.skipChangelog) {
6375
6422
  return createSkippedResult('No changelog to write');
6376
6423
  }
6377
- const changelogPath = `${projectRoot}/CHANGELOG.md`;
6424
+ const changelogFileName = config.changelogFileName ?? DEFAULT_CHANGELOG_FILENAME;
6425
+ const changelogPath = `${projectRoot}/${changelogFileName}`;
6378
6426
  let existingContent = '';
6379
6427
  // Read existing changelog
6380
6428
  try {
6381
6429
  existingContent = tree.read(changelogPath, 'utf-8') ?? '';
6382
6430
  }
6383
6431
  catch {
6384
- logger.debug('No existing CHANGELOG.md found');
6432
+ logger.debug(`No existing ${changelogFileName} found`);
6385
6433
  }
6386
6434
  // If no existing content, create new changelog
6387
6435
  if (!existingContent.trim()) {
@@ -6399,7 +6447,7 @@ function createWriteChangelogStep() {
6399
6447
  stateUpdates: {
6400
6448
  modifiedFiles: [...(state.modifiedFiles ?? []), changelogPath],
6401
6449
  },
6402
- message: `Created CHANGELOG.md with version ${nextVersion}`,
6450
+ message: `Created ${changelogFileName} with version ${nextVersion}`,
6403
6451
  };
6404
6452
  }
6405
6453
  // Parse existing and add entry
@@ -6433,7 +6481,7 @@ function createWriteChangelogStep() {
6433
6481
  stateUpdates: {
6434
6482
  modifiedFiles: [...(state.modifiedFiles ?? []), changelogPath],
6435
6483
  },
6436
- message: `Updated CHANGELOG.md with version ${nextVersion}`,
6484
+ message: `Updated ${changelogFileName} with version ${nextVersion}`,
6437
6485
  };
6438
6486
  }, {
6439
6487
  dependsOn: ['generate-changelog'],
@@ -6790,6 +6838,7 @@ exports.ANALYZE_COMMITS_STEP_ID = ANALYZE_COMMITS_STEP_ID;
6790
6838
  exports.CALCULATE_BUMP_STEP_ID = CALCULATE_BUMP_STEP_ID;
6791
6839
  exports.CREATE_COMMIT_STEP_ID = CREATE_COMMIT_STEP_ID;
6792
6840
  exports.CREATE_TAG_STEP_ID = CREATE_TAG_STEP_ID;
6841
+ exports.DEFAULT_COMMIT_TYPE_TO_SECTION = DEFAULT_COMMIT_TYPE_TO_SECTION;
6793
6842
  exports.FETCH_REGISTRY_STEP_ID = FETCH_REGISTRY_STEP_ID;
6794
6843
  exports.GENERATE_CHANGELOG_STEP_ID = GENERATE_CHANGELOG_STEP_ID;
6795
6844
  exports.RESOLVE_REPOSITORY_STEP_ID = RESOLVE_REPOSITORY_STEP_ID;