mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
feat(settings): add include-files toggle for workspace context
This commit is contained in:
parent
1d4fc52485
commit
36d46af3e8
10 changed files with 84 additions and 10 deletions
|
|
@ -142,6 +142,13 @@ export const globalSettingsSchema = z.object({
|
|||
|
||||
maxOpenTabsContext: z.number().optional(),
|
||||
maxWorkspaceFiles: z.number().optional(),
|
||||
/**
|
||||
* Controls what is shown in the workspace files context.
|
||||
* - "files": Shows both files and directories (default, current behavior)
|
||||
* - "folders": Shows only the folder structure
|
||||
* @default "files"
|
||||
*/
|
||||
workspaceFilesMode: z.enum(["files", "folders"]).optional(),
|
||||
showRooIgnoredFiles: z.boolean().optional(),
|
||||
maxReadFileLine: z.number().optional(),
|
||||
maxImageFileSize: z.number().optional(),
|
||||
|
|
@ -200,6 +207,9 @@ export const globalSettingsSchema = z.object({
|
|||
|
||||
export type GlobalSettings = z.infer<typeof globalSettingsSchema>
|
||||
|
||||
// Workspace files mode type for controlling what is shown in the workspace files context
|
||||
export type WorkspaceFilesMode = NonNullable<GlobalSettings["workspaceFilesMode"]>
|
||||
|
||||
export const GLOBAL_SETTINGS_KEYS = globalSettingsSchema.keyof().options
|
||||
|
||||
/**
|
||||
|
|
@ -349,6 +359,7 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
rateLimitSeconds: 0,
|
||||
maxOpenTabsContext: 20,
|
||||
maxWorkspaceFiles: 200,
|
||||
workspaceFilesMode: "files",
|
||||
maxGitStatusFiles: 20,
|
||||
showRooIgnoredFiles: true,
|
||||
maxReadFileLine: -1, // -1 to enable full file reading.
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ describe("getEnvironmentDetails", () => {
|
|||
expect(result).toContain("# Current Workspace Directory")
|
||||
expect(result).toContain("Files")
|
||||
|
||||
expect(listFiles).toHaveBeenCalledWith(mockCwd, true, 50)
|
||||
expect(listFiles).toHaveBeenCalledWith(mockCwd, true, 50, false)
|
||||
|
||||
expect(formatResponse.formatFilesList).toHaveBeenCalledWith(
|
||||
mockCwd,
|
||||
|
|
@ -183,6 +183,8 @@ describe("getEnvironmentDetails", () => {
|
|||
false,
|
||||
mockCline.rooIgnoreController,
|
||||
false,
|
||||
undefined,
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,9 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
|
|||
}
|
||||
|
||||
if (includeFileDetails) {
|
||||
details += `\n\n# Current Workspace Directory (${cline.cwd.toPosix()}) Files\n`
|
||||
const workspaceFilesMode = state?.workspaceFilesMode ?? "files"
|
||||
const headerText = workspaceFilesMode === "folders" ? "Folder Structure" : "Files"
|
||||
details += `\n\n# Current Workspace Directory (${cline.cwd.toPosix()}) ${headerText}\n`
|
||||
const isDesktop = arePathsEqual(cline.cwd, path.join(os.homedir(), "Desktop"))
|
||||
|
||||
if (isDesktop) {
|
||||
|
|
@ -298,7 +300,8 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
|
|||
if (maxFiles === 0) {
|
||||
details += "(Workspace files context disabled. Use list_files to explore if needed.)"
|
||||
} else {
|
||||
const [files, didHitLimit] = await listFiles(cline.cwd, true, maxFiles)
|
||||
const foldersOnly = workspaceFilesMode === "folders"
|
||||
const [files, didHitLimit] = await listFiles(cline.cwd, true, maxFiles, foldersOnly)
|
||||
const { showRooIgnoredFiles = false } = state ?? {}
|
||||
|
||||
const result = formatResponse.formatFilesList(
|
||||
|
|
@ -307,6 +310,8 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
|
|||
didHitLimit,
|
||||
cline.rooIgnoreController,
|
||||
showRooIgnoredFiles,
|
||||
undefined,
|
||||
foldersOnly,
|
||||
)
|
||||
|
||||
details += result
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|||
rooIgnoreController: RooIgnoreController | undefined,
|
||||
showRooIgnoredFiles: boolean,
|
||||
rooProtectedController?: RooProtectedController,
|
||||
foldersOnly: boolean = false,
|
||||
): string => {
|
||||
const sorted = files
|
||||
.map((file) => {
|
||||
|
|
@ -222,11 +223,12 @@ Otherwise, if you have not completed the task and do not need additional informa
|
|||
}
|
||||
}
|
||||
if (didHitLimit) {
|
||||
return `${rooIgnoreParsed.join(
|
||||
"\n",
|
||||
)}\n\n(File list truncated. Use list_files on specific subdirectories if you need to explore further.)`
|
||||
const truncationMessage = foldersOnly
|
||||
? "(Folder list truncated. Use list_files on specific subdirectories if you need to explore further.)"
|
||||
: "(File list truncated. Use list_files on specific subdirectories if you need to explore further.)"
|
||||
return `${rooIgnoreParsed.join("\n")}\n\n${truncationMessage}`
|
||||
} else if (rooIgnoreParsed.length === 0 || (rooIgnoreParsed.length === 1 && rooIgnoreParsed[0] === "")) {
|
||||
return "No files found."
|
||||
return foldersOnly ? "No folders found." : "No files found."
|
||||
} else {
|
||||
return rooIgnoreParsed.join("\n")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1859,6 +1859,7 @@ export class ClineProvider
|
|||
experiments,
|
||||
maxOpenTabsContext,
|
||||
maxWorkspaceFiles,
|
||||
workspaceFilesMode,
|
||||
browserToolEnabled,
|
||||
telemetrySetting,
|
||||
showRooIgnoredFiles,
|
||||
|
|
@ -2003,6 +2004,7 @@ export class ClineProvider
|
|||
mcpServers: this.mcpHub?.getAllServers() ?? [],
|
||||
maxOpenTabsContext: maxOpenTabsContext ?? 20,
|
||||
maxWorkspaceFiles: maxWorkspaceFiles ?? 200,
|
||||
workspaceFilesMode: workspaceFilesMode ?? "files",
|
||||
cwd,
|
||||
browserToolEnabled: browserToolEnabled ?? true,
|
||||
telemetrySetting,
|
||||
|
|
@ -2237,6 +2239,7 @@ export class ClineProvider
|
|||
customModes,
|
||||
maxOpenTabsContext: stateValues.maxOpenTabsContext ?? 20,
|
||||
maxWorkspaceFiles: stateValues.maxWorkspaceFiles ?? 200,
|
||||
workspaceFilesMode: stateValues.workspaceFilesMode ?? "files",
|
||||
openRouterUseMiddleOutTransform: stateValues.openRouterUseMiddleOutTransform,
|
||||
browserToolEnabled: stateValues.browserToolEnabled ?? true,
|
||||
telemetrySetting: stateValues.telemetrySetting || "unset",
|
||||
|
|
|
|||
|
|
@ -28,9 +28,15 @@ interface ScanContext {
|
|||
* @param dirPath - Directory path to list files from
|
||||
* @param recursive - Whether to recursively list files in subdirectories
|
||||
* @param limit - Maximum number of files to return
|
||||
* @param foldersOnly - When true, only returns directories (no files)
|
||||
* @returns Tuple of [file paths array, whether the limit was reached]
|
||||
*/
|
||||
export async function listFiles(dirPath: string, recursive: boolean, limit: number): Promise<[string[], boolean]> {
|
||||
export async function listFiles(
|
||||
dirPath: string,
|
||||
recursive: boolean,
|
||||
limit: number,
|
||||
foldersOnly: boolean = false,
|
||||
): Promise<[string[], boolean]> {
|
||||
// Early return for limit of 0 - no need to scan anything
|
||||
if (limit === 0) {
|
||||
return [[], false]
|
||||
|
|
@ -43,6 +49,25 @@ export async function listFiles(dirPath: string, recursive: boolean, limit: numb
|
|||
return specialResult
|
||||
}
|
||||
|
||||
// For folders-only mode, skip file scanning entirely
|
||||
if (foldersOnly) {
|
||||
const ignoreInstance = await createIgnoreInstance(dirPath)
|
||||
const directories = await listFilteredDirectories(dirPath, recursive, ignoreInstance, limit)
|
||||
|
||||
// Sort and format directories
|
||||
const sortedDirs = directories.sort((a, b) => a.localeCompare(b))
|
||||
const trimmedDirs = sortedDirs.slice(0, limit)
|
||||
const limitReached = trimmedDirs.length >= limit
|
||||
|
||||
// If we hit the limit, ensure all first-level directories are included
|
||||
if (limitReached && recursive) {
|
||||
const firstLevelDirs = await getFirstLevelDirectories(dirPath, ignoreInstance)
|
||||
return ensureFirstLevelDirectoriesIncluded(trimmedDirs, firstLevelDirs, limit)
|
||||
}
|
||||
|
||||
return [trimmedDirs, limitReached]
|
||||
}
|
||||
|
||||
// Get ripgrep path
|
||||
const rgPath = await getRipgrepPath()
|
||||
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ export type ExtensionState = Pick<
|
|||
| "includeCurrentCost"
|
||||
| "maxGitStatusFiles"
|
||||
| "requestDelaySeconds"
|
||||
| "workspaceFilesMode"
|
||||
> & {
|
||||
version: string
|
||||
clineMessages: ClineMessage[]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
listApiConfigMeta: any[]
|
||||
maxOpenTabsContext: number
|
||||
maxWorkspaceFiles: number
|
||||
workspaceFilesMode?: "files" | "folders"
|
||||
showRooIgnoredFiles?: boolean
|
||||
maxReadFileLine?: number
|
||||
maxImageFileSize?: number
|
||||
|
|
@ -35,6 +36,7 @@ type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
| "autoCondenseContextPercent"
|
||||
| "maxOpenTabsContext"
|
||||
| "maxWorkspaceFiles"
|
||||
| "workspaceFilesMode"
|
||||
| "showRooIgnoredFiles"
|
||||
| "maxReadFileLine"
|
||||
| "maxImageFileSize"
|
||||
|
|
@ -56,6 +58,7 @@ export const ContextManagementSettings = ({
|
|||
listApiConfigMeta,
|
||||
maxOpenTabsContext,
|
||||
maxWorkspaceFiles,
|
||||
workspaceFilesMode,
|
||||
showRooIgnoredFiles,
|
||||
setCachedStateField,
|
||||
maxReadFileLine,
|
||||
|
|
@ -145,7 +148,19 @@ export const ContextManagementSettings = ({
|
|||
<span className="w-10">{maxWorkspaceFiles ?? 200}</span>
|
||||
</div>
|
||||
<div className="text-vscode-descriptionForeground text-sm mt-1">
|
||||
{t("settings:contextManagement.workspaceFiles.description")}
|
||||
{workspaceFilesMode === "folders"
|
||||
? t("settings:contextManagement.workspaceFiles.descriptionFoldersOnly")
|
||||
: t("settings:contextManagement.workspaceFiles.description")}
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<VSCodeCheckbox
|
||||
checked={workspaceFilesMode !== "folders"}
|
||||
onChange={(e: any) =>
|
||||
setCachedStateField("workspaceFilesMode", e.target.checked ? "files" : "folders")
|
||||
}
|
||||
data-testid="workspace-files-include-files-checkbox">
|
||||
{t("settings:contextManagement.workspaceFiles.includeFiles")}
|
||||
</VSCodeCheckbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
includeCurrentTime,
|
||||
includeCurrentCost,
|
||||
maxGitStatusFiles,
|
||||
workspaceFilesMode,
|
||||
} = cachedState
|
||||
|
||||
const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration])
|
||||
|
|
@ -394,6 +395,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
mcpEnabled,
|
||||
maxOpenTabsContext: Math.min(Math.max(0, maxOpenTabsContext ?? 20), 500),
|
||||
maxWorkspaceFiles: Math.min(Math.max(0, maxWorkspaceFiles ?? 200), 500),
|
||||
workspaceFilesMode: workspaceFilesMode ?? "files",
|
||||
showRooIgnoredFiles: showRooIgnoredFiles ?? true,
|
||||
maxReadFileLine: maxReadFileLine ?? -1,
|
||||
maxImageFileSize: maxImageFileSize ?? 5,
|
||||
|
|
@ -770,6 +772,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
|
|||
listApiConfigMeta={listApiConfigMeta ?? []}
|
||||
maxOpenTabsContext={maxOpenTabsContext}
|
||||
maxWorkspaceFiles={maxWorkspaceFiles ?? 200}
|
||||
workspaceFilesMode={workspaceFilesMode}
|
||||
showRooIgnoredFiles={showRooIgnoredFiles}
|
||||
maxReadFileLine={maxReadFileLine}
|
||||
maxImageFileSize={maxImageFileSize}
|
||||
|
|
|
|||
|
|
@ -610,7 +610,14 @@
|
|||
},
|
||||
"workspaceFiles": {
|
||||
"label": "Workspace files context limit",
|
||||
"description": "Maximum number of files to include in current working directory details. Higher values provide more context but increase token usage."
|
||||
"description": "Maximum number of files to include in current working directory details. Higher values provide more context but increase token usage.",
|
||||
"descriptionFoldersOnly": "Maximum number of folders to include in current working directory details. Folders-only mode provides structural overview without file listings.",
|
||||
"includeFiles": "Include individual files (uncheck for folders only)",
|
||||
"mode": {
|
||||
"placeholder": "Select display mode",
|
||||
"filesAndFolders": "Files and Folders",
|
||||
"foldersOnly": "Folders Only"
|
||||
}
|
||||
},
|
||||
"rooignore": {
|
||||
"label": "Show .rooignore'd files in lists and searches",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue