mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 17:27:54 +00:00
feat: Multi-Directory Workspace Support (part1: add --include-directories option) (#4605)
Co-authored-by: Allen Hutchison <adh@google.com>
This commit is contained in:
@@ -11,7 +11,6 @@ import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||
import { BaseTool, Icon, ToolResult } from './tools.js';
|
||||
import { Type } from '@google/genai';
|
||||
import { shortenPath, makeRelative } from '../utils/paths.js';
|
||||
import { isWithinRoot } from '../utils/fileUtils.js';
|
||||
import { Config } from '../config/config.js';
|
||||
|
||||
// Subset of 'Path' interface provided by 'glob' that we can implement for testing
|
||||
@@ -130,8 +129,10 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
params.path || '.',
|
||||
);
|
||||
|
||||
if (!isWithinRoot(searchDirAbsolute, this.config.getTargetDir())) {
|
||||
return `Search path ("${searchDirAbsolute}") resolves outside the tool's root directory ("${this.config.getTargetDir()}").`;
|
||||
const workspaceContext = this.config.getWorkspaceContext();
|
||||
if (!workspaceContext.isPathWithinWorkspace(searchDirAbsolute)) {
|
||||
const directories = workspaceContext.getDirectories();
|
||||
return `Search path ("${searchDirAbsolute}") resolves outside the allowed workspace directories: ${directories.join(', ')}`;
|
||||
}
|
||||
|
||||
const targetDir = searchDirAbsolute || this.config.getTargetDir();
|
||||
@@ -189,10 +190,27 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
}
|
||||
|
||||
try {
|
||||
const searchDirAbsolute = path.resolve(
|
||||
this.config.getTargetDir(),
|
||||
params.path || '.',
|
||||
);
|
||||
const workspaceContext = this.config.getWorkspaceContext();
|
||||
const workspaceDirectories = workspaceContext.getDirectories();
|
||||
|
||||
// If a specific path is provided, resolve it and check if it's within workspace
|
||||
let searchDirectories: readonly string[];
|
||||
if (params.path) {
|
||||
const searchDirAbsolute = path.resolve(
|
||||
this.config.getTargetDir(),
|
||||
params.path,
|
||||
);
|
||||
if (!workspaceContext.isPathWithinWorkspace(searchDirAbsolute)) {
|
||||
return {
|
||||
llmContent: `Error: Path "${params.path}" is not within any workspace directory`,
|
||||
returnDisplay: `Path is not within workspace`,
|
||||
};
|
||||
}
|
||||
searchDirectories = [searchDirAbsolute];
|
||||
} else {
|
||||
// Search across all workspace directories
|
||||
searchDirectories = workspaceDirectories;
|
||||
}
|
||||
|
||||
// Get centralized file discovery service
|
||||
const respectGitIgnore =
|
||||
@@ -200,17 +218,26 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
this.config.getFileFilteringRespectGitIgnore();
|
||||
const fileDiscovery = this.config.getFileService();
|
||||
|
||||
const entries = (await glob(params.pattern, {
|
||||
cwd: searchDirAbsolute,
|
||||
withFileTypes: true,
|
||||
nodir: true,
|
||||
stat: true,
|
||||
nocase: !params.case_sensitive,
|
||||
dot: true,
|
||||
ignore: ['**/node_modules/**', '**/.git/**'],
|
||||
follow: false,
|
||||
signal,
|
||||
})) as GlobPath[];
|
||||
// Collect entries from all search directories
|
||||
let allEntries: GlobPath[] = [];
|
||||
|
||||
for (const searchDir of searchDirectories) {
|
||||
const entries = (await glob(params.pattern, {
|
||||
cwd: searchDir,
|
||||
withFileTypes: true,
|
||||
nodir: true,
|
||||
stat: true,
|
||||
nocase: !params.case_sensitive,
|
||||
dot: true,
|
||||
ignore: ['**/node_modules/**', '**/.git/**'],
|
||||
follow: false,
|
||||
signal,
|
||||
})) as GlobPath[];
|
||||
|
||||
allEntries = allEntries.concat(entries);
|
||||
}
|
||||
|
||||
const entries = allEntries;
|
||||
|
||||
// Apply git-aware filtering if enabled and in git repository
|
||||
let filteredEntries = entries;
|
||||
@@ -236,7 +263,12 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
}
|
||||
|
||||
if (!filteredEntries || filteredEntries.length === 0) {
|
||||
let message = `No files found matching pattern "${params.pattern}" within ${searchDirAbsolute}.`;
|
||||
let message = `No files found matching pattern "${params.pattern}"`;
|
||||
if (searchDirectories.length === 1) {
|
||||
message += ` within ${searchDirectories[0]}`;
|
||||
} else {
|
||||
message += ` within ${searchDirectories.length} workspace directories`;
|
||||
}
|
||||
if (gitIgnoredCount > 0) {
|
||||
message += ` (${gitIgnoredCount} files were git-ignored)`;
|
||||
}
|
||||
@@ -263,7 +295,12 @@ export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||
const fileListDescription = sortedAbsolutePaths.join('\n');
|
||||
const fileCount = sortedAbsolutePaths.length;
|
||||
|
||||
let resultMessage = `Found ${fileCount} file(s) matching "${params.pattern}" within ${searchDirAbsolute}`;
|
||||
let resultMessage = `Found ${fileCount} file(s) matching "${params.pattern}"`;
|
||||
if (searchDirectories.length === 1) {
|
||||
resultMessage += ` within ${searchDirectories[0]}`;
|
||||
} else {
|
||||
resultMessage += ` across ${searchDirectories.length} workspace directories`;
|
||||
}
|
||||
if (gitIgnoredCount > 0) {
|
||||
resultMessage += ` (${gitIgnoredCount} additional files were git-ignored)`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user