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
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PromptArchitect Refiner Panel
|
|
3
|
+
*
|
|
4
|
+
* A webview panel that provides an in-place prompt refinement experience.
|
|
5
|
+
* Users type their prompt, click Refine, and the text transforms before their eyes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as vscode from 'vscode';
|
|
9
|
+
import { PromptArchitectAPI } from './api';
|
|
10
|
+
import { getWorkspaceContext, hasWorkspaceIndex, ensureWorkspaceIndexed } from './extension';
|
|
11
|
+
|
|
12
|
+
export class RefinerPanel {
|
|
13
|
+
public static currentPanel: RefinerPanel | undefined;
|
|
14
|
+
private readonly panel: vscode.WebviewPanel;
|
|
15
|
+
private readonly api: PromptArchitectAPI;
|
|
16
|
+
private disposables: vscode.Disposable[] = [];
|
|
17
|
+
|
|
18
|
+
private constructor(panel: vscode.WebviewPanel, api: PromptArchitectAPI) {
|
|
19
|
+
this.panel = panel;
|
|
20
|
+
this.api = api;
|
|
21
|
+
|
|
22
|
+
// Set initial HTML content
|
|
23
|
+
this.updateWebview();
|
|
24
|
+
|
|
25
|
+
// Handle messages from webview
|
|
26
|
+
this.panel.webview.onDidReceiveMessage(
|
|
27
|
+
async (message) => {
|
|
28
|
+
switch (message.command) {
|
|
29
|
+
case 'refine':
|
|
30
|
+
await this.handleRefine(message.text, message.mode);
|
|
31
|
+
break;
|
|
32
|
+
case 'copyToClipboard':
|
|
33
|
+
await vscode.env.clipboard.writeText(message.text);
|
|
34
|
+
vscode.window.showInformationMessage('✅ Copied to clipboard!');
|
|
35
|
+
break;
|
|
36
|
+
case 'sendToChat':
|
|
37
|
+
await vscode.env.clipboard.writeText(message.text);
|
|
38
|
+
// Try to open Copilot Chat
|
|
39
|
+
try {
|
|
40
|
+
await vscode.commands.executeCommand('workbench.panel.chat.view.copilot.focus');
|
|
41
|
+
} catch {
|
|
42
|
+
// Fallback: try generic chat command
|
|
43
|
+
try {
|
|
44
|
+
await vscode.commands.executeCommand('workbench.action.chat.open');
|
|
45
|
+
} catch {
|
|
46
|
+
// If no chat available, just inform user
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
vscode.window.showInformationMessage('✅ Copied! Paste (Ctrl+V) in the chat input.');
|
|
50
|
+
break;
|
|
51
|
+
case 'insertInEditor':
|
|
52
|
+
await this.insertInActiveEditor(message.text);
|
|
53
|
+
break;
|
|
54
|
+
case 'indexWorkspace':
|
|
55
|
+
await vscode.commands.executeCommand('promptarchitect.indexWorkspace');
|
|
56
|
+
// Refresh the webview to update index status
|
|
57
|
+
this.updateWebview();
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
null,
|
|
62
|
+
this.disposables
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Clean up on panel close
|
|
66
|
+
this.panel.onDidDispose(() => this.dispose(), null, this.disposables);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public static createOrShow(api: PromptArchitectAPI) {
|
|
70
|
+
const column = vscode.ViewColumn.Beside;
|
|
71
|
+
|
|
72
|
+
// If panel exists, show it
|
|
73
|
+
if (RefinerPanel.currentPanel) {
|
|
74
|
+
RefinerPanel.currentPanel.panel.reveal(column);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create new panel
|
|
79
|
+
const panel = vscode.window.createWebviewPanel(
|
|
80
|
+
'promptArchitectRefiner',
|
|
81
|
+
'✨ Prompt Refiner',
|
|
82
|
+
column,
|
|
83
|
+
{
|
|
84
|
+
enableScripts: true,
|
|
85
|
+
retainContextWhenHidden: true,
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
RefinerPanel.currentPanel = new RefinerPanel(panel, api);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static prefill(text: string) {
|
|
93
|
+
if (RefinerPanel.currentPanel) {
|
|
94
|
+
RefinerPanel.currentPanel.panel.webview.postMessage({
|
|
95
|
+
command: 'prefill',
|
|
96
|
+
text,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private async handleRefine(text: string, mode: string) {
|
|
102
|
+
if (!text.trim()) {
|
|
103
|
+
this.panel.webview.postMessage({
|
|
104
|
+
command: 'error',
|
|
105
|
+
message: 'Please enter some text to refine.',
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Send loading state
|
|
111
|
+
this.panel.webview.postMessage({ command: 'loading', loading: true });
|
|
112
|
+
|
|
113
|
+
// Automatically ensure workspace is indexed (no user interaction)
|
|
114
|
+
// This runs silently in the background
|
|
115
|
+
await ensureWorkspaceIndexed();
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const config = vscode.workspace.getConfiguration('promptarchitect');
|
|
119
|
+
const targetModel = config.get<string>('targetModel') || 'general';
|
|
120
|
+
const useWorkspaceContext = config.get<boolean>('useWorkspaceContext') !== false;
|
|
121
|
+
|
|
122
|
+
// Get feedback based on refinement mode
|
|
123
|
+
const feedbackMap: Record<string, string> = {
|
|
124
|
+
clarity: 'Make this prompt clearer and more specific. Improve structure and reduce ambiguity.',
|
|
125
|
+
detailed: 'Expand this prompt with more context, requirements, and specific details.',
|
|
126
|
+
concise: 'Make this prompt more concise while keeping the core intent. Remove redundancy.',
|
|
127
|
+
technical: 'Make this prompt more technically precise with proper terminology and specifications.',
|
|
128
|
+
creative: 'Make this prompt more engaging and creative while maintaining clarity.',
|
|
129
|
+
structured: 'Add clear structure with sections, bullet points, or numbered steps.',
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
let feedback = feedbackMap[mode] || feedbackMap.clarity;
|
|
133
|
+
|
|
134
|
+
// Append workspace context if available
|
|
135
|
+
if (useWorkspaceContext) {
|
|
136
|
+
const workspaceContext = getWorkspaceContext();
|
|
137
|
+
if (workspaceContext) {
|
|
138
|
+
feedback += `\n\n--- WORKSPACE CONTEXT ---\n${workspaceContext}\n--- END WORKSPACE CONTEXT ---\n\nUse the workspace context above to make the prompt more relevant to this specific project, using appropriate terminology, patterns, and conventions.`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const result = await this.api.refinePrompt({
|
|
143
|
+
prompt: text,
|
|
144
|
+
feedback,
|
|
145
|
+
targetModel,
|
|
146
|
+
preserveStructure: mode === 'structured',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Send refined text back to webview
|
|
150
|
+
this.panel.webview.postMessage({
|
|
151
|
+
command: 'refined',
|
|
152
|
+
text: result.refinedPrompt,
|
|
153
|
+
changes: result.changes,
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
this.panel.webview.postMessage({
|
|
157
|
+
command: 'error',
|
|
158
|
+
message: `Refinement failed: ${error}`,
|
|
159
|
+
});
|
|
160
|
+
} finally {
|
|
161
|
+
this.panel.webview.postMessage({ command: 'loading', loading: false });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private async insertInActiveEditor(text: string) {
|
|
166
|
+
const editor = vscode.window.activeTextEditor;
|
|
167
|
+
if (editor) {
|
|
168
|
+
await editor.edit((editBuilder) => {
|
|
169
|
+
if (editor.selection.isEmpty) {
|
|
170
|
+
editBuilder.insert(editor.selection.active, text);
|
|
171
|
+
} else {
|
|
172
|
+
editBuilder.replace(editor.selection, text);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
vscode.window.showInformationMessage('✅ Inserted into editor!');
|
|
176
|
+
} else {
|
|
177
|
+
// Create new document with the text
|
|
178
|
+
const doc = await vscode.workspace.openTextDocument({ content: text });
|
|
179
|
+
await vscode.window.showTextDocument(doc);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private updateWebview() {
|
|
184
|
+
const isIndexed = hasWorkspaceIndex();
|
|
185
|
+
this.panel.webview.html = this.getHtmlContent(isIndexed);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private getHtmlContent(isIndexed: boolean): string {
|
|
189
|
+
const indexStatus = isIndexed
|
|
190
|
+
? '<span class="index-status indexed">📁 Workspace indexed</span>'
|
|
191
|
+
: '<span class="index-status not-indexed" title="Click to index workspace for better refinement">⚠️ Not indexed</span>';
|
|
192
|
+
|
|
193
|
+
return /*html*/ `
|
|
194
|
+
<!DOCTYPE html>
|
|
195
|
+
<html lang="en">
|
|
196
|
+
<head>
|
|
197
|
+
<meta charset="UTF-8">
|
|
198
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
199
|
+
<title>Prompt Refiner</title>
|
|
200
|
+
<style>
|
|
201
|
+
* {
|
|
202
|
+
box-sizing: border-box;
|
|
203
|
+
margin: 0;
|
|
204
|
+
padding: 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
body {
|
|
208
|
+
font-family: var(--vscode-font-family);
|
|
209
|
+
background: var(--vscode-editor-background);
|
|
210
|
+
color: var(--vscode-editor-foreground);
|
|
211
|
+
padding: 16px;
|
|
212
|
+
height: 100vh;
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-direction: column;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.header {
|
|
218
|
+
display: flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
gap: 8px;
|
|
221
|
+
margin-bottom: 16px;
|
|
222
|
+
padding-bottom: 12px;
|
|
223
|
+
border-bottom: 1px solid var(--vscode-widget-border);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.header h1 {
|
|
227
|
+
font-size: 16px;
|
|
228
|
+
font-weight: 600;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.header .sparkle {
|
|
232
|
+
font-size: 20px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.input-container {
|
|
236
|
+
flex: 1;
|
|
237
|
+
display: flex;
|
|
238
|
+
flex-direction: column;
|
|
239
|
+
min-height: 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.prompt-input {
|
|
243
|
+
flex: 1;
|
|
244
|
+
width: 100%;
|
|
245
|
+
padding: 12px;
|
|
246
|
+
border: 1px solid var(--vscode-input-border);
|
|
247
|
+
background: var(--vscode-input-background);
|
|
248
|
+
color: var(--vscode-input-foreground);
|
|
249
|
+
border-radius: 6px;
|
|
250
|
+
font-family: var(--vscode-editor-font-family);
|
|
251
|
+
font-size: 13px;
|
|
252
|
+
line-height: 1.5;
|
|
253
|
+
resize: none;
|
|
254
|
+
min-height: 150px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.prompt-input:focus {
|
|
258
|
+
outline: none;
|
|
259
|
+
border-color: var(--vscode-focusBorder);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.prompt-input::placeholder {
|
|
263
|
+
color: var(--vscode-input-placeholderForeground);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.mode-selector {
|
|
267
|
+
display: flex;
|
|
268
|
+
gap: 6px;
|
|
269
|
+
margin: 12px 0;
|
|
270
|
+
flex-wrap: wrap;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.mode-btn {
|
|
274
|
+
padding: 6px 12px;
|
|
275
|
+
border: 1px solid var(--vscode-button-secondaryBackground);
|
|
276
|
+
background: var(--vscode-button-secondaryBackground);
|
|
277
|
+
color: var(--vscode-button-secondaryForeground);
|
|
278
|
+
border-radius: 16px;
|
|
279
|
+
font-size: 11px;
|
|
280
|
+
cursor: pointer;
|
|
281
|
+
transition: all 0.15s ease;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.mode-btn:hover {
|
|
285
|
+
background: var(--vscode-button-secondaryHoverBackground);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.mode-btn.active {
|
|
289
|
+
background: var(--vscode-button-background);
|
|
290
|
+
color: var(--vscode-button-foreground);
|
|
291
|
+
border-color: var(--vscode-button-background);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.actions {
|
|
295
|
+
display: flex;
|
|
296
|
+
gap: 8px;
|
|
297
|
+
margin-top: 12px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.btn {
|
|
301
|
+
flex: 1;
|
|
302
|
+
padding: 10px 16px;
|
|
303
|
+
border: none;
|
|
304
|
+
border-radius: 6px;
|
|
305
|
+
font-size: 13px;
|
|
306
|
+
font-weight: 500;
|
|
307
|
+
cursor: pointer;
|
|
308
|
+
display: flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
justify-content: center;
|
|
311
|
+
gap: 6px;
|
|
312
|
+
transition: all 0.15s ease;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.btn-primary {
|
|
316
|
+
background: var(--vscode-button-background);
|
|
317
|
+
color: var(--vscode-button-foreground);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.btn-primary:hover {
|
|
321
|
+
background: var(--vscode-button-hoverBackground);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.btn-secondary {
|
|
325
|
+
background: var(--vscode-button-secondaryBackground);
|
|
326
|
+
color: var(--vscode-button-secondaryForeground);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.btn-secondary:hover {
|
|
330
|
+
background: var(--vscode-button-secondaryHoverBackground);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.btn:disabled {
|
|
334
|
+
opacity: 0.6;
|
|
335
|
+
cursor: not-allowed;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.btn .icon {
|
|
339
|
+
font-size: 14px;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.status {
|
|
343
|
+
margin-top: 12px;
|
|
344
|
+
padding: 10px;
|
|
345
|
+
border-radius: 6px;
|
|
346
|
+
font-size: 12px;
|
|
347
|
+
display: none;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.status.visible {
|
|
351
|
+
display: block;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.status.loading {
|
|
355
|
+
background: var(--vscode-inputValidation-infoBackground);
|
|
356
|
+
border: 1px solid var(--vscode-inputValidation-infoBorder);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.status.success {
|
|
360
|
+
background: var(--vscode-inputValidation-infoBackground);
|
|
361
|
+
border: 1px solid var(--vscode-charts-green);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.status.error {
|
|
365
|
+
background: var(--vscode-inputValidation-errorBackground);
|
|
366
|
+
border: 1px solid var(--vscode-inputValidation-errorBorder);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.changes-list {
|
|
370
|
+
margin-top: 8px;
|
|
371
|
+
padding-left: 16px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.changes-list li {
|
|
375
|
+
margin: 4px 0;
|
|
376
|
+
font-size: 11px;
|
|
377
|
+
color: var(--vscode-descriptionForeground);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.spinner {
|
|
381
|
+
display: inline-block;
|
|
382
|
+
width: 14px;
|
|
383
|
+
height: 14px;
|
|
384
|
+
border: 2px solid var(--vscode-button-foreground);
|
|
385
|
+
border-top-color: transparent;
|
|
386
|
+
border-radius: 50%;
|
|
387
|
+
animation: spin 0.8s linear infinite;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@keyframes spin {
|
|
391
|
+
to { transform: rotate(360deg); }
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.char-count {
|
|
395
|
+
font-size: 11px;
|
|
396
|
+
color: var(--vscode-descriptionForeground);
|
|
397
|
+
text-align: right;
|
|
398
|
+
margin-top: 4px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.tip {
|
|
402
|
+
font-size: 11px;
|
|
403
|
+
color: var(--vscode-descriptionForeground);
|
|
404
|
+
margin-top: 8px;
|
|
405
|
+
padding: 8px;
|
|
406
|
+
background: var(--vscode-textBlockQuote-background);
|
|
407
|
+
border-radius: 4px;
|
|
408
|
+
border-left: 3px solid var(--vscode-textLink-foreground);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.index-status {
|
|
412
|
+
font-size: 11px;
|
|
413
|
+
padding: 4px 8px;
|
|
414
|
+
border-radius: 12px;
|
|
415
|
+
cursor: pointer;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.index-status.indexed {
|
|
419
|
+
background: var(--vscode-testing-iconPassed);
|
|
420
|
+
color: var(--vscode-editor-background);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.index-status.not-indexed {
|
|
424
|
+
background: var(--vscode-inputValidation-warningBackground);
|
|
425
|
+
border: 1px solid var(--vscode-inputValidation-warningBorder);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.index-status:hover {
|
|
429
|
+
opacity: 0.8;
|
|
430
|
+
}
|
|
431
|
+
</style>
|
|
432
|
+
</head>
|
|
433
|
+
<body>
|
|
434
|
+
<div class="header">
|
|
435
|
+
<span class="sparkle">✨</span>
|
|
436
|
+
<h1>Prompt Refiner</h1>
|
|
437
|
+
${indexStatus}
|
|
438
|
+
</div>
|
|
439
|
+
|
|
440
|
+
<div class="input-container">
|
|
441
|
+
<textarea
|
|
442
|
+
class="prompt-input"
|
|
443
|
+
id="promptInput"
|
|
444
|
+
placeholder="Type or paste your prompt here... Then click 'Refine' to improve it before sending to your AI chat."
|
|
445
|
+
></textarea>
|
|
446
|
+
<div class="char-count"><span id="charCount">0</span> characters</div>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<div class="mode-selector">
|
|
450
|
+
<button class="mode-btn active" data-mode="clarity" title="Improve clarity and specificity">🎯 Clarity</button>
|
|
451
|
+
<button class="mode-btn" data-mode="detailed" title="Add more context and details">📝 Detailed</button>
|
|
452
|
+
<button class="mode-btn" data-mode="concise" title="Make more concise">✂️ Concise</button>
|
|
453
|
+
<button class="mode-btn" data-mode="technical" title="Add technical precision">⚙️ Technical</button>
|
|
454
|
+
<button class="mode-btn" data-mode="structured" title="Add structure and formatting">📋 Structured</button>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
<div class="actions">
|
|
458
|
+
<button class="btn btn-primary" id="refineBtn">
|
|
459
|
+
<span class="icon">✨</span>
|
|
460
|
+
<span class="btn-text">Refine</span>
|
|
461
|
+
</button>
|
|
462
|
+
<button class="btn btn-secondary" id="copyBtn">
|
|
463
|
+
<span class="icon">📋</span>
|
|
464
|
+
Copy
|
|
465
|
+
</button>
|
|
466
|
+
<button class="btn btn-secondary" id="sendBtn" title="Copy to clipboard and open chat">
|
|
467
|
+
<span class="icon">💬</span>
|
|
468
|
+
Send to Chat
|
|
469
|
+
</button>
|
|
470
|
+
</div>
|
|
471
|
+
|
|
472
|
+
<div class="status" id="status"></div>
|
|
473
|
+
|
|
474
|
+
<div class="tip">
|
|
475
|
+
💡 <strong>Tip:</strong> After refining, click "Send to Chat" to copy and open Copilot Chat, then paste with Ctrl+V.
|
|
476
|
+
</div>
|
|
477
|
+
|
|
478
|
+
<script>
|
|
479
|
+
const vscode = acquireVsCodeApi();
|
|
480
|
+
const input = document.getElementById('promptInput');
|
|
481
|
+
const charCount = document.getElementById('charCount');
|
|
482
|
+
const refineBtn = document.getElementById('refineBtn');
|
|
483
|
+
const copyBtn = document.getElementById('copyBtn');
|
|
484
|
+
const sendBtn = document.getElementById('sendBtn');
|
|
485
|
+
const status = document.getElementById('status');
|
|
486
|
+
const modeBtns = document.querySelectorAll('.mode-btn');
|
|
487
|
+
const indexStatus = document.querySelector('.index-status');
|
|
488
|
+
|
|
489
|
+
let currentMode = 'clarity';
|
|
490
|
+
let isLoading = false;
|
|
491
|
+
|
|
492
|
+
// Index status click handler
|
|
493
|
+
if (indexStatus) {
|
|
494
|
+
indexStatus.addEventListener('click', () => {
|
|
495
|
+
vscode.postMessage({ command: 'indexWorkspace' });
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Update character count
|
|
500
|
+
input.addEventListener('input', () => {
|
|
501
|
+
charCount.textContent = input.value.length;
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// Mode selection
|
|
505
|
+
modeBtns.forEach(btn => {
|
|
506
|
+
btn.addEventListener('click', () => {
|
|
507
|
+
modeBtns.forEach(b => b.classList.remove('active'));
|
|
508
|
+
btn.classList.add('active');
|
|
509
|
+
currentMode = btn.dataset.mode;
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Refine button
|
|
514
|
+
refineBtn.addEventListener('click', () => {
|
|
515
|
+
if (isLoading) return;
|
|
516
|
+
vscode.postMessage({
|
|
517
|
+
command: 'refine',
|
|
518
|
+
text: input.value,
|
|
519
|
+
mode: currentMode
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
// Copy button
|
|
524
|
+
copyBtn.addEventListener('click', () => {
|
|
525
|
+
vscode.postMessage({
|
|
526
|
+
command: 'copyToClipboard',
|
|
527
|
+
text: input.value
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Send to chat button
|
|
532
|
+
sendBtn.addEventListener('click', () => {
|
|
533
|
+
vscode.postMessage({
|
|
534
|
+
command: 'sendToChat',
|
|
535
|
+
text: input.value
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Handle keyboard shortcuts
|
|
540
|
+
input.addEventListener('keydown', (e) => {
|
|
541
|
+
// Ctrl+Enter to refine
|
|
542
|
+
if (e.ctrlKey && e.key === 'Enter') {
|
|
543
|
+
e.preventDefault();
|
|
544
|
+
refineBtn.click();
|
|
545
|
+
}
|
|
546
|
+
// Ctrl+Shift+Enter to send to chat
|
|
547
|
+
if (e.ctrlKey && e.shiftKey && e.key === 'Enter') {
|
|
548
|
+
e.preventDefault();
|
|
549
|
+
sendBtn.click();
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Handle messages from extension
|
|
554
|
+
window.addEventListener('message', event => {
|
|
555
|
+
const message = event.data;
|
|
556
|
+
|
|
557
|
+
switch (message.command) {
|
|
558
|
+
case 'prefill':
|
|
559
|
+
input.value = message.text;
|
|
560
|
+
charCount.textContent = message.text.length;
|
|
561
|
+
input.focus();
|
|
562
|
+
break;
|
|
563
|
+
|
|
564
|
+
case 'loading':
|
|
565
|
+
isLoading = message.loading;
|
|
566
|
+
refineBtn.disabled = message.loading;
|
|
567
|
+
if (message.loading) {
|
|
568
|
+
refineBtn.innerHTML = '<span class="spinner"></span><span class="btn-text">Refining...</span>';
|
|
569
|
+
status.className = 'status visible loading';
|
|
570
|
+
status.innerHTML = '⏳ Refining your prompt...';
|
|
571
|
+
} else {
|
|
572
|
+
refineBtn.innerHTML = '<span class="icon">✨</span><span class="btn-text">Refine</span>';
|
|
573
|
+
}
|
|
574
|
+
break;
|
|
575
|
+
|
|
576
|
+
case 'refined':
|
|
577
|
+
input.value = message.text;
|
|
578
|
+
charCount.textContent = message.text.length;
|
|
579
|
+
status.className = 'status visible success';
|
|
580
|
+
let html = '✅ Prompt refined successfully!';
|
|
581
|
+
if (message.changes && message.changes.length > 0) {
|
|
582
|
+
html += '<ul class="changes-list">';
|
|
583
|
+
message.changes.forEach(change => {
|
|
584
|
+
html += '<li>' + change + '</li>';
|
|
585
|
+
});
|
|
586
|
+
html += '</ul>';
|
|
587
|
+
}
|
|
588
|
+
status.innerHTML = html;
|
|
589
|
+
// Auto-hide after 5 seconds
|
|
590
|
+
setTimeout(() => {
|
|
591
|
+
status.className = 'status';
|
|
592
|
+
}, 5000);
|
|
593
|
+
break;
|
|
594
|
+
|
|
595
|
+
case 'error':
|
|
596
|
+
status.className = 'status visible error';
|
|
597
|
+
status.innerHTML = '❌ ' + message.message;
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
// Focus input on load
|
|
603
|
+
input.focus();
|
|
604
|
+
</script>
|
|
605
|
+
</body>
|
|
606
|
+
</html>
|
|
607
|
+
`;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private dispose() {
|
|
611
|
+
RefinerPanel.currentPanel = undefined;
|
|
612
|
+
this.panel.dispose();
|
|
613
|
+
while (this.disposables.length) {
|
|
614
|
+
const disposable = this.disposables.pop();
|
|
615
|
+
if (disposable) {
|
|
616
|
+
disposable.dispose();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
package/src/templates.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Quick Pick Provider
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as vscode from 'vscode';
|
|
6
|
+
|
|
7
|
+
export interface TemplateItem extends vscode.QuickPickItem {
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const TEMPLATES: TemplateItem[] = [
|
|
12
|
+
{
|
|
13
|
+
label: '$(code) Coding',
|
|
14
|
+
value: 'coding',
|
|
15
|
+
description: 'Programming & development',
|
|
16
|
+
detail: 'Structured prompts for coding tasks with context, requirements, and constraints',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: '$(book) Writing',
|
|
20
|
+
value: 'writing',
|
|
21
|
+
description: 'Content creation',
|
|
22
|
+
detail: 'Prompts optimized for writing with tone, audience, and style guidance',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: '$(search) Research',
|
|
26
|
+
value: 'research',
|
|
27
|
+
description: 'Investigation & discovery',
|
|
28
|
+
detail: 'Research prompts with sources, methodology, and output format',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: '$(graph) Analysis',
|
|
32
|
+
value: 'analysis',
|
|
33
|
+
description: 'Data & business analysis',
|
|
34
|
+
detail: 'Analysis prompts with metrics, comparisons, and recommendations',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: '$(verified) Fact Check',
|
|
38
|
+
value: 'factcheck',
|
|
39
|
+
description: 'Verification & validation',
|
|
40
|
+
detail: 'Fact-checking prompts with claims, sources, and confidence levels',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: '$(globe) General',
|
|
44
|
+
value: 'general',
|
|
45
|
+
description: 'General-purpose',
|
|
46
|
+
detail: 'Versatile template for any task type',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
export class TemplateQuickPick {
|
|
51
|
+
static async show(): Promise<string | undefined> {
|
|
52
|
+
const selected = await vscode.window.showQuickPick(TEMPLATES, {
|
|
53
|
+
placeHolder: 'Select a template',
|
|
54
|
+
title: 'PromptArchitect - Choose Template',
|
|
55
|
+
matchOnDescription: true,
|
|
56
|
+
matchOnDetail: true,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return selected?.value;
|
|
60
|
+
}
|
|
61
|
+
}
|