Skip to content

Commit 8c41430

Browse files
authored
feat: add automatic workspace rules and fix clicking on user prompt (#23)
* feat: add automatic workspace rules and fix clicking on user prompt in context transparency * add comments to code * fix: display os specific path in create prompt dialog
1 parent b030acf commit 8c41430

File tree

1 file changed

+56
-57
lines changed
  • packages/core/src/codewhispererChat/controllers/chat

1 file changed

+56
-57
lines changed

packages/core/src/codewhispererChat/controllers/chat/controller.ts

Lines changed: 56 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ import { DefaultAmazonQAppInitContext } from '../../../amazonq/apps/initContext'
6565
import globals from '../../../shared/extensionGlobals'
6666
import { MynahIconsType, MynahUIDataModel, QuickActionCommand } from '@aws/mynah-ui'
6767
import { LspClient } from '../../../amazonq/lsp/lspClient'
68-
import { ContextCommandItem } from '../../../amazonq/lsp/types'
68+
import { ContextCommandItem, ContextCommandItemType } from '../../../amazonq/lsp/types'
6969
import { createPromptCommand, workspaceCommand } from '../../../amazonq/webview/ui/tabs/constants'
7070
import fs from '../../../shared/fs/fs'
7171
import * as vscode from 'vscode'
@@ -121,12 +121,16 @@ export interface ChatControllerMessageListeners {
121121
readonly processFileClick: MessageListener<FileClick>
122122
}
123123

124-
const promptFileExtension = '.prompt'
124+
const promptFileExtension = '.prompt.md'
125125

126126
const additionalContentInnerContextLimit = 8192
127127

128128
const aditionalContentNameLimit = 1024
129129

130+
const getUserPromptsDirectory = () => {
131+
return path.join(fs.getUserHomeDir(), '.aws', 'amazonq', 'prompts')
132+
}
133+
130134
export class ChatController {
131135
private readonly sessionStorage: ChatSessionStorage
132136
private readonly triggerEventsStorage: TriggerEventsStorage
@@ -458,35 +462,19 @@ export class ChatController {
458462
}
459463
const promptsCmd: QuickActionCommand = contextCommand[0].commands?.[3]
460464

461-
// Check .aws/prompts for prompt files in workspace
462-
const workspacePromptFiles = await vscode.workspace.findFiles(`.aws/prompts/*${promptFileExtension}`)
463-
464-
if (workspacePromptFiles.length > 0) {
465-
promptsCmd.children?.[0].commands.push(
466-
...workspacePromptFiles.map((file) => {
467-
const workspacePath = vscode.workspace.getWorkspaceFolder(file)?.uri.path || path.dirname(file.path)
468-
const relativePath = path.relative(workspacePath, file.path)
469-
return {
470-
command: path.basename(file.path, promptFileExtension),
471-
icon: 'magic' as MynahIconsType,
472-
route: [workspacePath, relativePath],
473-
}
474-
})
475-
)
476-
}
477-
// Check ~/.aws/prompts for global prompt files
465+
// Check for user prompts
478466
try {
479-
const systemPromptsDirectory = path.join(fs.getUserHomeDir(), '.aws', 'prompts')
480-
const directoryExists = await fs.exists(systemPromptsDirectory)
467+
const userPromptsDirectory = getUserPromptsDirectory()
468+
const directoryExists = await fs.exists(userPromptsDirectory)
481469
if (directoryExists) {
482-
const systemPromptFiles = await fs.readdir(systemPromptsDirectory)
470+
const systemPromptFiles = await fs.readdir(userPromptsDirectory)
483471
promptsCmd.children?.[0].commands.push(
484472
...systemPromptFiles
485473
.filter(([name]) => name.endsWith(promptFileExtension))
486474
.map(([name]) => ({
487475
command: path.basename(name, promptFileExtension),
488476
icon: 'magic' as MynahIconsType,
489-
route: [systemPromptsDirectory, name],
477+
route: [userPromptsDirectory, name],
490478
}))
491479
)
492480
}
@@ -536,19 +524,7 @@ export class ChatController {
536524
mandatory: true,
537525
title: 'Prompt name',
538526
placeholder: 'Enter prompt name',
539-
description: 'Use this prompt in the chat by typing `@` followed by the prompt name.',
540-
},
541-
{
542-
id: 'shared-scope',
543-
type: 'select',
544-
title: 'Save globally for all projects?',
545-
mandatory: true,
546-
value: 'system',
547-
description: `If yes is selected, ${promptFileExtension} file will be saved in ~/.aws/prompts.`,
548-
options: [
549-
{ value: 'project', label: 'No' },
550-
{ value: 'system', label: 'Yes' },
551-
],
527+
description: `Use this prompt by typing \`@\` followed by the prompt name. Prompt will be saved in ${getUserPromptsDirectory()}.`,
552528
},
553529
],
554530
[
@@ -568,18 +544,11 @@ export class ChatController {
568544
private async processCustomFormAction(message: CustomFormActionMessage) {
569545
if (message.tabID) {
570546
if (message.action.id === 'submit-create-prompt') {
571-
let promptsDirectory = path.join(fs.getUserHomeDir(), '.aws', 'prompts')
572-
if (
573-
vscode.workspace.workspaceFolders?.[0] &&
574-
message.action.formItemValues?.['shared-scope'] === 'project'
575-
) {
576-
const workspaceUri = vscode.workspace.workspaceFolders[0].uri
577-
promptsDirectory = vscode.Uri.joinPath(workspaceUri, '.aws', 'prompts').fsPath
578-
}
547+
const userPromptsDirectory = getUserPromptsDirectory()
579548

580549
const title = message.action.formItemValues?.['prompt-name']
581550
const newFilePath = path.join(
582-
promptsDirectory,
551+
userPromptsDirectory,
583552
title ? `${title}${promptFileExtension}` : `default${promptFileExtension}`
584553
)
585554
const newFileContent = new Uint8Array(Buffer.from(''))
@@ -610,8 +579,16 @@ export class ChatController {
610579
if (!projectRoot) {
611580
return
612581
}
613-
614-
const absoluteFilePath = path.join(projectRoot, message.filePath)
582+
let absoluteFilePath = path.join(projectRoot, message.filePath)
583+
584+
// Handle clicking on a user prompt outside the workspace
585+
if (message.filePath.endsWith(promptFileExtension)) {
586+
try {
587+
await vscode.workspace.fs.stat(vscode.Uri.file(absoluteFilePath))
588+
} catch {
589+
absoluteFilePath = path.join(getUserPromptsDirectory(), message.filePath)
590+
}
591+
}
615592

616593
try {
617594
// Open the file in VSCode
@@ -887,18 +864,36 @@ export class ChatController {
887864
}
888865

889866
private async resolveContextCommandPayload(triggerPayload: TriggerPayload): Promise<string[]> {
890-
if (triggerPayload.context === undefined || triggerPayload.context.length === 0) {
891-
return []
892-
}
893867
const contextCommands: ContextCommandItem[] = []
894868
const relativePaths: string[] = []
895-
for (const context of triggerPayload.context) {
896-
if (typeof context !== 'string' && context.route && context.route.length === 2) {
897-
contextCommands.push({
898-
workspaceFolder: context.route[0] || '',
899-
type: context.icon === 'folder' ? 'folder' : 'file',
900-
relativePath: context.route[1] || '',
869+
870+
// Check for workspace rules to add to context
871+
const workspaceRules = await vscode.workspace.findFiles(`.amazonq/rules/*${promptFileExtension}`)
872+
if (workspaceRules.length > 0) {
873+
contextCommands.push(
874+
...workspaceRules.map((rule) => {
875+
const workspaceFolderPath = vscode.workspace.getWorkspaceFolder(rule)?.uri?.path || ''
876+
return {
877+
workspaceFolder: workspaceFolderPath,
878+
// todo: add 'prompt' type to LSP model
879+
type: 'file' as ContextCommandItemType,
880+
relativePath: path.relative(workspaceFolderPath, rule.path),
881+
}
901882
})
883+
)
884+
}
885+
886+
// Add context commands added by user to context
887+
if (triggerPayload.context !== undefined && triggerPayload.context.length > 0) {
888+
for (const context of triggerPayload.context) {
889+
// todo: add handling of 'prompt' type (dependent on LSP changes)
890+
if (typeof context !== 'string' && context.route && context.route.length === 2) {
891+
contextCommands.push({
892+
workspaceFolder: context.route[0] || '',
893+
type: context.icon === 'folder' ? 'folder' : 'file',
894+
relativePath: context.route[1] || '',
895+
})
896+
}
902897
}
903898
}
904899
if (contextCommands.length === 0) {
@@ -916,7 +911,11 @@ export class ChatController {
916911
description: prompt.description.substring(0, aditionalContentNameLimit),
917912
innerContext: prompt.content.substring(0, additionalContentInnerContextLimit),
918913
})
919-
const relativePath = path.relative(workspaceFolder, prompt.filePath)
914+
let relativePath = path.relative(workspaceFolder, prompt.filePath)
915+
// Handle user prompts outside the workspace
916+
if (prompt.filePath.startsWith(getUserPromptsDirectory())) {
917+
relativePath = path.basename(prompt.filePath)
918+
}
920919
relativePaths.push(relativePath)
921920
}
922921
}

0 commit comments

Comments
 (0)