fix: trim release notes to recent versions

This commit is contained in:
paoloanzn committed 2026-03-31 15:52:53 +02:00
1 parent 71bf5f24a0
commit 4d728a1b19
4 files changed
+80 -56

No files matched your search

+19 -9
View File
@@ -3,8 +3,10 @@ import {
CHANGELOG_URL,
fetchAndStoreChangelog,
getAllReleaseNotes,
getRecentReleaseNoteGroups,
getStoredChangelog,
} from '../../utils/releaseNotes.js'
import { getGlobalConfig } from '../../utils/config.js'
function formatReleaseNotes(notes: Array<[string, string[]]>): string {
return notes
@@ -18,7 +20,7 @@ function formatReleaseNotes(notes: Array<[string, string[]]>): string {
export async function call(): Promise<LocalCommandResult> {
// Try to fetch the latest changelog with a 500ms timeout
let freshNotes: Array<[string, string[]]> = []
let changelog = ''
try {
const timeoutPromise = new Promise<void>((_, reject) => {
@@ -26,20 +28,28 @@ export async function call(): Promise<LocalCommandResult> {
})
await Promise.race([fetchAndStoreChangelog(), timeoutPromise])
freshNotes = getAllReleaseNotes(await getStoredChangelog())
changelog = await getStoredChangelog()
} catch {
// Either fetch failed or timed out - just use cached notes
}
// If we have fresh notes from the quick fetch, use those
if (freshNotes.length > 0) {
return { type: 'text', value: formatReleaseNotes(freshNotes) }
if (!changelog) {
changelog = await getStoredChangelog()
}
// Otherwise check cached notes
const cachedNotes = getAllReleaseNotes(await getStoredChangelog())
if (cachedNotes.length > 0) {
return { type: 'text', value: formatReleaseNotes(cachedNotes) }
const recentNotes = getRecentReleaseNoteGroups(
MACRO.VERSION,
getGlobalConfig().lastReleaseNotesSeen,
changelog,
3,
)
if (recentNotes.length > 0) {
return { type: 'text', value: formatReleaseNotes(recentNotes) }
}
const latestNotes = getAllReleaseNotes(changelog).slice(-3).reverse()
if (latestNotes.length > 0) {
return { type: 'text', value: formatReleaseNotes(latestNotes) }
}
// Nothing available, show link
+1 -1
View File
@@ -74,7 +74,7 @@ export function LogoV2() {
const config = getGlobalConfig();
let changelog;
try {
changelog = getRecentReleaseNotesSync(3);
changelog = getRecentReleaseNotesSync(3, MACRO.VERSION, config.lastReleaseNotesSeen);
} catch {
changelog = [];
}
+13 -24
View File
@@ -9,7 +9,10 @@ import {
truncateToWidth,
truncateToWidthNoEllipsis,
} from './format.js'
import { getStoredChangelogFromMemory, parseChangelog } from './releaseNotes.js'
import {
getRecentReleaseNotes,
getStoredChangelogFromMemory,
} from './releaseNotes.js'
import { gt } from './semver.js'
import { loadMessageLogs } from './sessionStorage.js'
import { getInitialSettings } from './settings/settings.js'
@@ -309,7 +312,11 @@ export function formatModelAndBilling(
* For ants, uses commits bundled at build time
* For external users, uses public changelog
*/
export function getRecentReleaseNotesSync(maxItems: number): string[] {
export function getRecentReleaseNotesSync(
maxItems: number,
currentVersion: string = MACRO.VERSION,
lastSeenVersion?: string | null,
): string[] {
// For ants, use bundled changelog
if (process.env.USER_TYPE === 'ant') {
const changelog = MACRO.VERSION_CHANGELOG
@@ -325,26 +332,8 @@ export function getRecentReleaseNotesSync(maxItems: number): string[] {
return []
}
let parsed
try {
parsed = parseChangelog(changelog)
} catch {
return []
}
// Get notes from recent versions
const allNotes: string[] = []
const versions = Object.keys(parsed)
.sort((a, b) => (gt(a, b) ? -1 : 1))
.slice(0, 3) // Look at top 3 recent versions
for (const version of versions) {
const notes = parsed[version]
if (notes) {
allNotes.push(...notes)
}
}
// Return raw notes without filtering or premature truncation
return allNotes.slice(0, maxItems)
return getRecentReleaseNotes(currentVersion, lastSeenVersion, changelog).slice(
0,
maxItems,
)
}
+47 -22
View File
@@ -210,28 +210,14 @@ export function getRecentReleaseNotes(
changelogContent: string = getStoredChangelogFromMemory(),
): string[] {
try {
const releaseNotes = parseChangelog(changelogContent)
// Strip SHA from both versions to compare only the base versions
const baseCurrentVersion = coerce(currentVersion)
const basePreviousVersion = previousVersion ? coerce(previousVersion) : null
if (
!basePreviousVersion ||
(baseCurrentVersion &&
gt(baseCurrentVersion.version, basePreviousVersion.version))
) {
// Get all versions that are newer than the last seen version
return Object.entries(releaseNotes)
.filter(
([version]) =>
!basePreviousVersion || gt(version, basePreviousVersion.version),
)
.sort(([versionA], [versionB]) => (gt(versionA, versionB) ? -1 : 1)) // Sort newest first
.flatMap(([_, notes]) => notes)
.filter(Boolean)
.slice(0, MAX_RELEASE_NOTES_SHOWN)
}
return getRecentReleaseNoteGroups(
currentVersion,
previousVersion,
changelogContent,
)
.flatMap(([, notes]) => notes)
.filter(Boolean)
.slice(0, MAX_RELEASE_NOTES_SHOWN)
} catch (error) {
logError(toError(error))
return []
@@ -239,6 +225,45 @@ export function getRecentReleaseNotes(
return []
}
export function getRecentReleaseNoteGroups(
currentVersion: string,
previousVersion: string | null | undefined,
changelogContent: string = getStoredChangelogFromMemory(),
maxVersions: number = Number.POSITIVE_INFINITY,
): Array<[string, string[]]> {
try {
const releaseNotes = parseChangelog(changelogContent)
// Strip SHA/build metadata from both versions to compare only the base semver.
const baseCurrentVersion = coerce(currentVersion)
const basePreviousVersion = previousVersion ? coerce(previousVersion) : null
if (!baseCurrentVersion) {
return []
}
if (
basePreviousVersion &&
!gt(baseCurrentVersion.version, basePreviousVersion.version)
) {
return []
}
return Object.entries(releaseNotes)
.filter(
([version]) =>
!basePreviousVersion || gt(version, basePreviousVersion.version),
)
.sort(([versionA], [versionB]) => (gt(versionA, versionB) ? -1 : 1))
.slice(0, maxVersions)
.map(([version, notes]) => [version, notes.filter(Boolean)] as [string, string[]])
.filter(([, notes]) => notes.length > 0)
} catch (error) {
logError(toError(error))
return []
}
}
/**
* Gets all release notes as an array of [version, notes] arrays.
* Versions are sorted with oldest first.