Skip to content

Commit 9adbc53

Browse files
committed
'chore: WIP'
1 parent 4659f54 commit 9adbc53

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1081
-9
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// kilocode_change - new file: Storybook story for Release Notes Modal component
2+
import type { Meta, StoryObj } from "@storybook/react-vite"
3+
import { ReleaseNotesModal } from "@/components/release-notes/ReleaseNotesModal"
4+
import { sampleReleaseNotes } from "./sampleReleaseNotes"
5+
6+
const meta = {
7+
title: "Components/ReleaseNotesModal",
8+
component: ReleaseNotesModal,
9+
argTypes: {
10+
isOpen: {
11+
control: { type: "boolean" },
12+
},
13+
loading: {
14+
control: { type: "boolean" },
15+
},
16+
currentVersion: {
17+
control: { type: "text" },
18+
},
19+
},
20+
parameters: {
21+
disableChromaticDualThemeSnapshot: true,
22+
},
23+
args: {
24+
isOpen: true,
25+
currentVersion: "4.106.0",
26+
releases: sampleReleaseNotes,
27+
loading: false,
28+
onClose: () => console.log("Modal closed"),
29+
onMarkAsViewed: (version: string) => console.log("Version marked as viewed:", version),
30+
},
31+
} satisfies Meta<typeof ReleaseNotesModal>
32+
33+
export default meta
34+
type Story = StoryObj<typeof meta>
35+
36+
export const Default: Story = {
37+
args: {
38+
releases: sampleReleaseNotes,
39+
},
40+
}
41+
42+
export const SingleRelease: Story = {
43+
args: {
44+
releases: [sampleReleaseNotes[0]],
45+
},
46+
}
47+
48+
export const UncategorizedChanges: Story = {
49+
args: {
50+
currentVersion: "4.104.0",
51+
releases: [sampleReleaseNotes[2]], // The one with only rawChanges
52+
},
53+
}
54+
55+
export const Loading: Story = {
56+
args: {
57+
releases: [],
58+
loading: true,
59+
},
60+
}
61+
62+
export const EmptyReleases: Story = {
63+
args: {
64+
releases: [],
65+
loading: false,
66+
},
67+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// kilocode_change - new file: Sample release notes data for Storybook testing
2+
import { ReleaseNote } from "@/types/release-notes"
3+
4+
// Sample release notes data for testing
5+
export const sampleReleaseNotes: ReleaseNote[] = [
6+
{
7+
version: "4.106.0",
8+
features: [
9+
{
10+
description: "Preliminary support for native tool calling (a.k.a native function calling) was added",
11+
category: "feature",
12+
prNumber: 2833,
13+
commitHash: "0b8ef46",
14+
author: "mcowger",
15+
details:
16+
"This feature is currently experimental and mostly intended for users interested in contributing to its development.\nIt is so far only supported when using OpenRouter or Kilo Code providers.",
17+
},
18+
],
19+
fixes: [],
20+
improvements: [
21+
{
22+
description: "CMD-I now invokes the agent so you can give it more complex prompts",
23+
category: "improvement",
24+
prNumber: 3050,
25+
commitHash: "357d438",
26+
author: "markijbema",
27+
},
28+
],
29+
breakingChanges: [],
30+
rawChanges: [],
31+
},
32+
{
33+
version: "4.105.0",
34+
features: [
35+
{
36+
description: "Improve the edit chat area to allow context and file drag and drop when editing messages",
37+
category: "feature",
38+
prNumber: 3005,
39+
commitHash: "b87ae9c",
40+
author: "kevinvandijk",
41+
},
42+
],
43+
fixes: [
44+
{
45+
description: "A warning is now shown when the webview memory usage crosses 90% of the limit",
46+
category: "fix",
47+
prNumber: 3046,
48+
commitHash: "1bd934f",
49+
author: "chrarnoldus",
50+
},
51+
],
52+
improvements: [],
53+
breakingChanges: [],
54+
rawChanges: [],
55+
},
56+
{
57+
version: "4.104.0",
58+
features: [],
59+
fixes: [],
60+
improvements: [],
61+
breakingChanges: [],
62+
rawChanges: [
63+
{
64+
description: "Update Gemini provider to support dynamic model retrieval",
65+
category: "other",
66+
prNumber: 2673,
67+
commitHash: "cf1aca2",
68+
author: "mcowger",
69+
},
70+
{
71+
description: "Improved OpenAI compatible parser's ability to yield reasoning content",
72+
category: "other",
73+
prNumber: 2749,
74+
commitHash: "7e493ec",
75+
author: "mcowger",
76+
},
77+
],
78+
},
79+
]

packages/types/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export * from "./message.js"
1414
export * from "./mode.js"
1515
export * from "./model.js"
1616
export * from "./provider-settings.js"
17+
export * from "./release-notes.js"
1718
export * from "./single-file-read-models.js"
1819
export * from "./task.js"
1920
export * from "./todo.js"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export interface ReleaseItem {
2+
description: string
3+
prNumber?: number
4+
commitHash?: string
5+
author?: string
6+
category: ReleaseItemCategory
7+
}
8+
9+
export type ReleaseItemCategory = "feature" | "fix" | "other"
10+
11+
export interface ReleaseNote {
12+
version: string
13+
changes: ReleaseItem[]
14+
}
15+
16+
export interface ReleaseData {
17+
currentVersion: string
18+
releases: ReleaseNote[]
19+
}

webview-ui/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
# production
1212
/build
1313

14+
# kilocode_change - Generated release notes JSON (but keep .d.ts files)
15+
/src/generated/**/*.json
16+
1417
# misc
1518
.DS_Store
1619
.env.local
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#!/usr/bin/env node
2+
// kilocode_change - new file: Build-time script to parse CHANGELOG.md and generate releases.json
3+
4+
import fs from 'fs'
5+
import path from 'path'
6+
import process from 'process'
7+
import { fileURLToPath } from 'url'
8+
9+
const __filename = fileURLToPath(import.meta.url)
10+
const __dirname = path.dirname(__filename)
11+
12+
console.log('🚀 Starting changelog parsing...')
13+
14+
// Paths
15+
const changelogPath = path.resolve(__dirname, '../../CHANGELOG.md')
16+
const outputDir = path.resolve(__dirname, '../src/generated/releases')
17+
18+
console.log('📖 Reading changelog from:', changelogPath)
19+
console.log('📁 Output directory:', outputDir)
20+
21+
// Check if changelog exists
22+
if (!fs.existsSync(changelogPath)) {
23+
console.error('❌ Changelog not found at:', changelogPath)
24+
process.exit(1)
25+
}
26+
27+
// Read changelog
28+
const changelogContent = fs.readFileSync(changelogPath, 'utf-8')
29+
console.log('📄 Changelog loaded, length:', changelogContent.length, 'characters')
30+
31+
// Parse releases using split-based approach for better content extraction
32+
const releases = []
33+
34+
// Split changelog into sections by version headers
35+
const versionSections = changelogContent.split(/^## \[v(\d+\.\d+\.\d+)\]/gm)
36+
37+
// Process each version section (skip first empty element)
38+
for (let i = 1; i < versionSections.length; i += 2) {
39+
const version = versionSections[i]
40+
const sectionContent = versionSections[i + 1] || ''
41+
42+
const changes = extractChangesFromSection(sectionContent)
43+
44+
if (changes.length > 0) {
45+
const release = {
46+
version,
47+
changes
48+
}
49+
50+
releases.push(release)
51+
console.log(`📝 Parsed release v${version} with ${changes.length} changes`)
52+
}
53+
}
54+
55+
function extractChangesFromSection(sectionContent) {
56+
const lines = sectionContent.split('\n')
57+
const changes = []
58+
let currentChange = null
59+
let collectingMultilineDescription = false
60+
61+
for (const line of lines) {
62+
const trimmedLine = line.trim()
63+
64+
// Skip empty lines and section headers
65+
if (!trimmedLine || trimmedLine.startsWith('###')) {
66+
// Stop collecting multiline content when we hit a section break
67+
if (trimmedLine.startsWith('###')) {
68+
collectingMultilineDescription = false
69+
}
70+
continue
71+
}
72+
73+
// Check if this is a new change entry
74+
if (trimmedLine.startsWith('- [#')) {
75+
// Save previous change if exists
76+
if (currentChange) {
77+
changes.push(currentChange)
78+
}
79+
80+
// Create new change entry
81+
currentChange = parseChangeEntry(trimmedLine)
82+
collectingMultilineDescription = true
83+
} else if (collectingMultilineDescription && currentChange) {
84+
// Check if this is indented content (part of the multiline description)
85+
if (line.startsWith(' ') || line.startsWith('\t')) {
86+
// This is indented content, part of the description
87+
currentChange.description += ' ' + trimmedLine
88+
} else if (trimmedLine.startsWith('- ') && !trimmedLine.startsWith('- [#')) {
89+
// This is a bullet point in the description, not a new change
90+
currentChange.description += ' ' + trimmedLine.replace(/^- /, '')
91+
} else {
92+
// Any other content that might be part of the description
93+
currentChange.description += ' ' + trimmedLine
94+
}
95+
}
96+
}
97+
98+
// Don't forget the last change
99+
if (currentChange) {
100+
changes.push(currentChange)
101+
}
102+
103+
return changes
104+
}
105+
106+
function parseChangeEntry(line) {
107+
const item = {
108+
description: line.replace(/^- /, '').trim(),
109+
category: 'other'
110+
}
111+
112+
// Extract PR number
113+
const prMatch = line.match(/\[#(\d+)\]/)
114+
if (prMatch) {
115+
item.prNumber = parseInt(prMatch[1])
116+
}
117+
118+
// Extract commit hash
119+
const commitMatch = line.match(/\[`([a-f0-9]+)`\]/)
120+
if (commitMatch) {
121+
item.commitHash = commitMatch[1]
122+
}
123+
124+
// Extract author - updated regex to handle hyphens and other valid GitHub username characters
125+
const authorMatch = line.match(/Thanks \[@([\w-]+)\]/)
126+
if (authorMatch) {
127+
item.author = authorMatch[1]
128+
}
129+
130+
// Extract description after "! - "
131+
const descMatch = line.match(/! - (.+)$/)
132+
if (descMatch) {
133+
item.description = descMatch[1].trim()
134+
}
135+
136+
return item
137+
}
138+
139+
console.log(`✅ Found ${releases.length} releases`)
140+
141+
// Limit to the last 10 releases to keep build size manageable
142+
const MAX_RELEASES = 10
143+
const limitedReleases = releases.slice(0, MAX_RELEASES)
144+
console.log(`🔢 Limiting to ${limitedReleases.length} most recent releases (from ${releases.length} total)`)
145+
146+
// Add improved categorization based on patterns and content keywords
147+
limitedReleases.forEach(release => {
148+
release.changes.forEach(change => {
149+
change.category = categorizeChange(change.description)
150+
})
151+
})
152+
153+
// kilocode_change start: Simplified categorization - just 3 categories
154+
function categorizeChange(description) {
155+
const desc = description.toLowerCase().trim()
156+
157+
// Simple keyword-based categorization
158+
if (desc.includes('fix') || desc.includes('bug') || desc.includes('correct') || desc.includes('resolve')) {
159+
return 'fix'
160+
}
161+
162+
if (desc.includes('add') || desc.includes('new') || desc.includes('introduce')) {
163+
return 'feature'
164+
}
165+
166+
// Everything else goes to "other"
167+
return 'other'
168+
}
169+
// kilocode_change end
170+
171+
// Create output directory
172+
if (!fs.existsSync(outputDir)) {
173+
fs.mkdirSync(outputDir, { recursive: true })
174+
console.log('📁 Created output directory')
175+
}
176+
177+
// Generate single releases.json file with current version and all releases
178+
const releaseData = {
179+
currentVersion: limitedReleases[0]?.version || "0.0.0",
180+
releases: limitedReleases
181+
}
182+
183+
const releasesPath = path.join(outputDir, 'releases.json')
184+
fs.writeFileSync(releasesPath, JSON.stringify(releaseData, null, 2))
185+
186+
console.log(`💾 Generated releases.json with ${limitedReleases.length} releases`)
187+
console.log(`📋 Current version: ${releaseData.currentVersion}`)
188+
console.log('🎉 Changelog parsing completed successfully!')

webview-ui/src/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { TooltipProvider } from "./components/ui/tooltip"
3232
import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip"
3333
import { useKiloIdentity } from "./utils/kilocode/useKiloIdentity"
3434
import { MemoryWarningBanner } from "./kilocode/MemoryWarningBanner"
35+
import { AutoReleaseNotesChecker } from "./components/release-notes" // kilocode_change
3536

3637
type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account" | "cloud" | "profile" // kilocode_change: add "profile"
3738

@@ -282,6 +283,10 @@ const App = () => {
282283
<>
283284
{/* kilocode_change: add MemoryWarningBanner */}
284285
<MemoryWarningBanner />
286+
287+
{/* kilocode_change: Auto Release Notes Checker - only show if user has API configured */}
288+
{apiConfiguration && <AutoReleaseNotesChecker />}
289+
285290
{tab === "modes" && <ModesView onDone={() => switchTab("chat")} />}
286291
{tab === "mcp" && <McpView onDone={() => switchTab("chat")} />}
287292
{tab === "history" && <HistoryView onDone={() => switchTab("chat")} />}

0 commit comments

Comments
 (0)