chenbhao commited on
Commit
60e4320
·
1 Parent(s): 3199d61

feat: /release-notes and what's news

Browse files
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "claude-code-source-snapshot",
3
- "version": "2.1.87",
4
  "private": true,
5
  "workspaces": [
6
  "packages/*"
 
1
  {
2
  "name": "claude-code-source-snapshot",
3
+ "version": "2.1.0",
4
  "private": true,
5
  "workspaces": [
6
  "packages/*"
src/components/LogoV2/CondensedLogo.tsx CHANGED
@@ -58,7 +58,7 @@ export function CondensedLogo(): ReactNode {
58
  const textWidth = Math.max(columns - 15, 20)
59
 
60
  // Truncate version to fit within available width, accounting for "Claude Code v" prefix
61
- const versionPrefix = 'Claude Code v'
62
  const truncatedVersion = truncate(
63
  version,
64
  Math.max(textWidth - versionPrefix.length, 6),
@@ -92,7 +92,7 @@ export function CondensedLogo(): ReactNode {
92
  {/* Info */}
93
  <Box flexDirection="column">
94
  <Text>
95
- <Text bold>Claude Code</Text>{' '}
96
  <Text dimColor>v{truncatedVersion}</Text>
97
  </Text>
98
  {shouldSplit ? (
 
58
  const textWidth = Math.max(columns - 15, 20)
59
 
60
  // Truncate version to fit within available width, accounting for "Claude Code v" prefix
61
+ const versionPrefix = 'Versper Claw v'
62
  const truncatedVersion = truncate(
63
  version,
64
  Math.max(textWidth - versionPrefix.length, 6),
 
92
  {/* Info */}
93
  <Box flexDirection="column">
94
  <Text>
95
+ <Text bold>Versper Claw</Text>{' '}
96
  <Text dimColor>v{truncatedVersion}</Text>
97
  </Text>
98
  {shouldSplit ? (
src/components/LogoV2/LogoV2.tsx CHANGED
@@ -250,8 +250,8 @@ export function LogoV2(): React.ReactNode {
250
  const layoutMode = getLayoutMode(columns)
251
 
252
  const userTheme = resolveThemeSetting(getGlobalConfig().theme)
253
- const borderTitle = ` ${color('claude', userTheme)('Claude Code')} ${color('inactive', userTheme)(`v${version}`)} `
254
- const compactBorderTitle = color('claude', userTheme)(' Claude Code ')
255
 
256
  // Early return for compact mode
257
  if (layoutMode === 'compact') {
 
250
  const layoutMode = getLayoutMode(columns)
251
 
252
  const userTheme = resolveThemeSetting(getGlobalConfig().theme)
253
+ const borderTitle = ` ${color('claude', userTheme)('Versper Claw')} ${color('inactive', userTheme)(`v${version}`)} `
254
+ const compactBorderTitle = color('claude', userTheme)(' Versper Claw ')
255
 
256
  // Early return for compact mode
257
  if (layoutMode === 'compact') {
src/entrypoints/cli.tsx CHANGED
@@ -37,7 +37,7 @@ async function main(): Promise<void> {
37
  if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
38
  // MACRO.VERSION is inlined at build time
39
  // biome-ignore lint/suspicious/noConsole:: intentional console output
40
- console.log(`${MACRO.VERSION} (Claude Code)`);
41
  return;
42
  }
43
 
 
37
  if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
38
  // MACRO.VERSION is inlined at build time
39
  // biome-ignore lint/suspicious/noConsole:: intentional console output
40
+ console.log(`${MACRO.VERSION} (Versper Claw)`);
41
  return;
42
  }
43
 
src/utils/releaseNotes.ts CHANGED
@@ -26,9 +26,9 @@ const MAX_RELEASE_NOTES_SHOWN = 5
26
  * 3. Next time the user starts Claude, the cached changelog is available immediately
27
  */
28
  export const CHANGELOG_URL =
29
- 'https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md'
30
  const RAW_CHANGELOG_URL =
31
- 'https://raw.githubusercontent.com/anthropics/claude-code/refs/heads/main/CHANGELOG.md'
32
 
33
  /**
34
  * Get the path for the cached changelog file.
@@ -90,9 +90,29 @@ export async function fetchAndStoreChangelog(): Promise<void> {
90
  return
91
  }
92
 
93
- const response = await axios.get(RAW_CHANGELOG_URL)
 
 
94
  if (response.status === 200) {
95
- const changelogContent = response.data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  // Skip write if content unchanged — writing Date.now() defeats the
98
  // dirty-check in saveGlobalConfig since the timestamp always differs.
@@ -244,12 +264,13 @@ export function getRecentReleaseNoteGroups(
244
 
245
  if (
246
  basePreviousVersion &&
247
- !gt(baseCurrentVersion.version, basePreviousVersion.version)
 
248
  ) {
249
  return []
250
  }
251
 
252
- return Object.entries(releaseNotes)
253
  .filter(
254
  ([version]) =>
255
  !basePreviousVersion || gt(version, basePreviousVersion.version),
@@ -258,6 +279,18 @@ export function getRecentReleaseNoteGroups(
258
  .slice(0, maxVersions)
259
  .map(([version, notes]) => [version, notes.filter(Boolean)] as [string, string[]])
260
  .filter(([, notes]) => notes.length > 0)
 
 
 
 
 
 
 
 
 
 
 
 
261
  } catch (error) {
262
  logError(toError(error))
263
  return []
 
26
  * 3. Next time the user starts Claude, the cached changelog is available immediately
27
  */
28
  export const CHANGELOG_URL =
29
+ 'https://github.com/versperai/VersperClaw/releases'
30
  const RAW_CHANGELOG_URL =
31
+ 'https://api.github.com/repos/versperai/VersperClaw/releases'
32
 
33
  /**
34
  * Get the path for the cached changelog file.
 
90
  return
91
  }
92
 
93
+ const response = await axios.get(RAW_CHANGELOG_URL, {
94
+ headers: { 'User-Agent': 'VersperClaw' },
95
+ })
96
  if (response.status === 200) {
97
+ const releases = response.data as Array<{
98
+ tag_name: string
99
+ name: string
100
+ }>
101
+
102
+ // Transform releases into markdown format that parseChangelog expects:
103
+ // ## version
104
+ // - description
105
+ const changelogContent = releases
106
+ .map(release => {
107
+ const version = release.tag_name.replace(/^v/, '')
108
+ const lines = [`## ${version}`]
109
+ if (release.name) {
110
+ lines.push(`- ${release.name}`)
111
+ }
112
+ return lines.length > 1 ? lines.join('\n') : ''
113
+ })
114
+ .filter(Boolean)
115
+ .join('\n\n')
116
 
117
  // Skip write if content unchanged — writing Date.now() defeats the
118
  // dirty-check in saveGlobalConfig since the timestamp always differs.
 
264
 
265
  if (
266
  basePreviousVersion &&
267
+ !gt(baseCurrentVersion.version, basePreviousVersion.version) &&
268
+ Object.keys(releaseNotes).length === 0
269
  ) {
270
  return []
271
  }
272
 
273
+ const filtered = Object.entries(releaseNotes)
274
  .filter(
275
  ([version]) =>
276
  !basePreviousVersion || gt(version, basePreviousVersion.version),
 
279
  .slice(0, maxVersions)
280
  .map(([version, notes]) => [version, notes.filter(Boolean)] as [string, string[]])
281
  .filter(([, notes]) => notes.length > 0)
282
+
283
+ // Fallback: if version-filter returns empty but releases exist
284
+ // (e.g., fork where app version exceeds all releases), show latest releases
285
+ if (filtered.length === 0 && Object.keys(releaseNotes).length > 0) {
286
+ return Object.entries(releaseNotes)
287
+ .sort(([versionA], [versionB]) => (gt(versionA, versionB) ? -1 : 1))
288
+ .slice(0, maxVersions)
289
+ .map(([version, notes]) => [version, notes.filter(Boolean)] as [string, string[]])
290
+ .filter(([, notes]) => notes.length > 0)
291
+ }
292
+
293
+ return filtered
294
  } catch (error) {
295
  logError(toError(error))
296
  return []