Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions src/agent_librarian/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,16 @@ def scan_file_inventory(
else None
)
includes = _clean_patterns(include_patterns)

# Optimizamos a Set para búsquedas O(1) veloces
excludes = DEFAULT_EXCLUDE_PATTERNS | set(
_clean_patterns(exclude_patterns, split_commas=True)
)

# Separamos patrones planos de nombres fijos para evitar fnmatchcase innecesarios
flat_excludes = {p for p in excludes if "/" not in p}
complex_excludes = {p for p in excludes if "/" in p}

if excluded_output == root:
return []

Expand All @@ -53,28 +60,44 @@ def scan_file_inventory(
for current, dirnames, filenames in os.walk(root, followlinks=False):
current_path = Path(current)
kept_dirs: list[str] = []

# Eliminamos llamadas físicas a .resolve() y filtramos en memoria RAM
for dirname in dirnames:
if dirname in flat_excludes:
continue

# Construcción lógica de ruta en memoria, evitando tocar el disco duro
candidate_path = current_path / dirname
if candidate_path.is_symlink():
continue
candidate = candidate_path.resolve()
relative = candidate.relative_to(root)
if _matches_any(relative, excludes):
relative = candidate_path.relative_to(root)
if complex_excludes and _matches_any(relative, complex_excludes):
continue

if excluded_output and (
candidate == excluded_output or excluded_output in candidate.parents
candidate_path == excluded_output or excluded_output in candidate_path.parents
):
continue
kept_dirs.append(dirname)

dirnames[:] = sorted(kept_dirs)

for filename in sorted(filenames):
if filename in flat_excludes:
continue

path = current_path / filename
if path.is_symlink():
continue

relative = path.relative_to(root)
if path.is_symlink() or _matches_any(relative, excludes):
if complex_excludes and _matches_any(relative, complex_excludes):
continue

if includes and not _matches_any(relative, includes):
continue

files.append(path)

return sorted(files, key=lambda path: path.relative_to(root).as_posix())
Expand Down Expand Up @@ -124,4 +147,4 @@ def _matches_any(relative: Path, patterns: Iterable[str]) -> bool:
return True
if pattern.startswith("**/") and fnmatchcase(path, pattern[3:]):
return True
return False
return False