v2.6.0 (#524)
Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Clément Sirieix <clement.sirieix@mistral.ai> Co-authored-by: Gauthier Guinet <43207538+Gguinet@users.noreply.github.com> Co-authored-by: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai> Co-authored-by: Michel Thomazo <51709227+michelTho@users.noreply.github.com> Co-authored-by: Quentin <torroba.q@gmail.com> Co-authored-by: Simon <80467011+sorgfresser@users.noreply.github.com> Co-authored-by: Simon Van de Kerckhove <simon.vandekerckhove@mistral.ai> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: angelapopopo <angele.lenglemetz@mistral.ai> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
parent
5103019b01
commit
eb580209d4
180 changed files with 11136 additions and 1030 deletions
|
|
@ -1,6 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from vibe.core.paths._local_config_walk import walk_local_config_dirs_all
|
||||
from vibe.core.paths._local_config_walk import (
|
||||
WALK_MAX_DEPTH,
|
||||
has_config_dirs_nearby,
|
||||
walk_local_config_dirs_all,
|
||||
)
|
||||
from vibe.core.paths._vibe_home import (
|
||||
DEFAULT_TOOL_DIR,
|
||||
GLOBAL_ENV_FILE,
|
||||
|
|
@ -26,6 +30,8 @@ __all__ = [
|
|||
"SESSION_LOG_DIR",
|
||||
"TRUSTED_FOLDERS_FILE",
|
||||
"VIBE_HOME",
|
||||
"WALK_MAX_DEPTH",
|
||||
"GlobalPath",
|
||||
"has_config_dirs_nearby",
|
||||
"walk_local_config_dirs_all",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections import deque
|
||||
from functools import cache
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from vibe.core.autocompletion.file_indexer.ignore_rules import WALK_SKIP_DIR_NAMES
|
||||
|
||||
logger = logging.getLogger("vibe")
|
||||
|
||||
_VIBE_DIR = ".vibe"
|
||||
_TOOLS_SUBDIR = Path(_VIBE_DIR) / "tools"
|
||||
_VIBE_SKILLS_SUBDIR = Path(_VIBE_DIR) / "skills"
|
||||
|
|
@ -13,27 +17,117 @@ _AGENTS_SUBDIR = Path(_VIBE_DIR) / "agents"
|
|||
_AGENTS_DIR = ".agents"
|
||||
_AGENTS_SKILLS_SUBDIR = Path(_AGENTS_DIR) / "skills"
|
||||
|
||||
WALK_MAX_DEPTH = 4
|
||||
_MAX_DIRS = 2000
|
||||
|
||||
|
||||
def _collect_config_dirs_at(
|
||||
path: Path,
|
||||
entries: set[str],
|
||||
tools: list[Path],
|
||||
skills: list[Path],
|
||||
agents: list[Path],
|
||||
) -> None:
|
||||
"""Check a single directory for .vibe/ and .agents/ config subdirs."""
|
||||
if _VIBE_DIR in entries:
|
||||
if (candidate := path / _TOOLS_SUBDIR).is_dir():
|
||||
tools.append(candidate)
|
||||
if (candidate := path / _VIBE_SKILLS_SUBDIR).is_dir():
|
||||
skills.append(candidate)
|
||||
if (candidate := path / _AGENTS_SUBDIR).is_dir():
|
||||
agents.append(candidate)
|
||||
if _AGENTS_DIR in entries:
|
||||
if (candidate := path / _AGENTS_SKILLS_SUBDIR).is_dir():
|
||||
skills.append(candidate)
|
||||
|
||||
|
||||
def _iter_child_dirs(path: Path, entries: set[str]) -> list[Path]:
|
||||
"""Return sorted child directories to descend into, skipping ignored and dot-dirs."""
|
||||
children: list[Path] = []
|
||||
for name in sorted(entries):
|
||||
if name in WALK_SKIP_DIR_NAMES or name.startswith("."):
|
||||
continue
|
||||
child = path / name
|
||||
try:
|
||||
if child.is_dir():
|
||||
children.append(child)
|
||||
except OSError:
|
||||
continue
|
||||
return children
|
||||
|
||||
|
||||
@cache
|
||||
def walk_local_config_dirs_all(
|
||||
root: Path,
|
||||
) -> tuple[tuple[Path, ...], tuple[Path, ...], tuple[Path, ...]]:
|
||||
"""Discover .vibe/ and .agents/ config directories under *root*.
|
||||
|
||||
Uses breadth-first search bounded by ``WALK_MAX_DEPTH`` and ``_MAX_DIRS``
|
||||
to avoid unbounded traversal in large repositories.
|
||||
"""
|
||||
tools_dirs: list[Path] = []
|
||||
skills_dirs: list[Path] = []
|
||||
agents_dirs: list[Path] = []
|
||||
|
||||
resolved_root = root.resolve()
|
||||
for dirpath, dirnames, _ in os.walk(resolved_root, topdown=True):
|
||||
dir_set = frozenset(dirnames)
|
||||
path = Path(dirpath)
|
||||
if _VIBE_DIR in dir_set:
|
||||
if (candidate := path / _TOOLS_SUBDIR).is_dir():
|
||||
tools_dirs.append(candidate)
|
||||
if (candidate := path / _VIBE_SKILLS_SUBDIR).is_dir():
|
||||
skills_dirs.append(candidate)
|
||||
if (candidate := path / _AGENTS_SUBDIR).is_dir():
|
||||
agents_dirs.append(candidate)
|
||||
if _AGENTS_DIR in dir_set:
|
||||
if (candidate := path / _AGENTS_SKILLS_SUBDIR).is_dir():
|
||||
skills_dirs.append(candidate)
|
||||
dirnames[:] = sorted(d for d in dirnames if d not in WALK_SKIP_DIR_NAMES)
|
||||
queue: deque[tuple[Path, int]] = deque([(resolved_root, 0)])
|
||||
visited = 0
|
||||
|
||||
while queue and visited < _MAX_DIRS:
|
||||
current, depth = queue.popleft()
|
||||
visited += 1
|
||||
|
||||
try:
|
||||
entries = set(os.listdir(current))
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
_collect_config_dirs_at(current, entries, tools_dirs, skills_dirs, agents_dirs)
|
||||
|
||||
if depth < WALK_MAX_DEPTH:
|
||||
queue.extend(
|
||||
(child, depth + 1) for child in _iter_child_dirs(current, entries)
|
||||
)
|
||||
|
||||
if visited >= _MAX_DIRS:
|
||||
logger.warning(
|
||||
"Config directory scan reached directory limit (%d dirs) at %s",
|
||||
_MAX_DIRS,
|
||||
resolved_root,
|
||||
)
|
||||
|
||||
return (tuple(tools_dirs), tuple(skills_dirs), tuple(agents_dirs))
|
||||
|
||||
|
||||
def has_config_dirs_nearby(
|
||||
root: Path, *, max_depth: int = WALK_MAX_DEPTH, max_dirs: int = 200
|
||||
) -> bool:
|
||||
"""Quick check for .vibe/ or .agents/ config dirs in the near subtree.
|
||||
|
||||
Returns ``True`` as soon as any config directory is found, without
|
||||
enumerating all of them.
|
||||
"""
|
||||
resolved = root.resolve()
|
||||
queue: deque[tuple[Path, int]] = deque([(resolved, 0)])
|
||||
visited = 0
|
||||
found: list[Path] = []
|
||||
|
||||
while queue and visited < max_dirs:
|
||||
current, depth = queue.popleft()
|
||||
visited += 1
|
||||
|
||||
try:
|
||||
entries = set(os.listdir(current))
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
_collect_config_dirs_at(current, entries, found, found, found)
|
||||
if found:
|
||||
return True
|
||||
|
||||
if depth < max_depth:
|
||||
queue.extend(
|
||||
(child, depth + 1) for child in _iter_child_dirs(current, entries)
|
||||
)
|
||||
|
||||
return False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue