Skip to content

Commit 775c321

Browse files
committed
added small repo warning + custom instructions
1 parent 3890db6 commit 775c321

File tree

6 files changed

+105
-7
lines changed

6 files changed

+105
-7
lines changed

src/core/webview/webviewMessageHandler.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1904,6 +1904,8 @@ export const webviewMessageHandler = async (
19041904
const addToGitignore = message.addToGitignore || false
19051905
const alwaysAllowWriteProtected = message.alwaysAllowWriteProtected || false
19061906
const apiConfigName = message.apiConfigName
1907+
const includeCustomRules = message.includeCustomRules || false
1908+
const customRulesText = message.customRulesText || ""
19071909

19081910
// Save current API config to restore later
19091911
const currentApiConfig = getGlobalState("currentApiConfigName")
@@ -1920,6 +1922,8 @@ export const webviewMessageHandler = async (
19201922
selectedRuleTypes,
19211923
addToGitignore,
19221924
alwaysAllowWriteProtected,
1925+
includeCustomRules,
1926+
customRulesText,
19231927
)
19241928

19251929
// Spawn a new task in code mode to generate the rules
@@ -1954,7 +1958,7 @@ export const webviewMessageHandler = async (
19541958
}
19551959
break
19561960
case "checkExistingRuleFiles":
1957-
// Check which rule files already exist
1961+
// Check which rule files already exist and count source files
19581962
try {
19591963
const workspacePath = getWorkspacePath()
19601964
if (!workspacePath) {
@@ -1963,6 +1967,7 @@ export const webviewMessageHandler = async (
19631967

19641968
const { fileExistsAtPath } = await import("../../utils/fs")
19651969
const path = await import("path")
1970+
const fs = await import("fs/promises")
19661971

19671972
const ruleTypeToPath: Record<string, string> = {
19681973
general: path.join(workspacePath, ".roo", "rules", "coding-standards.md"),
@@ -1984,9 +1989,28 @@ export const webviewMessageHandler = async (
19841989
}
19851990
}
19861991

1992+
// Count all files in the workspace
1993+
let sourceFileCount = 0
1994+
try {
1995+
// Use VS Code API to count all files
1996+
const vscode = await import("vscode")
1997+
1998+
// Find all files (excluding common non-project files)
1999+
const pattern = "**/*"
2000+
const excludePattern =
2001+
"**/node_modules/**,**/.git/**,**/dist/**,**/build/**,**/.next/**,**/.nuxt/**,**/coverage/**,**/.cache/**"
2002+
2003+
const files = await vscode.workspace.findFiles(pattern, excludePattern)
2004+
sourceFileCount = files.length
2005+
} catch (error) {
2006+
// If counting fails, set to -1 to indicate unknown
2007+
sourceFileCount = -1
2008+
}
2009+
19872010
await provider.postMessageToWebview({
19882011
type: "existingRuleFiles",
19892012
files: existingFiles,
2013+
sourceFileCount,
19902014
})
19912015
} catch (error) {
19922016
// Silently fail - not critical

src/services/rules/rulesGenerator.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ export async function createRulesGenerationTaskMessage(
99
selectedRuleTypes: string[],
1010
addToGitignore: boolean,
1111
alwaysAllowWriteProtected: boolean = false,
12+
includeCustomRules: boolean = false,
13+
customRulesText: string = "",
1214
): Promise<string> {
1315
// Only create directories if auto-approve is enabled
1416
if (alwaysAllowWriteProtected) {
@@ -135,7 +137,7 @@ ${ruleInstructions
135137
- Project-specific conventions and best practices
136138
- File organization patterns
137139
138-
5. **Keep rules concise** - aim for 20-30 lines per file, focusing on the most important guidelines
140+
5. **Keep rules concise** - aim for 20 lines per file, focusing on the most important guidelines
139141
140142
6. **Open the generated files** in the editor for review after creation
141143
@@ -149,6 +151,12 @@ ${
149151
- If .gitignore doesn't exist, create it
150152
- If the entries already exist in .gitignore, don't duplicate them`
151153
: ""
154+
}
155+
156+
${
157+
includeCustomRules && customRulesText
158+
? `\n**Additional rules from User to add to the rules file:**\n${customRulesText}`
159+
: ""
152160
}`
153161

154162
return taskMessage

src/shared/ExtensionMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export interface ExtensionMessage {
110110
text?: string
111111
payload?: any // Add a generic payload for now, can refine later
112112
files?: string[] // For existingRuleFiles
113+
sourceFileCount?: number // For existingRuleFiles to show warning for small repos
113114
action?:
114115
| "chatButtonClicked"
115116
| "mcpButtonClicked"

src/shared/WebviewMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ export interface WebviewMessage {
241241
addToGitignore?: boolean // For generateRules
242242
alwaysAllowWriteProtected?: boolean // For generateRules
243243
apiConfigName?: string // For generateRules
244+
includeCustomRules?: boolean // For generateRules
245+
customRulesText?: string // For generateRules
244246
files?: string[] // For existingRuleFiles response
245247
codeIndexSettings?: {
246248
// Global state settings

webview-ui/src/components/settings/RulesSettings.tsx

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { vscode } from "@/utils/vscode"
66
import { cn } from "@/lib/utils"
77
import { useExtensionState } from "@/context/ExtensionStateContext"
88
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StandardTooltip } from "@/components/ui"
9+
import { VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"
910

1011
import { SectionHeader } from "./SectionHeader"
1112
import { Section } from "./Section"
@@ -29,10 +30,13 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
2930
type: "success" | "error" | null
3031
message: string
3132
}>({ type: null, message: "" })
32-
const [addToGitignore, setAddToGitignore] = useState(false)
33+
const [addToGitignore, setAddToGitignore] = useState(true)
3334
const [_existingFiles, setExistingFiles] = useState<string[]>([])
34-
const [alwaysAllowWriteProtected, setAlwaysAllowWriteProtected] = useState(false)
35+
const [alwaysAllowWriteProtected, setAlwaysAllowWriteProtected] = useState(true)
3536
const [selectedApiConfig, setSelectedApiConfig] = useState<string>("")
37+
const [includeCustomRules, setIncludeCustomRules] = useState(false)
38+
const [customRulesText, setCustomRulesText] = useState("")
39+
const [sourceFileCount, setSourceFileCount] = useState<number | null>(null)
3640

3741
const { listApiConfigMeta, currentApiConfigName } = useExtensionState()
3842

@@ -118,6 +122,10 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
118122
exists: message.files?.includes(rule.id) || false,
119123
})),
120124
)
125+
// Set source file count if provided
126+
if (message.sourceFileCount !== undefined) {
127+
setSourceFileCount(message.sourceFileCount)
128+
}
121129
} else if (message.type === "state") {
122130
// Update alwaysAllowWriteProtected from the extension state
123131
if (message.state?.alwaysAllowWriteProtected !== undefined) {
@@ -150,6 +158,8 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
150158
addToGitignore,
151159
alwaysAllowWriteProtected,
152160
apiConfigName: selectedApiConfig,
161+
includeCustomRules,
162+
customRulesText: includeCustomRules ? customRulesText : "",
153163
})
154164
}
155165

@@ -221,6 +231,15 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
221231
</div>
222232
</div>
223233

234+
{/* Small repository warning */}
235+
{sourceFileCount !== null && sourceFileCount > 0 && sourceFileCount < 20 && (
236+
<div className="flex items-start gap-2 p-3 bg-vscode-inputValidation-warningBackground border border-vscode-inputValidation-warningBorder rounded-md">
237+
<AlertTriangle className="w-4 h-4 text-vscode-inputValidation-warningForeground mt-0.5 flex-shrink-0" />
238+
<div className="text-sm text-vscode-inputValidation-warningForeground">
239+
{t("settings:rules.smallRepoWarning", { count: sourceFileCount })}
240+
</div>
241+
</div>
242+
)}
224243
{hasExistingFiles && (
225244
<div className="flex items-start gap-2 p-3 bg-vscode-inputValidation-warningBackground border border-vscode-inputValidation-warningBorder rounded-md">
226245
<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
235254
</div>
236255
)}
237256

238-
<div className="border-t border-vscode-panel-border pt-4">
257+
<div className="border-t border-vscode-panel-border pt-2">
239258
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
240259
<input
241260
type="checkbox"
@@ -251,7 +270,7 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
251270
</label>
252271
</div>
253272

254-
<div className="border-t border-vscode-panel-border pt-4">
273+
<div className="border-t border-vscode-panel-border pt-2">
255274
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
256275
<input
257276
type="checkbox"
@@ -275,6 +294,45 @@ export const RulesSettings = ({ className, hasUnsavedChanges, ...props }: RulesS
275294
</label>
276295
</div>
277296

297+
<div className="border-t border-vscode-panel-border pt-4">
298+
<label className="flex items-center gap-2 cursor-pointer hover:opacity-80">
299+
<input
300+
type="checkbox"
301+
checked={includeCustomRules}
302+
onChange={(e) => setIncludeCustomRules(e.target.checked)}
303+
/>
304+
<div>
305+
<div className="text-sm font-medium">
306+
{t("settings:rules.includeCustomRules")}
307+
</div>
308+
<div className="text-xs text-vscode-descriptionForeground">
309+
{t("settings:rules.includeCustomRulesDescription")}
310+
</div>
311+
</div>
312+
</label>
313+
314+
{includeCustomRules && (
315+
<div className="mt-3 pl-6">
316+
<VSCodeTextArea
317+
resize="vertical"
318+
value={customRulesText}
319+
onChange={(e) => {
320+
const value =
321+
(e as unknown as CustomEvent)?.detail?.target?.value ||
322+
((e as any).target as HTMLTextAreaElement).value
323+
setCustomRulesText(value)
324+
}}
325+
placeholder={t("settings:rules.customRulesPlaceholder")}
326+
rows={6}
327+
className="w-full"
328+
/>
329+
<div className="text-xs text-vscode-descriptionForeground mt-1">
330+
{t("settings:rules.customRulesHint")}
331+
</div>
332+
</div>
333+
)}
334+
</div>
335+
278336
<div className="flex flex-col gap-3">
279337
<Select value={selectedApiConfig} onValueChange={setSelectedApiConfig}>
280338
<SelectTrigger className="w-fit min-w-[5rem] max-w-[8rem]">

webview-ui/src/i18n/locales/en/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,12 @@
656656
"autoApproveProtected": "Auto-approve protected file writes",
657657
"autoApproveProtectedDescription": "Allow Roo to make and write to .roo directory without requiring manual approval",
658658
"autoApproveRecommendation": "For the best experience generating rules, we recommend enabling auto-approve for both read and write operations in the Auto-Approve settings above.",
659-
"selectApiConfig": "Select API configuration"
659+
"selectApiConfig": "Select API configuration",
660+
"includeCustomRules": "Include my own rules",
661+
"includeCustomRulesDescription": "Add custom instructions to the rule generation prompt",
662+
"customRulesPlaceholder": "Enter your custom rules or instructions here...",
663+
"customRulesHint": "These will be included in the prompt when generating rules for your project",
664+
"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."
660665
},
661666
"promptCaching": {
662667
"label": "Disable prompt caching",

0 commit comments

Comments
 (0)