mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Improve locked files detection with smarter pattern matching and prevent AI from attempting to modify locked files
This commit is contained in:
parent
b42975b531
commit
38b26cac0e
@ -312,10 +312,51 @@ export const ChatImpl = memo(
|
||||
}
|
||||
|
||||
// Check if the message is trying to modify locked files or folders
|
||||
const { modifiedPrompt, hasLockedItems } = checkForLockedItems(messageContent);
|
||||
const { hasLockedItems, lockedFiles, lockedFolders } = checkForLockedItems(messageContent);
|
||||
|
||||
// Use the modified prompt that includes warnings about locked files/folders
|
||||
const finalMessageContent = hasLockedItems ? modifiedPrompt : messageContent;
|
||||
// If we have locked items, we'll handle this specially
|
||||
if (hasLockedItems) {
|
||||
// Create a list of locked items for display
|
||||
const lockedItems = [
|
||||
...lockedFiles.map((f) => `File: ${f.path} (${f.lockMode} lock)`),
|
||||
...lockedFolders.map((f) => `Folder: ${f.path} (${f.lockMode} lock)`),
|
||||
].join('\n- ');
|
||||
|
||||
// Add a user message to the chat
|
||||
const userMessage: Message = {
|
||||
id: Date.now().toString(),
|
||||
role: 'user',
|
||||
content: messageContent,
|
||||
};
|
||||
|
||||
// Add an assistant message explaining the locked files
|
||||
const assistantMessage: Message = {
|
||||
id: (Date.now() + 1).toString(),
|
||||
role: 'assistant',
|
||||
content: `I've detected that you're asking me to modify locked files or folders. These items are currently locked and cannot be modified:\n\n- ${lockedItems}\n\nPlease unlock these items first if you want me to modify them. You can do this by right-clicking on the file/folder in the file tree and selecting "Unlock".`,
|
||||
};
|
||||
|
||||
// Add both messages to the chat
|
||||
setMessages([...messages, userMessage, assistantMessage]);
|
||||
|
||||
// Clear the input
|
||||
setInput('');
|
||||
|
||||
// Show an alert
|
||||
workbenchStore.actionAlert.set({
|
||||
type: 'warning',
|
||||
title: 'Locked Files/Folders Detected',
|
||||
description: 'Your request mentions locked files or folders',
|
||||
content:
|
||||
'These items are locked and cannot be modified. Please unlock them first if you want to modify them.',
|
||||
isLockedFile: true,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If no locked items, proceed normally with the original message
|
||||
const finalMessageContent = messageContent;
|
||||
|
||||
runAnimation();
|
||||
|
||||
|
@ -12,6 +12,7 @@ const logger = createScopedLogger('useLockedFilesChecker');
|
||||
* - Update app/components/file.tsx
|
||||
* - Change the code in src/utils/helper.ts
|
||||
* - Fix the bug in folder/file.js
|
||||
* - Update the readme
|
||||
*/
|
||||
function extractPotentialFilePaths(prompt: string): string[] {
|
||||
// Common file extensions to look for
|
||||
@ -59,8 +60,92 @@ function extractPotentialFilePaths(prompt: string): string[] {
|
||||
const folderMatches = [...prompt.matchAll(folderRegex)];
|
||||
const folderPaths = folderMatches.map((match) => match[2]);
|
||||
|
||||
// Look for common file names without extensions
|
||||
const commonFileNames = [
|
||||
{ pattern: /\b(readme|read\s*me)\b/gi, path: 'README.md' },
|
||||
{ pattern: /\b(license)\b/gi, path: 'LICENSE' },
|
||||
{ pattern: /\b(changelog|change\s*log)\b/gi, path: 'CHANGELOG.md' },
|
||||
{ pattern: /\b(package\.json)\b/gi, path: 'package.json' },
|
||||
{ pattern: /\b(tsconfig|ts\s*config)\b/gi, path: 'tsconfig.json' },
|
||||
{ pattern: /\b(gitignore|git\s*ignore)\b/gi, path: '.gitignore' },
|
||||
{ pattern: /\b(env|environment|\.env)\b/gi, path: '.env' },
|
||||
{ pattern: /\b(docker\s*file)\b/gi, path: 'Dockerfile' },
|
||||
{ pattern: /\b(compose\.ya?ml)\b/gi, path: 'docker-compose.yml' },
|
||||
|
||||
// Common action verbs that might indicate file modification intent
|
||||
{ pattern: /\b(update|modify|change|edit|fix|create|add to|implement|write|rewrite)\b/gi, path: '' },
|
||||
];
|
||||
|
||||
const commonFilePaths = commonFileNames.flatMap(({ pattern, path }) => {
|
||||
// If this is an action verb pattern and it matches, we need to check all files
|
||||
if (path === '' && prompt.match(pattern)) {
|
||||
return []; // We'll handle action verbs separately
|
||||
}
|
||||
|
||||
return prompt.match(pattern) ? [path] : [];
|
||||
});
|
||||
|
||||
// Also check for files in the current workbench store
|
||||
const workbenchFiles = Object.keys(workbenchStore.files.get());
|
||||
|
||||
// Check if the prompt mentions updating or modifying any of these files
|
||||
const actionWords = [
|
||||
'update',
|
||||
'modify',
|
||||
'change',
|
||||
'edit',
|
||||
'fix',
|
||||
'create',
|
||||
'add to',
|
||||
'implement',
|
||||
'write',
|
||||
'rewrite',
|
||||
];
|
||||
|
||||
// Check if any action word is in the prompt
|
||||
const hasActionWord = actionWords.some((action) => new RegExp(`\\b${action}\\b`, 'i').test(prompt));
|
||||
|
||||
// If we detect an action word, we need to be more cautious and check all important files
|
||||
let mentionedFiles: string[] = [];
|
||||
|
||||
if (hasActionWord) {
|
||||
// First, check for specific file mentions
|
||||
mentionedFiles = workbenchFiles.filter((file) => {
|
||||
const fileName = file.split('/').pop() || '';
|
||||
|
||||
// Check if any action word is followed by this filename
|
||||
return actionWords.some((action) => {
|
||||
const regex = new RegExp(`${action}\\s+(?:the\\s+)?(?:file\\s+)?['"]?${fileName}['"]?`, 'i');
|
||||
return regex.test(prompt);
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
* If no specific files are mentioned but action words are present,
|
||||
* include common important files that are often modified
|
||||
*/
|
||||
if (mentionedFiles.length === 0) {
|
||||
const importantFilePatterns = [
|
||||
/README\.md$/i,
|
||||
/package\.json$/i,
|
||||
/index\.(js|ts|jsx|tsx)$/i,
|
||||
/app\.(js|ts|jsx|tsx)$/i,
|
||||
/main\.(js|ts|jsx|tsx)$/i,
|
||||
/styles\.(css|scss)$/i,
|
||||
];
|
||||
|
||||
mentionedFiles = workbenchFiles.filter((file) => importantFilePatterns.some((pattern) => pattern.test(file)));
|
||||
}
|
||||
} else {
|
||||
// If no action words, just check for direct file mentions
|
||||
mentionedFiles = workbenchFiles.filter((file) => {
|
||||
const fileName = file.split('/').pop() || '';
|
||||
return new RegExp(`\\b${fileName}\\b`, 'i').test(prompt);
|
||||
});
|
||||
}
|
||||
|
||||
// Combine and remove duplicates
|
||||
return [...new Set([...filePaths, ...folderPaths])];
|
||||
return [...new Set([...filePaths, ...folderPaths, ...commonFilePaths, ...mentionedFiles])];
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user