added small repo warning + custom instructions

This commit is contained in:
Will Li 2025-07-18 01:28:36 -07:00
parent 3890db6f60
commit 775c321e7f
6 changed files with 105 additions and 7 deletions

View file

@ -1904,6 +1904,8 @@ export const webviewMessageHandler = async (
const addToGitignore = message.addToGitignore || false
const alwaysAllowWriteProtected = message.alwaysAllowWriteProtected || false
const apiConfigName = message.apiConfigName
const includeCustomRules = message.includeCustomRules || false
const customRulesText = message.customRulesText || ""
// Save current API config to restore later
const currentApiConfig = getGlobalState("currentApiConfigName")
@ -1920,6 +1922,8 @@ export const webviewMessageHandler = async (
selectedRuleTypes,
addToGitignore,
alwaysAllowWriteProtected,
includeCustomRules,
customRulesText,
)
// Spawn a new task in code mode to generate the rules
@ -1954,7 +1958,7 @@ export const webviewMessageHandler = async (
}
break
case "checkExistingRuleFiles":
// Check which rule files already exist
// Check which rule files already exist and count source files
try {
const workspacePath = getWorkspacePath()
if (!workspacePath) {
@ -1963,6 +1967,7 @@ export const webviewMessageHandler = async (
const { fileExistsAtPath } = await import("../../utils/fs")
const path = await import("path")
const fs = await import("fs/promises")
const ruleTypeToPath: Record<string, string> = {
general: path.join(workspacePath, ".roo", "rules", "coding-standards.md"),
@ -1984,9 +1989,28 @@ export const webviewMessageHandler = async (
}
}
// Count all files in the workspace
let sourceFileCount = 0
try {
// Use VS Code API to count all files
const vscode = await import("vscode")
// Find all files (excluding common non-project files)
const pattern = "**/*"
const excludePattern =
"**/node_modules/**,**/.git/**,**/dist/**,**/build/**,**/.next/**,**/.nuxt/**,**/coverage/**,**/.cache/**"
const files = await vscode.workspace.findFiles(pattern, excludePattern)
sourceFileCount = files.length
} catch (error) {
// If counting fails, set to -1 to indicate unknown
sourceFileCount = -1
}
await provider.postMessageToWebview({
type: "existingRuleFiles",
files: existingFiles,
sourceFileCount,
})
} catch (error) {
// Silently fail - not critical

View file

@ -9,6 +9,8 @@ export async function createRulesGenerationTaskMessage(
selectedRuleTypes: string[],
addToGitignore: boolean,
alwaysAllowWriteProtected: boolean = false,
includeCustomRules: boolean = false,
customRulesText: string = "",
): Promise<string> {
// Only create directories if auto-approve is enabled
if (alwaysAllowWriteProtected) {
@ -135,7 +137,7 @@ ${ruleInstructions
- Project-specific conventions and best practices
- File organization patterns
5. **Keep rules concise** - aim for 20-30 lines per file, focusing on the most important guidelines
5. **Keep rules concise** - aim for 20 lines per file, focusing on the most important guidelines
6. **Open the generated files** in the editor for review after creation
@ -149,6 +151,12 @@ ${
- If .gitignore doesn't exist, create it
- If the entries already exist in .gitignore, don't duplicate them`
: ""
}
${
includeCustomRules && customRulesText
? `\n**Additional rules from User to add to the rules file:**\n${customRulesText}`
: ""
}`
return taskMessage

View file

@ -110,6 +110,7 @@ export interface ExtensionMessage {
text?: string
payload?: any // Add a generic payload for now, can refine later
files?: string[] // For existingRuleFiles
sourceFileCount?: number // For existingRuleFiles to show warning for small repos
action?:
| "chatButtonClicked"
| "mcpButtonClicked"

View file

@ -241,6 +241,8 @@ export interface WebviewMessage {
addToGitignore?: boolean // For generateRules
alwaysAllowWriteProtected?: boolean // For generateRules
apiConfigName?: string // For generateRules
includeCustomRules?: boolean // For generateRules
customRulesText?: string // For generateRules
files?: string[] // For existingRuleFiles response
codeIndexSettings?: {
// Global state settings

View file

@ -6,6 +6,7 @@ import { vscode } from "@/utils/vscode"
import { cn } from "@/lib/utils"
import { useExtensionState } from "@/context/ExtensionStateContext"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StandardTooltip } from "@/components/ui"
import { VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"
import { SectionHeader } from "./SectionHeader"
import { Section } from "./Section"
@ -29,10 +30,13 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
type: "success" | "error" | null
message: string
}>({ type: null, message: "" })
const [addToGitignore, setAddToGitignore] = useState(false)
const [addToGitignore, setAddToGitignore] = useState(true)
const [_existingFiles, setExistingFiles] = useState<string[]>([])
const [alwaysAllowWriteProtected, setAlwaysAllowWriteProtected] = useState(false)
const [alwaysAllowWriteProtected, setAlwaysAllowWriteProtected] = useState(true)
const [selectedApiConfig, setSelectedApiConfig] = useState<string>("")
const [includeCustomRules, setIncludeCustomRules] = useState(false)
const [customRulesText, setCustomRulesText] = useState("")
const [sourceFileCount, setSourceFileCount] = useState<number | null>(null)
const { listApiConfigMeta, currentApiConfigName } = useExtensionState()
@ -118,6 +122,10 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
exists: message.files?.includes(rule.id) || false,
})),
)
// Set source file count if provided
if (message.sourceFileCount !== undefined) {
setSourceFileCount(message.sourceFileCount)
}
} else if (message.type === "state") {
// Update alwaysAllowWriteProtected from the extension state
if (message.state?.alwaysAllowWriteProtected !== undefined) {
@ -150,6 +158,8 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
addToGitignore,
alwaysAllowWriteProtected,
apiConfigName: selectedApiConfig,
includeCustomRules,
customRulesText: includeCustomRules ? customRulesText : "",
})
}
@ -221,6 +231,15 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
</div>
</div>
{/* Small repository warning */}
{sourceFileCount !== null && sourceFileCount > 0 && sourceFileCount < 20 && (
<div className="flex items-start gap-2 p-3 bg-vscode-inputValidation-warningBackground border border-vscode-inputValidation-warningBorder rounded-md">
<AlertTriangle className="w-4 h-4 text-vscode-inputValidation-warningForeground mt-0.5 flex-shrink-0" />
<div className="text-sm text-vscode-inputValidation-warningForeground">
{t("settings:rules.smallRepoWarning", { count: sourceFileCount })}
</div>
</div>
)}
{hasExistingFiles && (
<div className="flex items-start gap-2 p-3 bg-vscode-inputValidation-warningBackground border border-vscode-inputValidation-warningBorder rounded-md">
<AlertTriangle className="w-4 h-4 text-vscode-inputValidation-warningForeground mt-0.5 flex-shrink-0" />
@ -235,7 +254,7 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
</div>
)}
<div className="border-t border-vscode-panel-border pt-4">
<div className="border-t border-vscode-panel-border pt-2">
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
<input
type="checkbox"
@ -251,7 +270,7 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
</label>
</div>
<div className="border-t border-vscode-panel-border pt-4">
<div className="border-t border-vscode-panel-border pt-2">
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
<input
type="checkbox"
@ -275,6 +294,45 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
</label>
</div>
<div className="border-t border-vscode-panel-border pt-4">
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
<input
type="checkbox"
checked={includeCustomRules}
onChange={(e) => setIncludeCustomRules(e.target.checked)}
/>
<div>
<div className="text-sm font-medium">
{t("settings:rules.includeCustomRules")}
</div>
<div className="text-xs text-vscode-descriptionForeground">
{t("settings:rules.includeCustomRulesDescription")}
</div>
</div>
</label>
{includeCustomRules && (
<div className="mt-3 pl-6">
<VSCodeTextArea
resize="vertical"
value={customRulesText}
onChange={(e) => {
const value =
(e as unknown as CustomEvent)?.detail?.target?.value ||
((e as any).target as HTMLTextAreaElement).value
setCustomRulesText(value)
}}
placeholder={t("settings:rules.customRulesPlaceholder")}
rows={6}
className="w-full"
/>
<div className="text-xs text-vscode-descriptionForeground mt-1">
{t("settings:rules.customRulesHint")}
</div>
</div>
)}
</div>
<div className="flex flex-col gap-3">
<Select value={selectedApiConfig} onValueChange={setSelectedApiConfig}>
<SelectTrigger className="w-fit min-w-[5rem] max-w-[8rem]">

View file

@ -656,7 +656,12 @@
"autoApproveProtected": "Auto-approve protected file writes",
"autoApproveProtectedDescription": "Allow Roo to make and write to .roo directory without requiring manual approval",
"autoApproveRecommendation": "For the best experience generating rules, we recommend enabling auto-approve for both read and write operations in the Auto-Approve settings above.",
"selectApiConfig": "Select API configuration"
"selectApiConfig": "Select API configuration",
"includeCustomRules": "Include my own rules",
"includeCustomRulesDescription": "Add custom instructions to the rule generation prompt",
"customRulesPlaceholder": "Enter your custom rules or instructions here...",
"customRulesHint": "These will be included in the prompt when generating rules for your project",
"smallRepoWarning": "This repository contains only {{count}} files. With limited code examples, the generated rules may be overly specific to your current implementation. Consider regenerating rules as your project grows."
},
"promptCaching": {
"label": "Disable prompt caching",