Skip to content

Commit 15cb6de

Browse files
committed
refactor: Make ls.py tool cross-platform and default path to current directory
Co-authored-by: cecli (openai/gemini_cli/gemini-2.5-pro)
1 parent 7361036 commit 15cb6de

1 file changed

Lines changed: 46 additions & 33 deletions

File tree

cecli/tools/ls.py

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,80 @@ class Tool(BaseTool):
88
SCHEMA = {
99
"type": "function",
1010
"function": {
11-
"name": "Ls",
12-
"description": "List files in a directory.",
11+
"name": "ls",
12+
"description": "List files in a directory. Paths are relative to the project root.",
1313
"parameters": {
1414
"type": "object",
1515
"properties": {
16-
"directory": {
16+
"path": {
1717
"type": "string",
18-
"description": "The directory to list.",
19-
},
18+
"description": (
19+
"The path of the directory to list, relative to the project root. "
20+
"Defaults to the project root."
21+
),
22+
"default": ".",
23+
}
2024
},
21-
"required": ["directory"],
25+
"required": [],
2226
},
2327
},
2428
}
2529

2630
@classmethod
27-
def execute(cls, coder, dir_path=None, directory=None, **kwargs):
28-
# Handle both positional and keyword arguments for backward compatibility
29-
if dir_path is None and directory is not None:
30-
dir_path = directory
31-
elif dir_path is None:
32-
return "Error: Missing directory parameter"
31+
def execute(cls, coder, path=None, directory=None, **kwargs):
3332
"""
3433
List files in directory and optionally add some to context.
3534
3635
This provides information about the structure of the codebase,
3736
similar to how a developer would explore directories.
3837
"""
38+
# Handle both positional and keyword arguments for backward compatibility
39+
dir_path = path or directory or "."
40+
3941
try:
40-
# Make the path relative to root if it's absolute
41-
if dir_path.startswith("/"):
42-
rel_dir = os.path.relpath(dir_path, coder.root)
43-
else:
44-
rel_dir = dir_path
42+
# Create an absolute path from the provided relative path
43+
abs_path = os.path.abspath(os.path.join(coder.root, dir_path))
4544

46-
# Get absolute path
47-
abs_dir = coder.abs_root_path(rel_dir)
45+
# Security check: ensure the resolved path is within the project root
46+
if not abs_path.startswith(os.path.abspath(coder.root)):
47+
coder.io.tool_error(
48+
f"Error: Path '{dir_path}' attempts to access files outside the project"
49+
" root."
50+
)
51+
return "Error: Path is outside the project root."
4852

4953
# Check if path exists
50-
if not os.path.exists(abs_dir):
51-
coder.io.tool_output(f"⚠️ Directory '{dir_path}' not found")
54+
if not os.path.exists(abs_path):
55+
coder.io.tool_output(f"⚠️ Path '{dir_path}' not found")
5256
return "Directory not found"
5357

5458
# Get directory contents
5559
contents = []
56-
try:
57-
with os.scandir(abs_dir) as entries:
58-
for entry in entries:
59-
if entry.is_file() and not entry.name.startswith("."):
60-
rel_path = os.path.join(rel_dir, entry.name)
61-
contents.append(rel_path)
62-
except NotADirectoryError:
63-
# If it's a file, just return the file
64-
contents = [rel_dir]
60+
if os.path.isdir(abs_path):
61+
# It's a directory, list its contents
62+
try:
63+
with os.scandir(abs_path) as entries:
64+
for entry in entries:
65+
if entry.is_file() and not entry.name.startswith("."):
66+
rel_path = os.path.relpath(entry.path, coder.root)
67+
contents.append(rel_path)
68+
except OSError as e:
69+
coder.io.tool_error(f"Error listing directory '{dir_path}': {e}")
70+
return f"Error: {e}"
71+
elif os.path.isfile(abs_path):
72+
# It's a file, just return its relative path
73+
contents.append(os.path.relpath(abs_path, coder.root))
6574

6675
if contents:
6776
coder.io.tool_output(f"📋 Listed {len(contents)} file(s) in '{dir_path}'")
68-
if len(contents) > 10:
69-
return f"Found {len(contents)} files: {', '.join(contents[:10])}..."
77+
sorted_contents = sorted(contents)
78+
if len(sorted_contents) > 10:
79+
return (
80+
f"Found {len(sorted_contents)} files:"
81+
f" {', '.join(sorted_contents[:10])}..."
82+
)
7083
else:
71-
return f"Found {len(contents)} files: {', '.join(contents)}"
84+
return f"Found {len(sorted_contents)} files: {', '.join(sorted_contents)}"
7285
else:
7386
coder.io.tool_output(f"📋 No files found in '{dir_path}'")
7487
return "No files found in directory"

0 commit comments

Comments
 (0)