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.
- package/.vscodeignore +7 -0
- package/CHANGELOG.md +28 -0
- package/LICENSE +44 -0
- package/README.md +200 -0
- package/docs/CHAT_UI_REDESIGN_PLAN.md +371 -0
- package/images/hub-icon.svg +6 -0
- package/images/prompt-lab-icon.svg +11 -0
- package/package.json +519 -0
- package/src/agentPrompts.ts +278 -0
- package/src/agentService.ts +630 -0
- package/src/api.ts +223 -0
- package/src/authService.ts +556 -0
- package/src/chatPanel.ts +979 -0
- package/src/extension.ts +822 -0
- package/src/providers/aiChatViewProvider.ts +1023 -0
- package/src/providers/environmentTreeProvider.ts +311 -0
- package/src/providers/index.ts +9 -0
- package/src/providers/notesTreeProvider.ts +301 -0
- package/src/providers/quickAccessTreeProvider.ts +328 -0
- package/src/providers/scriptsTreeProvider.ts +324 -0
- package/src/refinerPanel.ts +620 -0
- package/src/templates.ts +61 -0
- package/src/workspaceIndexer.ts +766 -0
- package/tsconfig.json +16 -0
package/src/extension.ts
ADDED
|
@@ -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
|
+
}
|