promptarchitect 0.6.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.
@@ -0,0 +1,822 @@
1
+ /**
2
+ * PromptArchitect VS Code Extension
3
+ *
4
+ * AI-powered prompt engineering directly in your editor.
5
+ * Requires authentication for continued use.
6
+ */
7
+
8
+ import * as vscode from 'vscode';
9
+ import { PromptArchitectAPI } from './api';
10
+ import { TemplateQuickPick } from './templates';
11
+ import { RefinerPanel } from './refinerPanel';
12
+ import { ChatPanel } from './chatPanel';
13
+ import { WorkspaceIndexer } from './workspaceIndexer';
14
+ import { AuthService } from './authService';
15
+ import { AgentService } from './agentService';
16
+ import {
17
+ ScriptsTreeProvider,
18
+ QuickAccessTreeProvider,
19
+ EnvironmentTreeProvider,
20
+ NotesTreeProvider,
21
+ AIChatViewProvider,
22
+ } from './providers';
23
+
24
+ let api: PromptArchitectAPI;
25
+ let authService: AuthService;
26
+ let agentService: AgentService;
27
+ let statusBarItem: vscode.StatusBarItem;
28
+ let authStatusBarItem: vscode.StatusBarItem;
29
+ let workspaceIndexer: WorkspaceIndexer;
30
+ let selectionDebounce: NodeJS.Timeout | undefined;
31
+
32
+ // Tree providers
33
+ let scriptsProvider: ScriptsTreeProvider;
34
+ let quickAccessProvider: QuickAccessTreeProvider;
35
+ let environmentProvider: EnvironmentTreeProvider;
36
+ let notesProvider: NotesTreeProvider;
37
+ let aiChatProvider: AIChatViewProvider;
38
+
39
+ export function activate(context: vscode.ExtensionContext) {
40
+ console.log('PromptArchitect extension activated');
41
+
42
+ // Initialize API client
43
+ const config = vscode.workspace.getConfiguration('promptarchitect');
44
+ const endpoint = config.get<string>('apiEndpoint') || 'https://us-central1-prompt-architect-3df7a.cloudfunctions.net/api';
45
+ api = new PromptArchitectAPI(endpoint);
46
+
47
+ // Initialize auth service
48
+ authService = AuthService.getInstance(context, endpoint);
49
+ context.subscriptions.push(authService);
50
+
51
+ // Set up auth token on API when session changes
52
+ authService.onDidChangeAuth(async (isAuthenticated) => {
53
+ if (isAuthenticated) {
54
+ const token = await authService.getAccessToken();
55
+ api.setAccessToken(token);
56
+ } else {
57
+ api.setAccessToken(null);
58
+ }
59
+ updateAuthStatusBar(isAuthenticated);
60
+ });
61
+
62
+ // Check auth status on startup and set token
63
+ initializeAuth(context);
64
+
65
+ // Initialize workspace indexer
66
+ workspaceIndexer = new WorkspaceIndexer(context);
67
+ workspaceIndexer.showStatusBar();
68
+ context.subscriptions.push(workspaceIndexer);
69
+
70
+ // Initialize agent service
71
+ agentService = AgentService.getInstance(context, api, workspaceIndexer);
72
+
73
+ // Set up proactive selection monitoring
74
+ setupProactiveFeatures(context);
75
+
76
+ // Initialize tree providers
77
+ scriptsProvider = new ScriptsTreeProvider(context);
78
+ quickAccessProvider = new QuickAccessTreeProvider(context);
79
+ environmentProvider = new EnvironmentTreeProvider(context);
80
+ notesProvider = new NotesTreeProvider(context);
81
+ aiChatProvider = new AIChatViewProvider(context, api);
82
+
83
+ // Register tree views
84
+ context.subscriptions.push(
85
+ vscode.window.registerTreeDataProvider('promptarchitect.scripts', scriptsProvider),
86
+ vscode.window.registerTreeDataProvider('promptarchitect.quickAccess', quickAccessProvider),
87
+ vscode.window.registerTreeDataProvider('promptarchitect.environment', environmentProvider),
88
+ vscode.window.registerTreeDataProvider('promptarchitect.notes', notesProvider),
89
+ vscode.window.registerWebviewViewProvider(AIChatViewProvider.viewType, aiChatProvider)
90
+ );
91
+
92
+ // Create main status bar item
93
+ if (config.get<boolean>('showStatusBar')) {
94
+ statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
95
+ statusBarItem.text = '$(rocket) PromptArchitect';
96
+ statusBarItem.tooltip = 'Click to open Project Command Center';
97
+ statusBarItem.command = 'promptarchitect.openProjectHub';
98
+ statusBarItem.show();
99
+ context.subscriptions.push(statusBarItem);
100
+ }
101
+
102
+ // Create auth status bar item
103
+ authStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 99);
104
+ authStatusBarItem.command = 'promptarchitect.manageAccount';
105
+ context.subscriptions.push(authStatusBarItem);
106
+
107
+ // Register original commands
108
+ context.subscriptions.push(
109
+ vscode.commands.registerCommand('promptarchitect.generatePrompt', generatePromptCommand),
110
+ vscode.commands.registerCommand('promptarchitect.refinePrompt', refinePromptCommand),
111
+ vscode.commands.registerCommand('promptarchitect.analyzePrompt', analyzePromptCommand),
112
+ vscode.commands.registerCommand('promptarchitect.showTemplates', showTemplatesCommand),
113
+ vscode.commands.registerCommand('promptarchitect.refineForChat', refineForChatCommand),
114
+ vscode.commands.registerCommand('promptarchitect.quickRefine', quickRefineCommand),
115
+ vscode.commands.registerCommand('promptarchitect.openChat', openChatCommand),
116
+ vscode.commands.registerCommand('promptarchitect.indexWorkspace', indexWorkspaceCommand),
117
+ vscode.commands.registerCommand('promptarchitect.clearWorkspaceIndex', clearWorkspaceIndexCommand),
118
+ // Auth commands
119
+ vscode.commands.registerCommand('promptarchitect.signIn', signInCommand),
120
+ vscode.commands.registerCommand('promptarchitect.signOut', signOutCommand),
121
+ vscode.commands.registerCommand('promptarchitect.manageAccount', manageAccountCommand)
122
+ );
123
+
124
+ // Register Project Hub commands
125
+ context.subscriptions.push(
126
+ // Scripts commands
127
+ vscode.commands.registerCommand('promptarchitect.refreshScripts', () => scriptsProvider.refresh()),
128
+ vscode.commands.registerCommand('promptarchitect.addCustomScript', () => scriptsProvider.addCustomScript()),
129
+ vscode.commands.registerCommand('promptarchitect.runScript', (item) => scriptsProvider.runScript(item)),
130
+ vscode.commands.registerCommand('promptarchitect.stopScript', (item) => scriptsProvider.stopScript(item)),
131
+
132
+ // Quick Access commands
133
+ vscode.commands.registerCommand('promptarchitect.pinCurrentFile', () => quickAccessProvider.pinCurrentFile()),
134
+ vscode.commands.registerCommand('promptarchitect.unpinFile', (item) => quickAccessProvider.unpinFile(item)),
135
+ vscode.commands.registerCommand('promptarchitect.openQuickAccessFile', (item) => quickAccessProvider.openFile(item)),
136
+
137
+ // Environment commands
138
+ vscode.commands.registerCommand('promptarchitect.refreshEnv', () => environmentProvider.refresh()),
139
+ vscode.commands.registerCommand('promptarchitect.createEnvFile', () => environmentProvider.createEnvFile()),
140
+ vscode.commands.registerCommand('promptarchitect.copyEnvValue', (item) => environmentProvider.copyValue(item)),
141
+ vscode.commands.registerCommand('promptarchitect.openEnvFile', (item) => environmentProvider.openEnvFile(item)),
142
+
143
+ // Notes commands
144
+ vscode.commands.registerCommand('promptarchitect.addNote', () => notesProvider.addNote()),
145
+ vscode.commands.registerCommand('promptarchitect.toggleNote', (item) => notesProvider.toggleNote(item)),
146
+ vscode.commands.registerCommand('promptarchitect.deleteNote', (item) => notesProvider.deleteNote(item)),
147
+
148
+ // Project Hub command
149
+ vscode.commands.registerCommand('promptarchitect.openProjectHub', openProjectHubCommand)
150
+ );
151
+
152
+ // Show welcome message on first install
153
+ const hasShownWelcome = context.globalState.get('hasShownWelcome');
154
+ if (!hasShownWelcome) {
155
+ showWelcomeMessage();
156
+ context.globalState.update('hasShownWelcome', true);
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Initialize authentication on startup
162
+ */
163
+ async function initializeAuth(context: vscode.ExtensionContext) {
164
+ const isAuthenticated = await authService.isAuthenticated();
165
+
166
+ if (isAuthenticated) {
167
+ // Set the access token for API requests
168
+ const token = await authService.getAccessToken();
169
+ api.setAccessToken(token);
170
+ updateAuthStatusBar(true);
171
+ } else {
172
+ updateAuthStatusBar(false);
173
+ // Prompt existing users to sign in
174
+ const hasUsedBefore = context.globalState.get('hasUsedBefore');
175
+ if (hasUsedBefore) {
176
+ // This is an existing user who needs to sign in
177
+ setTimeout(() => {
178
+ showAuthRequiredMessage();
179
+ }, 2000);
180
+ }
181
+ }
182
+
183
+ // Mark that the extension has been used
184
+ await context.globalState.update('hasUsedBefore', true);
185
+ }
186
+
187
+ /**
188
+ * Update auth status bar
189
+ */
190
+ function updateAuthStatusBar(isAuthenticated: boolean) {
191
+ if (!authStatusBarItem) return;
192
+
193
+ if (isAuthenticated) {
194
+ authService.getCurrentUser().then((user) => {
195
+ if (user) {
196
+ authStatusBarItem.text = `$(account) ${user.displayName}`;
197
+ authStatusBarItem.tooltip = `Signed in as ${user.email}\nClick to manage account`;
198
+ } else {
199
+ authStatusBarItem.text = '$(account) Signed In';
200
+ authStatusBarItem.tooltip = 'Click to manage account';
201
+ }
202
+ });
203
+ } else {
204
+ authStatusBarItem.text = '$(sign-in) Sign In';
205
+ authStatusBarItem.tooltip = 'Sign in to use PromptArchitect';
206
+ }
207
+ authStatusBarItem.show();
208
+ }
209
+
210
+ /**
211
+ * Show auth required message for existing users
212
+ */
213
+ async function showAuthRequiredMessage() {
214
+ const result = await vscode.window.showWarningMessage(
215
+ '🔐 PromptArchitect now requires sign-in. Please sign in or create an account to continue using the extension.',
216
+ { modal: false },
217
+ 'Sign In',
218
+ 'Create Account',
219
+ 'Learn More'
220
+ );
221
+
222
+ if (result === 'Sign In' || result === 'Create Account') {
223
+ await authService.signIn();
224
+ } else if (result === 'Learn More') {
225
+ vscode.env.openExternal(vscode.Uri.parse('https://promptarchitectlabs.com/auth'));
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Sign in command
231
+ */
232
+ async function signInCommand() {
233
+ await authService.signIn();
234
+ }
235
+
236
+ /**
237
+ * Sign out command
238
+ */
239
+ async function signOutCommand() {
240
+ await authService.signOut();
241
+ }
242
+
243
+ /**
244
+ * Manage account command
245
+ */
246
+ async function manageAccountCommand() {
247
+ const isAuthenticated = await authService.isAuthenticated();
248
+
249
+ if (!isAuthenticated) {
250
+ await authService.signIn();
251
+ return;
252
+ }
253
+
254
+ const user = await authService.getCurrentUser();
255
+ const choice = await vscode.window.showQuickPick(
256
+ [
257
+ { label: '$(account) ' + (user?.displayName || 'Account'), description: user?.email, kind: vscode.QuickPickItemKind.Default },
258
+ { label: '', kind: vscode.QuickPickItemKind.Separator },
259
+ { label: '$(gear) Account Settings', value: 'settings' },
260
+ { label: '$(history) Usage History', value: 'usage' },
261
+ { label: '$(sign-out) Sign Out', value: 'signout' },
262
+ ],
263
+ {
264
+ placeHolder: 'Manage your PromptArchitect account',
265
+ }
266
+ );
267
+
268
+ if ((choice as any)?.value === 'signout') {
269
+ await authService.signOut();
270
+ } else if ((choice as any)?.value === 'settings') {
271
+ vscode.env.openExternal(vscode.Uri.parse('https://promptarchitectlabs.com/settings'));
272
+ } else if ((choice as any)?.value === 'usage') {
273
+ vscode.env.openExternal(vscode.Uri.parse('https://promptarchitectlabs.com/usage'));
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Check if user is authenticated, prompt if not
279
+ * Returns true if authenticated, false if user declined
280
+ */
281
+ async function requireAuth(): Promise<boolean> {
282
+ return authService.requireAuth();
283
+ }
284
+
285
+ export function deactivate() {
286
+ console.log('PromptArchitect extension deactivated');
287
+ }
288
+
289
+ /**
290
+ * Generate a prompt from an idea
291
+ */
292
+ async function generatePromptCommand() {
293
+ // Require authentication
294
+ if (!await requireAuth()) {
295
+ return;
296
+ }
297
+
298
+ const config = vscode.workspace.getConfiguration('promptarchitect');
299
+ const defaultTemplate = config.get<string>('defaultTemplate') || 'general';
300
+ const targetModel = config.get<string>('targetModel') || 'general';
301
+
302
+ // Get idea from user
303
+ const idea = await vscode.window.showInputBox({
304
+ prompt: 'Enter your idea or concept',
305
+ placeHolder: 'e.g., Write a function to parse JSON with error handling',
306
+ ignoreFocusOut: true,
307
+ });
308
+
309
+ if (!idea) {
310
+ return;
311
+ }
312
+
313
+ // Ask for template (quick pick)
314
+ const template = await vscode.window.showQuickPick(
315
+ [
316
+ { label: '$(code) Coding', value: 'coding', description: 'Programming & development' },
317
+ { label: '$(book) Writing', value: 'writing', description: 'Content creation' },
318
+ { label: '$(search) Research', value: 'research', description: 'Investigation & discovery' },
319
+ { label: '$(graph) Analysis', value: 'analysis', description: 'Data & business analysis' },
320
+ { label: '$(verified) Fact Check', value: 'factcheck', description: 'Verification & validation' },
321
+ { label: '$(globe) General', value: 'general', description: 'General-purpose' },
322
+ ],
323
+ {
324
+ placeHolder: 'Select a template (or press Enter for default)',
325
+ title: 'PromptArchitect - Choose Template',
326
+ }
327
+ );
328
+
329
+ const selectedTemplate = template?.value || defaultTemplate;
330
+
331
+ // Show progress
332
+ await vscode.window.withProgress(
333
+ {
334
+ location: vscode.ProgressLocation.Notification,
335
+ title: 'PromptArchitect',
336
+ cancellable: false,
337
+ },
338
+ async (progress) => {
339
+ progress.report({ message: 'Generating prompt...' });
340
+
341
+ try {
342
+ const result = await api.generatePrompt({
343
+ idea,
344
+ template: selectedTemplate,
345
+ targetModel,
346
+ });
347
+
348
+ // Show result in new document
349
+ const doc = await vscode.workspace.openTextDocument({
350
+ content: result.prompt,
351
+ language: 'markdown',
352
+ });
353
+ await vscode.window.showTextDocument(doc, { preview: false });
354
+
355
+ // Show success message with metadata
356
+ vscode.window.showInformationMessage(
357
+ `✨ Prompt generated! Template: ${selectedTemplate}, Target: ${targetModel}`
358
+ );
359
+ } catch (error) {
360
+ vscode.window.showErrorMessage(`Failed to generate prompt: ${error}`);
361
+ }
362
+ }
363
+ );
364
+ }
365
+
366
+ /**
367
+ * Refine a selected prompt
368
+ */
369
+ async function refinePromptCommand() {
370
+ // Require authentication
371
+ if (!await requireAuth()) {
372
+ return;
373
+ }
374
+
375
+ const editor = vscode.window.activeTextEditor;
376
+ if (!editor) {
377
+ vscode.window.showWarningMessage('No active editor');
378
+ return;
379
+ }
380
+
381
+ const selection = editor.selection;
382
+ const selectedText = editor.document.getText(selection);
383
+
384
+ if (!selectedText) {
385
+ vscode.window.showWarningMessage('Please select some text to refine');
386
+ return;
387
+ }
388
+
389
+ // Get feedback from user
390
+ const feedback = await vscode.window.showInputBox({
391
+ prompt: 'How should this prompt be improved?',
392
+ placeHolder: 'e.g., Make it more specific, add error handling requirements',
393
+ ignoreFocusOut: true,
394
+ });
395
+
396
+ if (!feedback) {
397
+ return;
398
+ }
399
+
400
+ const config = vscode.workspace.getConfiguration('promptarchitect');
401
+ const targetModel = config.get<string>('targetModel') || 'general';
402
+
403
+ await vscode.window.withProgress(
404
+ {
405
+ location: vscode.ProgressLocation.Notification,
406
+ title: 'PromptArchitect',
407
+ cancellable: false,
408
+ },
409
+ async (progress) => {
410
+ progress.report({ message: 'Refining prompt...' });
411
+
412
+ try {
413
+ const result = await api.refinePrompt({
414
+ prompt: selectedText,
415
+ feedback,
416
+ targetModel,
417
+ });
418
+
419
+ // Replace selection with refined prompt
420
+ await editor.edit((editBuilder) => {
421
+ editBuilder.replace(selection, result.refinedPrompt);
422
+ });
423
+
424
+ vscode.window.showInformationMessage('✨ Prompt refined successfully!');
425
+ } catch (error) {
426
+ vscode.window.showErrorMessage(`Failed to refine prompt: ${error}`);
427
+ }
428
+ }
429
+ );
430
+ }
431
+
432
+ /**
433
+ * Analyze prompt quality
434
+ */
435
+ async function analyzePromptCommand() {
436
+ // Require authentication
437
+ if (!await requireAuth()) {
438
+ return;
439
+ }
440
+
441
+ const editor = vscode.window.activeTextEditor;
442
+ let promptText = '';
443
+
444
+ if (editor && !editor.selection.isEmpty) {
445
+ promptText = editor.document.getText(editor.selection);
446
+ } else {
447
+ // Ask for prompt input
448
+ const input = await vscode.window.showInputBox({
449
+ prompt: 'Enter the prompt to analyze',
450
+ placeHolder: 'Paste your prompt here...',
451
+ ignoreFocusOut: true,
452
+ });
453
+ if (!input) return;
454
+ promptText = input;
455
+ }
456
+
457
+ await vscode.window.withProgress(
458
+ {
459
+ location: vscode.ProgressLocation.Notification,
460
+ title: 'PromptArchitect',
461
+ cancellable: false,
462
+ },
463
+ async (progress) => {
464
+ progress.report({ message: 'Analyzing prompt...' });
465
+
466
+ try {
467
+ const result = await api.analyzePrompt({ prompt: promptText });
468
+
469
+ // Format analysis as markdown
470
+ const analysis = `# Prompt Analysis
471
+
472
+ ## Scores
473
+ | Metric | Score |
474
+ |--------|-------|
475
+ | Clarity | ${result.scores.clarity}/100 |
476
+ | Specificity | ${result.scores.specificity}/100 |
477
+ | Structure | ${result.scores.structure}/100 |
478
+ | Actionability | ${result.scores.actionability}/100 |
479
+ | **Overall** | **${result.overallScore}/100** |
480
+
481
+ ## Strengths
482
+ ${result.strengths.map((s: string) => `- ✅ ${s}`).join('\n')}
483
+
484
+ ## Suggestions
485
+ ${result.suggestions.map((s: string) => `- 💡 ${s}`).join('\n')}
486
+
487
+ ---
488
+ *Analyzed by PromptArchitect*
489
+ `;
490
+
491
+ // Show in new document
492
+ const doc = await vscode.workspace.openTextDocument({
493
+ content: analysis,
494
+ language: 'markdown',
495
+ });
496
+ await vscode.window.showTextDocument(doc, {
497
+ preview: true,
498
+ viewColumn: vscode.ViewColumn.Beside,
499
+ });
500
+ } catch (error) {
501
+ vscode.window.showErrorMessage(`Failed to analyze prompt: ${error}`);
502
+ }
503
+ }
504
+ );
505
+ }
506
+
507
+ /**
508
+ * Show template browser
509
+ */
510
+ async function showTemplatesCommand() {
511
+ const templates = [
512
+ {
513
+ label: '$(code) Coding Template',
514
+ detail: 'Structured for programming tasks with context, requirements, and constraints',
515
+ value: 'coding',
516
+ },
517
+ {
518
+ label: '$(book) Writing Template',
519
+ detail: 'Optimized for content creation with tone, audience, and style guidance',
520
+ value: 'writing',
521
+ },
522
+ {
523
+ label: '$(search) Research Template',
524
+ detail: 'Designed for investigation with sources, methodology, and output format',
525
+ value: 'research',
526
+ },
527
+ {
528
+ label: '$(graph) Analysis Template',
529
+ detail: 'Structured for data analysis with metrics, comparisons, and recommendations',
530
+ value: 'analysis',
531
+ },
532
+ {
533
+ label: '$(verified) Fact Check Template',
534
+ detail: 'Optimized for verification with claims, sources, and confidence levels',
535
+ value: 'factcheck',
536
+ },
537
+ {
538
+ label: '$(globe) General Template',
539
+ detail: 'Versatile template for any task type',
540
+ value: 'general',
541
+ },
542
+ ];
543
+
544
+ const selected = await vscode.window.showQuickPick(templates, {
545
+ placeHolder: 'Select a template to use',
546
+ title: 'PromptArchitect Templates',
547
+ });
548
+
549
+ if (selected) {
550
+ // Update default template setting
551
+ const config = vscode.workspace.getConfiguration('promptarchitect');
552
+ await config.update('defaultTemplate', selected.value, vscode.ConfigurationTarget.Global);
553
+
554
+ vscode.window.showInformationMessage(
555
+ `Default template set to: ${selected.label.replace(/\$\([^)]+\)\s*/, '')}`
556
+ );
557
+
558
+ // Optionally trigger generate with this template
559
+ const generate = await vscode.window.showQuickPick(['Yes', 'No'], {
560
+ placeHolder: 'Generate a prompt with this template now?',
561
+ });
562
+
563
+ if (generate === 'Yes') {
564
+ vscode.commands.executeCommand('promptarchitect.generatePrompt');
565
+ }
566
+ }
567
+ }
568
+
569
+ /**
570
+ * Open the Refiner Panel for interactive prompt refinement
571
+ * This allows users to refine prompts before sending to any AI chat
572
+ */
573
+ async function refineForChatCommand() {
574
+ // Require authentication
575
+ if (!await requireAuth()) {
576
+ return;
577
+ }
578
+
579
+ // Open the refiner panel
580
+ RefinerPanel.createOrShow(api);
581
+
582
+ // If there's selected text, prefill it
583
+ const editor = vscode.window.activeTextEditor;
584
+ if (editor && !editor.selection.isEmpty) {
585
+ const selectedText = editor.document.getText(editor.selection);
586
+ // Small delay to ensure panel is ready
587
+ setTimeout(() => {
588
+ RefinerPanel.prefill(selectedText);
589
+ }, 100);
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Quick refine - instantly refine selected text with default settings
595
+ */
596
+ async function quickRefineCommand() {
597
+ // Require authentication
598
+ if (!await requireAuth()) {
599
+ return;
600
+ }
601
+
602
+ const editor = vscode.window.activeTextEditor;
603
+ if (!editor) {
604
+ vscode.window.showWarningMessage('No active editor');
605
+ return;
606
+ }
607
+
608
+ const selection = editor.selection;
609
+ const selectedText = editor.document.getText(selection);
610
+
611
+ if (!selectedText) {
612
+ vscode.window.showWarningMessage('Please select some text to refine');
613
+ return;
614
+ }
615
+
616
+ const config = vscode.workspace.getConfiguration('promptarchitect');
617
+ const targetModel = config.get<string>('targetModel') || 'general';
618
+
619
+ await vscode.window.withProgress(
620
+ {
621
+ location: vscode.ProgressLocation.Notification,
622
+ title: 'PromptArchitect',
623
+ cancellable: false,
624
+ },
625
+ async (progress) => {
626
+ progress.report({ message: 'Quick refining...' });
627
+
628
+ try {
629
+ const result = await api.refinePrompt({
630
+ prompt: selectedText,
631
+ feedback: 'Improve clarity, specificity, and structure. Make this prompt more effective for AI assistants.',
632
+ targetModel,
633
+ });
634
+
635
+ // Replace selection with refined prompt
636
+ await editor.edit((editBuilder) => {
637
+ editBuilder.replace(selection, result.refinedPrompt);
638
+ });
639
+
640
+ vscode.window.showInformationMessage('⚡ Quick refined!');
641
+ } catch (error) {
642
+ vscode.window.showErrorMessage(`Failed to refine: ${error}`);
643
+ }
644
+ }
645
+ );
646
+ }
647
+
648
+ /**
649
+ * Open the PromptArchitect Chat Panel
650
+ * Full AI chat interface with built-in prompt refinement
651
+ */
652
+ async function openChatCommand() {
653
+ // Chat does not require authentication for basic usage
654
+ ChatPanel.createOrShow(api);
655
+
656
+ // If there's selected text, prefill it
657
+ const editor = vscode.window.activeTextEditor;
658
+ if (editor && !editor.selection.isEmpty) {
659
+ const selectedText = editor.document.getText(editor.selection);
660
+ setTimeout(() => {
661
+ ChatPanel.prefillPrompt(selectedText);
662
+ }, 100);
663
+ }
664
+ }
665
+
666
+ /**
667
+ * Open the Project Command Center in the Activity Bar
668
+ */
669
+ async function openProjectHubCommand() {
670
+ // Focus on the Project Command Center view container
671
+ await vscode.commands.executeCommand('workbench.view.extension.promptarchitect-hub');
672
+ }
673
+
674
+ /**
675
+ * Index the workspace for better prompt context
676
+ */
677
+ async function indexWorkspaceCommand() {
678
+ await workspaceIndexer.indexWorkspace();
679
+ }
680
+
681
+ /**
682
+ * Clear the workspace index
683
+ */
684
+ async function clearWorkspaceIndexCommand() {
685
+ const confirm = await vscode.window.showWarningMessage(
686
+ 'Clear the workspace index? You can re-index at any time.',
687
+ { modal: true },
688
+ 'Clear Index'
689
+ );
690
+
691
+ if (confirm === 'Clear Index') {
692
+ await workspaceIndexer.clearIndex();
693
+ vscode.window.showInformationMessage('Workspace index cleared');
694
+ }
695
+ }
696
+
697
+ /**
698
+ * Get workspace context for prompt refinement
699
+ */
700
+ export function getWorkspaceContext(): string {
701
+ return workspaceIndexer?.getContextForPrompt() || '';
702
+ }
703
+
704
+ /**
705
+ * Check if workspace has been indexed
706
+ */
707
+ export function hasWorkspaceIndex(): boolean {
708
+ return workspaceIndexer?.hasValidIndex() || false;
709
+ }
710
+
711
+ /**
712
+ * Prompt user to index workspace if not indexed
713
+ */
714
+ export async function promptToIndexWorkspace(): Promise<boolean> {
715
+ if (!workspaceIndexer) return false;
716
+ return workspaceIndexer.promptToIndex();
717
+ }
718
+
719
+ /**
720
+ * Ensure workspace is indexed (automatic, no user interaction)
721
+ * This is used by the autonomous prompt contextualization module
722
+ */
723
+ export async function ensureWorkspaceIndexed(): Promise<boolean> {
724
+ if (!workspaceIndexer) return false;
725
+ return workspaceIndexer.ensureIndexed();
726
+ }
727
+
728
+ /**
729
+ * Show welcome message
730
+ */
731
+ function showWelcomeMessage() {
732
+ vscode.window
733
+ .showInformationMessage(
734
+ '🎉 Welcome to PromptArchitect! Generate, refine, and analyze AI prompts with no API key required.',
735
+ 'Generate Prompt',
736
+ 'Learn More'
737
+ )
738
+ .then((selection) => {
739
+ if (selection === 'Generate Prompt') {
740
+ vscode.commands.executeCommand('promptarchitect.generatePrompt');
741
+ } else if (selection === 'Learn More') {
742
+ vscode.env.openExternal(vscode.Uri.parse('https://promptarchitect.com'));
743
+ }
744
+ });
745
+ }
746
+
747
+ /**
748
+ * Set up proactive features like selection monitoring and auto-suggestions
749
+ */
750
+ function setupProactiveFeatures(context: vscode.ExtensionContext) {
751
+ const config = vscode.workspace.getConfiguration('promptarchitect');
752
+ const proactiveEnabled = config.get<boolean>('proactiveRefine', false);
753
+
754
+ if (!proactiveEnabled) return;
755
+
756
+ // Monitor text selection changes
757
+ context.subscriptions.push(
758
+ vscode.window.onDidChangeTextEditorSelection(async (event) => {
759
+ // Clear previous debounce
760
+ if (selectionDebounce) {
761
+ clearTimeout(selectionDebounce);
762
+ }
763
+
764
+ // Only process if there's a selection
765
+ if (event.selections.length === 0 || event.selections[0].isEmpty) {
766
+ return;
767
+ }
768
+
769
+ // Debounce to avoid too many API calls
770
+ selectionDebounce = setTimeout(async () => {
771
+ try {
772
+ const editor = event.textEditor;
773
+ const selection = editor.selection;
774
+ const selectedText = editor.document.getText(selection);
775
+
776
+ // Only process if selection looks like a prompt (reasonable length)
777
+ if (selectedText.length < 20 || selectedText.length > 1000) {
778
+ return;
779
+ }
780
+
781
+ // Check if it might be a prompt worth refining
782
+ const suggestion = await agentService.getProactiveRefinement();
783
+
784
+ if (suggestion) {
785
+ // Show a subtle notification with the suggestion
786
+ const action = await vscode.window.showInformationMessage(
787
+ `💡 Prompt tip: ${suggestion}`,
788
+ 'Refine Now',
789
+ 'Dismiss'
790
+ );
791
+
792
+ if (action === 'Refine Now') {
793
+ vscode.commands.executeCommand('promptarchitect.quickRefine');
794
+ }
795
+ }
796
+ } catch {
797
+ // Silently ignore errors in proactive features
798
+ }
799
+ }, 1500); // Wait 1.5 seconds after selection stops
800
+ })
801
+ );
802
+
803
+ // Monitor file saves for auto-indexing
804
+ context.subscriptions.push(
805
+ vscode.workspace.onDidSaveTextDocument(async (document) => {
806
+ // Re-index on significant file saves
807
+ const significantFiles = ['package.json', 'tsconfig.json', '.env'];
808
+ const fileName = document.fileName.split(/[\\/]/).pop() || '';
809
+
810
+ if (significantFiles.includes(fileName)) {
811
+ await workspaceIndexer.ensureIndexed();
812
+ }
813
+ })
814
+ );
815
+ }
816
+
817
+ /**
818
+ * Get the agent service instance
819
+ */
820
+ export function getAgentService(): AgentService {
821
+ return agentService;
822
+ }