ai-changelog-generator-extension 0.4.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.
- package/.vscode/launch.json +41 -0
- package/.vscode/settings.json +15 -0
- package/.vscode/tasks.json +26 -0
- package/.vscodeignore +62 -0
- package/ARCHITECTURE-v0.4.0.md +418 -0
- package/CHANGELOG.md +28 -0
- package/DEVELOPMENT.md +266 -0
- package/IMPLEMENTATION_SUMMARY.md +240 -0
- package/IMPLEMENTATION_SUMMARY_v0.4.0.md +239 -0
- package/LICENSE +21 -0
- package/MIGRATION_CHECKLIST.md +200 -0
- package/QUICK-REFERENCE-v0.4.0.md +251 -0
- package/QUICK-START.md +211 -0
- package/README.md +95 -0
- package/RELEASE-NOTES-0.2.0.md +176 -0
- package/RELEASE-NOTES-0.3.0.md +275 -0
- package/RELEASE-NOTES-0.4.0.md +194 -0
- package/SETTINGS-GUIDE.md +418 -0
- package/TESTING-v0.4.0.md +263 -0
- package/TESTING.md +255 -0
- package/esbuild.js +54 -0
- package/package.json +282 -0
- package/setup.sh +58 -0
- package/src/commands/configureProvider.ts +28 -0
- package/src/commands/setupWizard.ts +333 -0
- package/src/commands/testConnection.ts +93 -0
- package/src/extension.ts +264 -0
- package/src/services/EnvFileService.ts +172 -0
- package/src/services/ExtensionConfigurationManager.ts +224 -0
- package/src/services/StatusService.ts +211 -0
- package/src/types/core.d.ts +85 -0
- package/src/views/CommitSidebarProvider.ts +572 -0
- package/src/views/OnboardingPanelProvider.ts +1366 -0
- package/src/views/ReleaseSidebarProvider.ts +370 -0
- package/src/views/SettingsPanelProvider.ts +991 -0
- package/test-package.sh +38 -0
- package/tsconfig.json +18 -0
- package/v0.4.0-COMPLETE.md +349 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import * as vscode from 'vscode'
|
|
2
|
+
import { ExtensionConfigurationManager } from '../services/ExtensionConfigurationManager'
|
|
3
|
+
import { EnvFileService } from '../services/EnvFileService'
|
|
4
|
+
import { StatusService } from '../services/StatusService'
|
|
5
|
+
|
|
6
|
+
export async function setupWizard(
|
|
7
|
+
configManager: ExtensionConfigurationManager
|
|
8
|
+
): Promise<boolean> {
|
|
9
|
+
const config = vscode.workspace.getConfiguration('aiChangelog')
|
|
10
|
+
|
|
11
|
+
StatusService.log('Setup wizard started')
|
|
12
|
+
|
|
13
|
+
// Welcome message
|
|
14
|
+
const proceed = await vscode.window.showInformationMessage(
|
|
15
|
+
'🎉 Welcome to AI Changelog Generator!\n\nThis wizard will help you configure your AI provider in 3 simple steps:\n\n1️⃣ Choose storage method\n2️⃣ Select AI provider\n3️⃣ Enter credentials\n\nReady to begin?',
|
|
16
|
+
{ modal: true },
|
|
17
|
+
'Start Setup',
|
|
18
|
+
'Cancel'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if (proceed !== 'Start Setup') {
|
|
22
|
+
StatusService.log('Setup wizard cancelled by user')
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Step 1: Check for existing environment variables
|
|
28
|
+
const autoDetect = config.get<boolean>('autoDetectEnv', true)
|
|
29
|
+
if (autoDetect) {
|
|
30
|
+
const envVars = await EnvFileService.detectEnvironmentVariables()
|
|
31
|
+
if (Object.keys(envVars).length > 0) {
|
|
32
|
+
StatusService.log(`Found ${Object.keys(envVars).length} API keys in .env files`)
|
|
33
|
+
|
|
34
|
+
const useEnv = await vscode.window.showInformationMessage(
|
|
35
|
+
`🔍 Found API keys in .env file!\n\nDetected: ${Object.keys(envVars).join(', ')}\n\nWould you like to import these keys?`,
|
|
36
|
+
{ modal: true },
|
|
37
|
+
'Import from .env',
|
|
38
|
+
'Configure Manually'
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if (useEnv === 'Import from .env') {
|
|
42
|
+
StatusService.log('Importing keys from .env file...')
|
|
43
|
+
|
|
44
|
+
// Import keys from .env
|
|
45
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
46
|
+
const provider = EnvFileService.getProviderFromKey(key)
|
|
47
|
+
if (provider && value) {
|
|
48
|
+
await configManager.storeApiKey(provider, value)
|
|
49
|
+
StatusService.log(`✓ Imported ${key} for ${provider}`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Set storage mode to env
|
|
54
|
+
await config.update('storageMode', 'env', vscode.ConfigurationTarget.Workspace)
|
|
55
|
+
|
|
56
|
+
// Determine primary provider
|
|
57
|
+
const firstKey = Object.keys(envVars)[0]
|
|
58
|
+
const primaryProvider = EnvFileService.getProviderFromKey(firstKey)
|
|
59
|
+
if (primaryProvider) {
|
|
60
|
+
await config.update('provider', primaryProvider, vscode.ConfigurationTarget.Workspace)
|
|
61
|
+
StatusService.log(`Set primary provider to ${primaryProvider}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await config.update('setupCompleted', true, vscode.ConfigurationTarget.Workspace)
|
|
65
|
+
|
|
66
|
+
vscode.window.showInformationMessage(
|
|
67
|
+
'✅ Setup complete! API keys imported from .env file.',
|
|
68
|
+
'Test Connection'
|
|
69
|
+
).then((action) => {
|
|
70
|
+
if (action === 'Test Connection') {
|
|
71
|
+
vscode.commands.executeCommand('ai-changelog.testConnection')
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
StatusService.log('Setup completed successfully (env import)')
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Step 2: Choose storage mode
|
|
82
|
+
await vscode.window.showInformationMessage(
|
|
83
|
+
'📍 Step 1 of 3: Storage Method\n\nWhere should API keys be stored?',
|
|
84
|
+
{ modal: false }
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
const storageMode = await vscode.window.showQuickPick(
|
|
88
|
+
[
|
|
89
|
+
{
|
|
90
|
+
label: '🔒 Secure Storage (Recommended)',
|
|
91
|
+
description: 'Store keys in VS Code secret storage',
|
|
92
|
+
value: 'secrets',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
label: '📄 Environment File',
|
|
96
|
+
description: 'Store keys in .env.local file',
|
|
97
|
+
value: 'env',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
label: '⚙️ Settings File',
|
|
101
|
+
description: 'Store in settings.json (not recommended - not secure)',
|
|
102
|
+
value: 'settings',
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
{
|
|
106
|
+
placeHolder: 'Select where to store API keys',
|
|
107
|
+
ignoreFocusOut: true,
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if (!storageMode) {
|
|
112
|
+
StatusService.log('Setup cancelled: No storage mode selected')
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
await config.update('storageMode', storageMode.value, vscode.ConfigurationTarget.Workspace)
|
|
117
|
+
StatusService.log(`Storage mode set to: ${storageMode.value}`)
|
|
118
|
+
|
|
119
|
+
// Step 3: Choose provider
|
|
120
|
+
await vscode.window.showInformationMessage(
|
|
121
|
+
'📍 Step 2 of 3: AI Provider\n\nSelect your AI provider',
|
|
122
|
+
{ modal: false }
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
const provider = await vscode.window.showQuickPick(
|
|
126
|
+
[
|
|
127
|
+
{ label: 'OpenAI', description: 'GPT-4, GPT-4 Turbo, GPT-4o', value: 'openai' },
|
|
128
|
+
{ label: 'Anthropic', description: 'Claude 3.5 Sonnet, Opus', value: 'anthropic' },
|
|
129
|
+
{ label: 'Google', description: 'Gemini Pro, Gemini Ultra', value: 'google' },
|
|
130
|
+
{ label: 'Azure OpenAI', description: 'Azure-hosted OpenAI models', value: 'azure' },
|
|
131
|
+
{
|
|
132
|
+
label: 'AWS Bedrock',
|
|
133
|
+
description: 'Claude via AWS Bedrock',
|
|
134
|
+
value: 'bedrock',
|
|
135
|
+
},
|
|
136
|
+
{ label: 'Ollama', description: 'Local models via Ollama', value: 'ollama' },
|
|
137
|
+
{ label: 'LM Studio', description: 'Local models via LM Studio', value: 'lmstudio' },
|
|
138
|
+
],
|
|
139
|
+
{
|
|
140
|
+
placeHolder: 'Select your AI provider',
|
|
141
|
+
ignoreFocusOut: true,
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if (!provider) {
|
|
146
|
+
StatusService.log('Setup cancelled: No provider selected')
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await config.update('provider', provider.value, vscode.ConfigurationTarget.Workspace)
|
|
151
|
+
StatusService.log(`Provider set to: ${provider.value}`)
|
|
152
|
+
|
|
153
|
+
// Step 4: Configure provider-specific settings
|
|
154
|
+
await vscode.window.showInformationMessage(
|
|
155
|
+
`📍 Step 3 of 3: Configure ${provider.label}\n\nAlmost there!`,
|
|
156
|
+
{ modal: false }
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
// Handle local providers (Ollama, LM Studio)
|
|
160
|
+
if (provider.value === 'ollama') {
|
|
161
|
+
const host = await vscode.window.showInputBox({
|
|
162
|
+
prompt: 'Ollama API host',
|
|
163
|
+
value: 'http://localhost:11434',
|
|
164
|
+
placeHolder: 'http://localhost:11434',
|
|
165
|
+
ignoreFocusOut: true,
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
if (host) {
|
|
169
|
+
await config.update('ollamaHost', host, vscode.ConfigurationTarget.Workspace)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const model = await vscode.window.showInputBox({
|
|
173
|
+
prompt: 'Ollama model name',
|
|
174
|
+
value: 'mistral',
|
|
175
|
+
placeHolder: 'mistral',
|
|
176
|
+
ignoreFocusOut: true,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
if (model) {
|
|
180
|
+
await config.update('model', model, vscode.ConfigurationTarget.Workspace)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
await config.update('setupCompleted', true, vscode.ConfigurationTarget.Workspace)
|
|
184
|
+
StatusService.log('Setup completed successfully (Ollama)')
|
|
185
|
+
|
|
186
|
+
const testNow = await vscode.window.showInformationMessage(
|
|
187
|
+
'✅ Ollama configured successfully!\n\nWould you like to test the connection?',
|
|
188
|
+
'Test Now',
|
|
189
|
+
'Skip'
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if (testNow === 'Test Now') {
|
|
193
|
+
vscode.commands.executeCommand('ai-changelog.testConnection')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (provider.value === 'lmstudio') {
|
|
200
|
+
const host = await vscode.window.showInputBox({
|
|
201
|
+
prompt: 'LM Studio API host',
|
|
202
|
+
value: 'http://localhost:1234',
|
|
203
|
+
placeHolder: 'http://localhost:1234',
|
|
204
|
+
ignoreFocusOut: true,
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
if (host) {
|
|
208
|
+
await config.update('lmStudioHost', host, vscode.ConfigurationTarget.Workspace)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
await config.update('setupCompleted', true, vscode.ConfigurationTarget.Workspace)
|
|
212
|
+
StatusService.log('Setup completed successfully (LM Studio)')
|
|
213
|
+
|
|
214
|
+
const testNow = await vscode.window.showInformationMessage(
|
|
215
|
+
'✅ LM Studio configured successfully!\n\nWould you like to test the connection?',
|
|
216
|
+
'Test Now',
|
|
217
|
+
'Skip'
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
if (testNow === 'Test Now') {
|
|
221
|
+
vscode.commands.executeCommand('ai-changelog.testConnection')
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return true
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Step 5: Get API key for cloud providers
|
|
228
|
+
const apiKey = await vscode.window.showInputBox({
|
|
229
|
+
prompt: `Enter your ${provider.label} API key`,
|
|
230
|
+
password: true,
|
|
231
|
+
placeHolder: 'sk-...',
|
|
232
|
+
ignoreFocusOut: true,
|
|
233
|
+
validateInput: (value) => {
|
|
234
|
+
if (!value || value.trim().length === 0) {
|
|
235
|
+
return 'API key is required'
|
|
236
|
+
}
|
|
237
|
+
if (value.length < 10) {
|
|
238
|
+
return 'API key seems too short. Please check it.'
|
|
239
|
+
}
|
|
240
|
+
return null
|
|
241
|
+
},
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
if (!apiKey) {
|
|
245
|
+
StatusService.log('Setup cancelled: No API key entered')
|
|
246
|
+
return false
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
StatusService.log(`API key entered for ${provider.value} (${apiKey.length} characters)`)
|
|
250
|
+
|
|
251
|
+
// Step 6: Save API key based on storage mode
|
|
252
|
+
try {
|
|
253
|
+
if (storageMode.value === 'env') {
|
|
254
|
+
const keyName = configManager['getKeyNameForProvider'](provider.value)
|
|
255
|
+
await EnvFileService.saveToEnvFile(keyName, apiKey)
|
|
256
|
+
StatusService.log(`✓ API key saved to .env file`)
|
|
257
|
+
vscode.window.showInformationMessage(`✅ API key saved to .env.local`)
|
|
258
|
+
} else if (storageMode.value === 'settings') {
|
|
259
|
+
// Save to workspace settings (not recommended)
|
|
260
|
+
const keyName = `${provider.value}ApiKey`
|
|
261
|
+
await config.update(keyName, apiKey, vscode.ConfigurationTarget.Workspace)
|
|
262
|
+
StatusService.log(`✓ API key saved to settings.json`)
|
|
263
|
+
vscode.window.showWarningMessage(
|
|
264
|
+
'⚠️ API key stored in settings.json. This is visible in your workspace settings and not recommended for security.'
|
|
265
|
+
)
|
|
266
|
+
} else {
|
|
267
|
+
// Default: secure storage
|
|
268
|
+
await configManager.storeApiKey(provider.value, apiKey)
|
|
269
|
+
StatusService.log(`✓ API key saved to secure storage`)
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
const errorMsg = error instanceof Error ? error.message : String(error)
|
|
273
|
+
StatusService.log(`✗ Failed to save API key: ${errorMsg}`)
|
|
274
|
+
vscode.window.showErrorMessage(`Failed to save API key: ${errorMsg}`)
|
|
275
|
+
return false
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Azure-specific configuration
|
|
279
|
+
if (provider.value === 'azure') {
|
|
280
|
+
const endpoint = await vscode.window.showInputBox({
|
|
281
|
+
prompt: 'Azure OpenAI endpoint',
|
|
282
|
+
placeHolder: 'https://your-resource.openai.azure.com',
|
|
283
|
+
ignoreFocusOut: true,
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
if (endpoint) {
|
|
287
|
+
await config.update('azureEndpoint', endpoint, vscode.ConfigurationTarget.Workspace)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const deployment = await vscode.window.showInputBox({
|
|
291
|
+
prompt: 'Azure deployment name',
|
|
292
|
+
placeHolder: 'gpt-4',
|
|
293
|
+
ignoreFocusOut: true,
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
if (deployment) {
|
|
297
|
+
await config.update(
|
|
298
|
+
'azureDeploymentName',
|
|
299
|
+
deployment,
|
|
300
|
+
vscode.ConfigurationTarget.Workspace
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Mark setup as completed
|
|
306
|
+
await config.update('setupCompleted', true, vscode.ConfigurationTarget.Workspace)
|
|
307
|
+
StatusService.log('Setup marked as complete')
|
|
308
|
+
|
|
309
|
+
// Test connection
|
|
310
|
+
const testConnection = await vscode.window.showInformationMessage(
|
|
311
|
+
'✅ Configuration saved!\n\nWould you like to test the connection to verify everything works?',
|
|
312
|
+
{ modal: true },
|
|
313
|
+
'Test Now',
|
|
314
|
+
'Skip'
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
if (testConnection === 'Test Now') {
|
|
318
|
+
StatusService.log('User requested connection test')
|
|
319
|
+
await vscode.commands.executeCommand('ai-changelog.testConnection')
|
|
320
|
+
} else {
|
|
321
|
+
vscode.window.showInformationMessage(
|
|
322
|
+
'🎉 Setup complete! You can test the connection anytime with "AI Changelog: Test Connection"'
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return true
|
|
327
|
+
} catch (error) {
|
|
328
|
+
const errorMsg = error instanceof Error ? error.message : String(error)
|
|
329
|
+
StatusService.log(`✗ Setup wizard failed: ${errorMsg}`)
|
|
330
|
+
vscode.window.showErrorMessage(`Setup failed: ${errorMsg}`)
|
|
331
|
+
return false
|
|
332
|
+
}
|
|
333
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as vscode from 'vscode'
|
|
2
|
+
import { ExtensionConfigurationManager } from '../services/ExtensionConfigurationManager'
|
|
3
|
+
import { StatusService } from '../services/StatusService'
|
|
4
|
+
|
|
5
|
+
export async function testConnection(
|
|
6
|
+
configManager: ExtensionConfigurationManager
|
|
7
|
+
): Promise<void> {
|
|
8
|
+
const provider = configManager.getCurrentProvider()
|
|
9
|
+
|
|
10
|
+
StatusService.log(`Testing connection to ${provider}...`, true)
|
|
11
|
+
|
|
12
|
+
await vscode.window.withProgress(
|
|
13
|
+
{
|
|
14
|
+
location: vscode.ProgressLocation.Notification,
|
|
15
|
+
title: `Testing ${provider} connection...`,
|
|
16
|
+
cancellable: false,
|
|
17
|
+
},
|
|
18
|
+
async (progress) => {
|
|
19
|
+
try {
|
|
20
|
+
progress.report({ increment: 30, message: 'Checking configuration...' })
|
|
21
|
+
|
|
22
|
+
// Ensure config manager is initialized to load env vars if needed
|
|
23
|
+
if (!configManager.isInitialized()) {
|
|
24
|
+
await configManager.initialize()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check if API key exists (for cloud providers)
|
|
28
|
+
if (provider !== 'ollama' && provider !== 'lmstudio') {
|
|
29
|
+
// Check in config manager (which includes env vars)
|
|
30
|
+
const keyName = configManager['getKeyNameForProvider'](provider)
|
|
31
|
+
const apiKey = configManager.get(keyName)
|
|
32
|
+
|
|
33
|
+
if (!apiKey || apiKey.trim().length === 0) {
|
|
34
|
+
throw new Error(`No API key configured for ${provider}. Storage mode: ${configManager.getStorageMode()}`)
|
|
35
|
+
}
|
|
36
|
+
StatusService.log(`✓ API key found for ${provider}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
progress.report({ increment: 30, message: 'Initializing...' })
|
|
40
|
+
|
|
41
|
+
// Try to import and initialize the ApplicationService
|
|
42
|
+
const { ApplicationService } = await import(
|
|
43
|
+
'@entro314labs/ai-changelog-generator/src/application/services/application.service.js'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
const workspaceFolders = vscode.workspace.workspaceFolders
|
|
47
|
+
if (!workspaceFolders) {
|
|
48
|
+
throw new Error('No workspace folder open')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const appService = new ApplicationService({
|
|
52
|
+
configManager: configManager,
|
|
53
|
+
cwd: workspaceFolders[0].uri.fsPath,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
progress.report({ increment: 40, message: 'Testing AI provider...' })
|
|
57
|
+
|
|
58
|
+
// This will test if the provider can be initialized
|
|
59
|
+
// For a real test, we'd need to make a small API call
|
|
60
|
+
StatusService.log(`✓ ${provider} provider initialized successfully`)
|
|
61
|
+
|
|
62
|
+
vscode.window.showInformationMessage(
|
|
63
|
+
`✅ Connection to ${provider} successful!\n\nProvider is configured and ready to use.`,
|
|
64
|
+
'View Details'
|
|
65
|
+
).then((action) => {
|
|
66
|
+
if (action === 'View Details') {
|
|
67
|
+
vscode.commands.executeCommand('ai-changelog.showStatus')
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
StatusService.log(`Connection test passed for ${provider}`)
|
|
72
|
+
} catch (error) {
|
|
73
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
74
|
+
StatusService.log(`✗ Connection test failed: ${errorMessage}`)
|
|
75
|
+
|
|
76
|
+
const action = await vscode.window.showErrorMessage(
|
|
77
|
+
`❌ Connection to ${provider} failed:\n\n${errorMessage}`,
|
|
78
|
+
'View Logs',
|
|
79
|
+
'Reconfigure',
|
|
80
|
+
'Check Status'
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if (action === 'View Logs') {
|
|
84
|
+
vscode.commands.executeCommand('ai-changelog.showLogs')
|
|
85
|
+
} else if (action === 'Reconfigure') {
|
|
86
|
+
vscode.commands.executeCommand('ai-changelog.setup')
|
|
87
|
+
} else if (action === 'Check Status') {
|
|
88
|
+
vscode.commands.executeCommand('ai-changelog.showStatus')
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
}
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import * as vscode from 'vscode'
|
|
2
|
+
import { CommitSidebarProvider } from './views/CommitSidebarProvider'
|
|
3
|
+
import { ReleaseSidebarProvider } from './views/ReleaseSidebarProvider'
|
|
4
|
+
import { SettingsPanelProvider } from './views/SettingsPanelProvider'
|
|
5
|
+
import { OnboardingPanelProvider } from './views/OnboardingPanelProvider'
|
|
6
|
+
import { ExtensionConfigurationManager } from './services/ExtensionConfigurationManager'
|
|
7
|
+
import { EnvFileService } from './services/EnvFileService'
|
|
8
|
+
import { StatusService } from './services/StatusService'
|
|
9
|
+
import { configureProviderCommand } from './commands/configureProvider'
|
|
10
|
+
import { setupWizard } from './commands/setupWizard'
|
|
11
|
+
import { testConnection } from './commands/testConnection'
|
|
12
|
+
|
|
13
|
+
export async function activate(context: vscode.ExtensionContext) {
|
|
14
|
+
console.log('AI Changelog Generator extension is activating...')
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Initialize StatusService first
|
|
18
|
+
StatusService.initialize(context)
|
|
19
|
+
StatusService.log('Extension activation started')
|
|
20
|
+
|
|
21
|
+
// Initialize configuration manager
|
|
22
|
+
const configManager = new ExtensionConfigurationManager(context.secrets)
|
|
23
|
+
|
|
24
|
+
// Check if setup is complete
|
|
25
|
+
const setupComplete = configManager.isSetupComplete()
|
|
26
|
+
StatusService.log(`Setup complete: ${setupComplete}`)
|
|
27
|
+
|
|
28
|
+
if (!setupComplete) {
|
|
29
|
+
// Update status bar
|
|
30
|
+
StatusService.updateStatus(configManager)
|
|
31
|
+
|
|
32
|
+
// Show onboarding panel
|
|
33
|
+
StatusService.log('Opening onboarding panel...')
|
|
34
|
+
OnboardingPanelProvider.createOrShow(context.extensionUri, configManager)
|
|
35
|
+
} else {
|
|
36
|
+
// Load configuration
|
|
37
|
+
await configManager.initialize()
|
|
38
|
+
StatusService.log('Configuration loaded successfully')
|
|
39
|
+
|
|
40
|
+
// Update status bar
|
|
41
|
+
StatusService.updateStatus(configManager)
|
|
42
|
+
|
|
43
|
+
// Auto-detect environment variables if enabled
|
|
44
|
+
const wsConfig = vscode.workspace.getConfiguration('aiChangelog')
|
|
45
|
+
const autoDetect = wsConfig.get<boolean>('autoDetectEnv', true)
|
|
46
|
+
const storageMode = configManager.getStorageMode()
|
|
47
|
+
|
|
48
|
+
if (autoDetect && storageMode !== 'env') {
|
|
49
|
+
const hasEnvVars = await EnvFileService.hasEnvVars()
|
|
50
|
+
if (hasEnvVars) {
|
|
51
|
+
StatusService.log('Env vars detected, asking user...')
|
|
52
|
+
const useEnv = await vscode.window.showInformationMessage(
|
|
53
|
+
'🔍 Detected API keys in .env files. Would you like to use them?',
|
|
54
|
+
'Use .env',
|
|
55
|
+
'Keep Current',
|
|
56
|
+
"Don't Ask Again"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
if (useEnv === 'Use .env') {
|
|
60
|
+
StatusService.log('Switching to .env storage mode')
|
|
61
|
+
await wsConfig.update('storageMode', 'env', vscode.ConfigurationTarget.Workspace)
|
|
62
|
+
await configManager.initialize() // Reload with env vars
|
|
63
|
+
StatusService.updateStatus(configManager)
|
|
64
|
+
vscode.window.showInformationMessage('✅ Now using API keys from .env file')
|
|
65
|
+
} else if (useEnv === "Don't Ask Again") {
|
|
66
|
+
StatusService.log('User disabled auto-detect')
|
|
67
|
+
await wsConfig.update('autoDetectEnv', false, vscode.ConfigurationTarget.Workspace)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('Configuration manager initialized')
|
|
74
|
+
StatusService.log('Registering commands...')
|
|
75
|
+
|
|
76
|
+
// Register Settings Panel Provider
|
|
77
|
+
const settingsProvider = new SettingsPanelProvider(context.extensionUri, configManager)
|
|
78
|
+
context.subscriptions.push(
|
|
79
|
+
vscode.window.registerWebviewViewProvider(
|
|
80
|
+
SettingsPanelProvider.viewType,
|
|
81
|
+
settingsProvider
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
StatusService.log('Settings panel provider registered')
|
|
85
|
+
|
|
86
|
+
// Register all commands
|
|
87
|
+
context.subscriptions.push(
|
|
88
|
+
vscode.commands.registerCommand('ai-changelog.setup', async () => {
|
|
89
|
+
StatusService.log('Setup command invoked - opening onboarding panel')
|
|
90
|
+
OnboardingPanelProvider.createOrShow(context.extensionUri, configManager)
|
|
91
|
+
})
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
context.subscriptions.push(
|
|
95
|
+
vscode.commands.registerCommand('ai-changelog.testConnection', async () => {
|
|
96
|
+
StatusService.log('Test connection command invoked')
|
|
97
|
+
await testConnection(configManager)
|
|
98
|
+
})
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
context.subscriptions.push(
|
|
102
|
+
vscode.commands.registerCommand('ai-changelog.showStatus', async () => {
|
|
103
|
+
StatusService.log('Show status command invoked')
|
|
104
|
+
await StatusService.showStatusReport(configManager)
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
context.subscriptions.push(
|
|
109
|
+
vscode.commands.registerCommand('ai-changelog.showLogs', () => {
|
|
110
|
+
StatusService.log('Show logs command invoked')
|
|
111
|
+
StatusService.showOutputChannel()
|
|
112
|
+
})
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
context.subscriptions.push(
|
|
116
|
+
vscode.commands.registerCommand('ai-changelog.detectEnv', async () => {
|
|
117
|
+
StatusService.log('Detect env command invoked')
|
|
118
|
+
const envVars = await EnvFileService.detectEnvironmentVariables()
|
|
119
|
+
if (Object.keys(envVars).length === 0) {
|
|
120
|
+
vscode.window.showInformationMessage('No API keys found in .env files')
|
|
121
|
+
StatusService.log('No env vars found')
|
|
122
|
+
} else {
|
|
123
|
+
const keys = Object.keys(envVars).join(', ')
|
|
124
|
+
vscode.window.showInformationMessage(`Found keys: ${keys}`)
|
|
125
|
+
StatusService.log(`Found env vars: ${keys}`)
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
context.subscriptions.push(
|
|
131
|
+
vscode.commands.registerCommand('ai-changelog.configure', () => {
|
|
132
|
+
StatusService.log('Configure provider command invoked')
|
|
133
|
+
configureProviderCommand(configManager)
|
|
134
|
+
})
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
// Listen for configuration changes and provide immediate feedback
|
|
138
|
+
context.subscriptions.push(
|
|
139
|
+
vscode.workspace.onDidChangeConfiguration(async (e) => {
|
|
140
|
+
if (e.affectsConfiguration('aiChangelog')) {
|
|
141
|
+
StatusService.log('Configuration changed, validating...')
|
|
142
|
+
|
|
143
|
+
// Reinitialize config manager
|
|
144
|
+
await configManager.initialize()
|
|
145
|
+
|
|
146
|
+
// Update status bar
|
|
147
|
+
StatusService.updateStatus(configManager)
|
|
148
|
+
|
|
149
|
+
// Validate provider changes
|
|
150
|
+
if (e.affectsConfiguration('aiChangelog.provider')) {
|
|
151
|
+
const provider = vscode.workspace.getConfiguration('aiChangelog').get<string>('provider')
|
|
152
|
+
StatusService.log(`Provider changed to: ${provider}`)
|
|
153
|
+
|
|
154
|
+
const hasKey = await configManager.hasApiKey(provider || 'openai')
|
|
155
|
+
if (!hasKey && provider !== 'ollama' && provider !== 'lmstudio') {
|
|
156
|
+
vscode.window.showWarningMessage(
|
|
157
|
+
`⚠️ Provider changed to ${provider} but no API key is configured.`,
|
|
158
|
+
'Open Settings'
|
|
159
|
+
).then((action) => {
|
|
160
|
+
if (action === 'Open Settings') {
|
|
161
|
+
vscode.commands.executeCommand('ai-changelog-settings-view.focus')
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
} else {
|
|
165
|
+
vscode.window.showInformationMessage(`✅ Provider set to ${provider}`)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validate storage mode changes
|
|
170
|
+
if (e.affectsConfiguration('aiChangelog.storageMode')) {
|
|
171
|
+
const mode = vscode.workspace.getConfiguration('aiChangelog').get<string>('storageMode')
|
|
172
|
+
StatusService.log(`Storage mode changed to: ${mode}`)
|
|
173
|
+
|
|
174
|
+
if (mode === 'env') {
|
|
175
|
+
const envVars = await EnvFileService.detectEnvironmentVariables()
|
|
176
|
+
if (Object.keys(envVars).length === 0) {
|
|
177
|
+
vscode.window.showWarningMessage(
|
|
178
|
+
'⚠️ Storage mode set to .env but no .env file found. Create .env.local in workspace root.'
|
|
179
|
+
)
|
|
180
|
+
} else {
|
|
181
|
+
vscode.window.showInformationMessage(
|
|
182
|
+
`✅ Found ${Object.keys(envVars).length} API key(s) in .env file`
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
vscode.window.showInformationMessage(`✅ Storage mode set to ${mode}`)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
StatusService.log('Configuration validation complete')
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Register the Commit Sidebar Provider
|
|
196
|
+
const sidebarProvider = new CommitSidebarProvider(context.extensionUri, configManager)
|
|
197
|
+
context.subscriptions.push(
|
|
198
|
+
vscode.window.registerWebviewViewProvider('ai-changelog-commit-view', sidebarProvider)
|
|
199
|
+
)
|
|
200
|
+
StatusService.log('Commit sidebar provider registered')
|
|
201
|
+
|
|
202
|
+
// Register Release Provider
|
|
203
|
+
const releaseProvider = new ReleaseSidebarProvider(context.extensionUri, configManager)
|
|
204
|
+
context.subscriptions.push(
|
|
205
|
+
vscode.window.registerWebviewViewProvider('ai-changelog-release-view', releaseProvider)
|
|
206
|
+
)
|
|
207
|
+
StatusService.log('Release sidebar provider registered')
|
|
208
|
+
|
|
209
|
+
// Register Commands
|
|
210
|
+
context.subscriptions.push(
|
|
211
|
+
vscode.commands.registerCommand('ai-changelog.generateCommit', async () => {
|
|
212
|
+
StatusService.log('Generate commit command invoked')
|
|
213
|
+
if (!configManager.isSetupComplete()) {
|
|
214
|
+
StatusService.log('Setup not complete, prompting user')
|
|
215
|
+
const runSetup = await vscode.window.showWarningMessage(
|
|
216
|
+
'AI Changelog Generator is not set up yet. Would you like to run the setup wizard?',
|
|
217
|
+
'Setup Now',
|
|
218
|
+
'Cancel'
|
|
219
|
+
)
|
|
220
|
+
if (runSetup === 'Setup Now') {
|
|
221
|
+
await vscode.commands.executeCommand('ai-changelog.setup')
|
|
222
|
+
}
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
await vscode.commands.executeCommand('ai-changelog-commit-view.focus')
|
|
226
|
+
})
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
context.subscriptions.push(
|
|
230
|
+
vscode.commands.registerCommand('ai-changelog.generateRelease', async () => {
|
|
231
|
+
StatusService.log('Generate release command invoked')
|
|
232
|
+
if (!configManager.isSetupComplete()) {
|
|
233
|
+
StatusService.log('Setup not complete, prompting user')
|
|
234
|
+
const runSetup = await vscode.window.showWarningMessage(
|
|
235
|
+
'AI Changelog Generator is not set up yet. Would you like to run the setup wizard?',
|
|
236
|
+
'Setup Now',
|
|
237
|
+
'Cancel'
|
|
238
|
+
)
|
|
239
|
+
if (runSetup === 'Setup Now') {
|
|
240
|
+
await vscode.commands.executeCommand('ai-changelog.setup')
|
|
241
|
+
}
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
await vscode.commands.executeCommand('ai-changelog-release-view.focus')
|
|
245
|
+
})
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
console.log('AI Changelog Generator extension is now active!')
|
|
249
|
+
StatusService.log('Extension activated successfully')
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
252
|
+
console.error('Failed to activate AI Changelog Generator extension:', errorMessage)
|
|
253
|
+
StatusService.log(`✗ Extension activation failed: ${errorMessage}`)
|
|
254
|
+
vscode.window.showErrorMessage(
|
|
255
|
+
`AI Changelog Generator failed to activate: ${errorMessage}`
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function deactivate() {
|
|
261
|
+
console.log('AI Changelog Generator extension is deactivating...')
|
|
262
|
+
StatusService.log('Extension deactivating')
|
|
263
|
+
StatusService.dispose()
|
|
264
|
+
}
|