From 4517e0745ee51bca74d3debc952166e10a4ff70e Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Sun, 15 Jun 2025 20:34:52 -0700 Subject: [PATCH 1/4] feat: implement parentRulesMaxDepth setting This commit implements the parentRulesMaxDepth setting which controls how many parent directories are searched for .roo/rules files. The setting is accessible from the Modes view and persists across sessions. Key changes: - Added parentRulesMaxDepth to the global settings schema - Added UI component in ModesView.tsx with improved styling - Updated state management to properly persist the setting Signed-off-by: Eric Wheeler --- packages/types/src/global-settings.ts | 1 + src/core/webview/ClineProvider.ts | 3 ++ src/core/webview/webviewMessageHandler.ts | 4 ++ src/services/roo-config/index.ts | 45 ++++++++++++++++--- src/shared/ExtensionMessage.ts | 1 + src/shared/WebviewMessage.ts | 1 + webview-ui/src/components/modes/ModesView.tsx | 26 +++++++++++ .../src/context/ExtensionStateContext.tsx | 5 +++ webview-ui/src/i18n/locales/en/settings.json | 6 ++- 9 files changed, 86 insertions(+), 6 deletions(-) diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index e713cafa4c..e79fc4cd1a 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -48,6 +48,7 @@ export const globalSettingsSchema = z.object({ allowedCommands: z.array(z.string()).optional(), allowedMaxRequests: z.number().nullish(), autoCondenseContext: z.boolean().optional(), + parentRulesMaxDepth: z.number().min(1).optional(), autoCondenseContextPercent: z.number().optional(), maxConcurrentFileReads: z.number().optional(), diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 51cb9a275b..8f1ce14064 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1402,6 +1402,7 @@ export class ClineProvider terminalCompressProgressBar, historyPreviewCollapsed, cloudUserInfo, + parentRulesMaxDepth, cloudIsAuthenticated, sharingEnabled, organizationAllowList, @@ -1490,6 +1491,7 @@ export class ClineProvider maxOpenTabsContext: maxOpenTabsContext ?? 20, maxWorkspaceFiles: maxWorkspaceFiles ?? 200, cwd, + parentRulesMaxDepth: parentRulesMaxDepth ?? 1, browserToolEnabled: browserToolEnabled ?? true, telemetrySetting, telemetryKey, @@ -1654,6 +1656,7 @@ export class ClineProvider showRooIgnoredFiles: stateValues.showRooIgnoredFiles ?? true, maxReadFileLine: stateValues.maxReadFileLine ?? -1, maxConcurrentFileReads: stateValues.maxConcurrentFileReads ?? 5, + parentRulesMaxDepth: stateValues.parentRulesMaxDepth ?? 1, historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false, cloudUserInfo, cloudIsAuthenticated, diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index cac94aa0ce..27681334db 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -193,6 +193,10 @@ export const webviewMessageHandler = async ( await updateGlobalState("autoCondenseContextPercent", message.value) await provider.postStateToWebview() break + case "parentRulesMaxDepth": + await updateGlobalState("parentRulesMaxDepth", Math.max(1, message.value ?? 1)) + await provider.postStateToWebview() + break case "terminalOperation": if (message.terminalOperation) { provider.getCurrentCline()?.handleTerminalOperation(message.terminalOperation) diff --git a/src/services/roo-config/index.ts b/src/services/roo-config/index.ts index b46c39e354..78aa57efa3 100644 --- a/src/services/roo-config/index.ts +++ b/src/services/roo-config/index.ts @@ -1,6 +1,8 @@ import * as path from "path" import * as os from "os" import fs from "fs/promises" +import { string } from "zod" +import { dir } from "console" /** * Gets the global .roo directory path based on the current platform @@ -145,15 +147,48 @@ export async function readFileIfExists(filePath: string): Promise * ``` */ export function getRooDirectoriesForCwd(cwd: string): string[] { - const directories: string[] = [] + const directories: Set = new Set() // Add global directory first - directories.push(getGlobalRooDirectory()) + directories.add(getGlobalRooDirectory()) - // Add project-local directory second - directories.push(getProjectRooDirectoryForCwd(cwd)) + // Add project and any parent directories + let currentCwd = path.resolve(cwd) + const rootDir = path.parse(currentCwd).root - return directories + // Get parentRulesMaxDepth from global state + let maxDepth = 1 + try { + const { ContextProxy } = require("../../core/config/ContextProxy") + maxDepth = ContextProxy.instance?.getValue("parentRulesMaxDepth") ?? 1 + console.log("Using parentRulesMaxDepth:", maxDepth) + } catch (error) { + // In test environments, ContextProxy might not be initialized + // Fall back to default value of 1 + console.error("Using default parentRulesMaxDepth: 1", error) + } + + let currentDepth = 0 + + // Loop from initialCwd up to root or until max depth is reached + while (currentDepth < maxDepth) { + directories.add(getProjectRooDirectoryForCwd(currentCwd)) + + // Stop if we've reached the root directory + if (currentCwd === rootDir) { + break + } + const parentCwd = path.resolve(currentCwd, "..") + + // Safety break if path.resolve doesn't change currentCwd (e.g., already at root) + if (parentCwd === currentCwd) { + break + } + currentCwd = parentCwd + currentDepth++ + } + + return Array.from(directories).sort() } /** diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 73ebf59d4c..29c10144df 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -203,6 +203,7 @@ export type ExtensionState = Pick< | "fuzzyMatchThreshold" // | "experiments" // Optional in GlobalSettings, required here. | "language" + | "parentRulesMaxDepth" // | "telemetrySetting" // Optional in GlobalSettings, required here. // | "mcpEnabled" // Optional in GlobalSettings, required here. // | "enableMcpServerCreation" // Optional in GlobalSettings, required here. diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 7efc97e8c7..b73391e555 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -100,6 +100,7 @@ export interface WebviewMessage { | "enhancePrompt" | "enhancedPrompt" | "draggedImages" + | "parentRulesMaxDepth" | "deleteMessage" | "terminalOutputLineLimit" | "terminalShellIntegrationTimeout" diff --git a/webview-ui/src/components/modes/ModesView.tsx b/webview-ui/src/components/modes/ModesView.tsx index 2dd6c6dc76..16df6b877e 100644 --- a/webview-ui/src/components/modes/ModesView.tsx +++ b/webview-ui/src/components/modes/ModesView.tsx @@ -73,6 +73,8 @@ const ModesView = ({ onDone }: ModesViewProps) => { customInstructions, setCustomInstructions, customModes, + parentRulesMaxDepth, + setParentRulesMaxDepth, } = useExtensionState() // Use a local state to track the visually active mode @@ -1032,6 +1034,30 @@ const ModesView = ({ onDone }: ModesViewProps) => { + {/* Parent Rules Max Depth Setting */} +
+
{t("settings:prompts.parentRulesMaxDepth.label")}
+
+ { + const value = Math.max(1, parseInt(e.target.value) || 1) + setParentRulesMaxDepth(value) + vscode.postMessage({ + type: "parentRulesMaxDepth", + value: value, + }) + }} + /> +
+
+ {t("settings:prompts.parentRulesMaxDepth.description")} +
+
+