in packages/core/src/tools/ls.ts [201:312]
async execute(
params: LSToolParams,
_signal: AbortSignal,
): Promise<ToolResult> {
const validationError = this.validateToolParams(params);
if (validationError) {
return this.errorResult(
`Error: Invalid parameters provided. Reason: ${validationError}`,
`Failed to execute tool.`,
);
}
try {
const stats = fs.statSync(params.path);
if (!stats) {
// fs.statSync throws on non-existence, so this check might be redundant
// but keeping for clarity. Error message adjusted.
return this.errorResult(
`Error: Directory not found or inaccessible: ${params.path}`,
`Directory not found or inaccessible.`,
);
}
if (!stats.isDirectory()) {
return this.errorResult(
`Error: Path is not a directory: ${params.path}`,
`Path is not a directory.`,
);
}
const files = fs.readdirSync(params.path);
// Get centralized file discovery service
const respectGitIgnore =
params.respect_git_ignore ??
this.config.getFileFilteringRespectGitIgnore();
const fileDiscovery = this.config.getFileService();
const entries: FileEntry[] = [];
let gitIgnoredCount = 0;
if (files.length === 0) {
// Changed error message to be more neutral for LLM
return {
llmContent: `Directory ${params.path} is empty.`,
returnDisplay: `Directory is empty.`,
};
}
for (const file of files) {
if (this.shouldIgnore(file, params.ignore)) {
continue;
}
const fullPath = path.join(params.path, file);
const relativePath = path.relative(this.rootDirectory, fullPath);
// Check if this file should be git-ignored (only in git repositories)
if (
respectGitIgnore &&
fileDiscovery.shouldGitIgnoreFile(relativePath)
) {
gitIgnoredCount++;
continue;
}
try {
const stats = fs.statSync(fullPath);
const isDir = stats.isDirectory();
entries.push({
name: file,
path: fullPath,
isDirectory: isDir,
size: isDir ? 0 : stats.size,
modifiedTime: stats.mtime,
});
} catch (error) {
// Log error internally but don't fail the whole listing
console.error(`Error accessing ${fullPath}: ${error}`);
}
}
// Sort entries (directories first, then alphabetically)
entries.sort((a, b) => {
if (a.isDirectory && !b.isDirectory) return -1;
if (!a.isDirectory && b.isDirectory) return 1;
return a.name.localeCompare(b.name);
});
// Create formatted content for LLM
const directoryContent = entries
.map((entry) => `${entry.isDirectory ? '[DIR] ' : ''}${entry.name}`)
.join('\n');
let resultMessage = `Directory listing for ${params.path}:\n${directoryContent}`;
if (gitIgnoredCount > 0) {
resultMessage += `\n\n(${gitIgnoredCount} items were git-ignored)`;
}
let displayMessage = `Listed ${entries.length} item(s).`;
if (gitIgnoredCount > 0) {
displayMessage += ` (${gitIgnoredCount} git-ignored)`;
}
return {
llmContent: resultMessage,
returnDisplay: displayMessage,
};
} catch (error) {
const errorMsg = `Error listing directory: ${error instanceof Error ? error.message : String(error)}`;
return this.errorResult(errorMsg, 'Failed to list directory.');
}
}