Summary
When logsmith generates a changelog for an unreleased state (no version provided), the section headings (### π Bug Fixes, ### π§Ή Chores, ### Contributors, etc.) are emitted at H3 directly under the file's # Changelog H1 β skipping H2 entirely. This violates markdown/heading-increment and breaks lint in any consuming repo.
Repro
In any repo using logsmith, run:
bunx --bun logsmith --output CHANGELOG.md
When there are unreleased commits and no version tag, the generated file looks like:
# Changelog
[Compare changes](https://github.com/owner/repo/compare/v0.13.2...HEAD)
### π Bug Fixes
- ...
### π§Ή Chores
- ...
### Contributors
- ...
Then run any markdown linter (e.g. pickier with markdown/heading-increment: error):
CHANGELOG.md
4:1 error Heading level should not skip from h1 to h3 markdown/heading-increment
Expected
Every section header should be reachable by walking heading levels one step at a time. With no version (unreleased) the sections should sit at H2, not H3:
# Changelog
[Compare changes](...)
## π Bug Fixes
- ...
## π§Ή Chores
- ...
## Contributors
- ...
When a version is present, the existing structure is correct β the version goes at H2 and sections at H3:
# Changelog
## v0.13.3
[Compare changes](...)
### π Bug Fixes
- ...
Where it's coming from
packages/logsmith/src/utils.ts β generateChangelogContent() around lines 369β470:
if (changelog.version) {
lines.push(`## ${config.versionPrefix}${changelog.version}`) // H2
...
}
// ...later, unconditionally:
for (const section of changelog.sections) {
lines.push(`### ${section.title}`) // H3 β but no H2 above when version is empty
...
}
if (changelog.contributors.length > 0 && !config.excludeEmail) {
lines.push(`### ${getLabel('contributors', config.language)}`) // same issue
...
}
When changelog.version is falsy, the H2 line is skipped, but the H3 sections still emit. The outer wrapper in packages/logsmith/src/changelog.ts (line ~148) then prepends # Changelog as H1 β producing the H1βH3 jump.
Real-world impact
This breaks CI lint across our 95 repos that use logsmith + pickier. We've been demoting H3βH2 manually in each affected CHANGELOG.md, but those edits don't survive the next bunx logsmith run.
Suggested fix
In generateChangelogContent, derive the section level from whether a version header was emitted:
const sectionLevel = changelog.version ? '###' : '##'
for (const section of changelog.sections) {
lines.push(`${sectionLevel} ${section.title}`)
...
}
// same for contributors:
lines.push(`${sectionLevel} ${getLabel('contributors', config.language)}`)
Alternatively, always emit an H2 anchor β e.g. ## Unreleased when no version β but the dynamic-level approach is less intrusive to existing CHANGELOG layouts.
Related observation
Older entries in some long-lived CHANGELOGs (generated by an earlier logsmith) used H2 for sections (## π§Ή Chores). The recent regression is when this changed to H3-without-an-H2-parent for the unreleased block.
Version
logsmith β installed via bunx logsmith (latest at time of report)
Summary
When logsmith generates a changelog for an unreleased state (no
versionprovided), the section headings (### π Bug Fixes,### π§Ή Chores,### Contributors, etc.) are emitted at H3 directly under the file's# ChangelogH1 β skipping H2 entirely. This violatesmarkdown/heading-incrementand breaks lint in any consuming repo.Repro
In any repo using logsmith, run:
When there are unreleased commits and no version tag, the generated file looks like:
Then run any markdown linter (e.g. pickier with
markdown/heading-increment: error):Expected
Every section header should be reachable by walking heading levels one step at a time. With no version (unreleased) the sections should sit at H2, not H3:
When a version is present, the existing structure is correct β the version goes at H2 and sections at H3:
Where it's coming from
packages/logsmith/src/utils.tsβgenerateChangelogContent()around lines 369β470:When
changelog.versionis falsy, the H2 line is skipped, but the H3 sections still emit. The outer wrapper inpackages/logsmith/src/changelog.ts(line ~148) then prepends# Changelogas H1 β producing the H1βH3 jump.Real-world impact
This breaks CI lint across our 95 repos that use logsmith + pickier. We've been demoting H3βH2 manually in each affected
CHANGELOG.md, but those edits don't survive the nextbunx logsmithrun.Suggested fix
In
generateChangelogContent, derive the section level from whether a version header was emitted:Alternatively, always emit an H2 anchor β e.g.
## Unreleasedwhen no version β but the dynamic-level approach is less intrusive to existing CHANGELOG layouts.Related observation
Older entries in some long-lived CHANGELOGs (generated by an earlier logsmith) used H2 for sections (
## π§Ή Chores). The recent regression is when this changed to H3-without-an-H2-parent for the unreleased block.Version
logsmith β installed via
bunx logsmith(latest at time of report)