跳轉至

Vibe Module API 參考

Boring 的核心感知與決策引擎。

Vibe Engine (核心引擎)

boring.vibe.engine

Vibe Engine (V10.23 Enhanced).

Core dispatcher that routes requests to appropriate language handlers.

V10.23 Enhancements: - Performance tracking for all operations - Analysis result caching (LRU with TTL) - Handler performance statistics - Integration with AdaptiveCache for cross-request optimization

VibePerformanceStats dataclass

V10.23: Performance tracking for Vibe operations.

Source code in src/boring/vibe/engine.py
@dataclass
class VibePerformanceStats:
    """V10.23: Performance tracking for Vibe operations."""

    total_analyses: int = 0
    total_reviews: int = 0
    total_test_gens: int = 0
    cache_hits: int = 0
    cache_misses: int = 0
    total_time_ms: float = 0.0
    handler_times: dict = field(default_factory=dict)  # handler_name -> total_ms

    @property
    def cache_hit_rate(self) -> float:
        total = self.cache_hits + self.cache_misses
        return self.cache_hits / total if total > 0 else 0.0

    @property
    def avg_operation_time_ms(self) -> float:
        total_ops = self.total_analyses + self.total_reviews + self.total_test_gens
        return self.total_time_ms / total_ops if total_ops > 0 else 0.0

VibeEngine

Main engine for Vibe Coder Pro tools (V10.23 Enhanced). Uses Strategy Pattern to select the correct handler for a file.

V10.23 Features: - LRU cache for analysis results (reduces repeated work) - Performance tracking per handler - Statistics for optimization insights

Source code in src/boring/vibe/engine.py
class VibeEngine:
    """
    Main engine for Vibe Coder Pro tools (V10.23 Enhanced).
    Uses Strategy Pattern to select the correct handler for a file.

    V10.23 Features:
    - LRU cache for analysis results (reduces repeated work)
    - Performance tracking per handler
    - Statistics for optimization insights
    """

    # V10.23: Cache configuration
    CACHE_MAX_SIZE = 50
    CACHE_TTL_SECONDS = 300  # 5 minutes

    def __init__(self):
        self._handlers: dict[str, BaseHandler] = {}
        self._default_handler: BaseHandler | None = None

        # V10.23: Analysis cache (key -> (result, timestamp))
        self._analysis_cache: dict[str, tuple] = {}
        self._review_cache: dict[str, tuple] = {}

        # V10.23: Performance tracking
        self._stats = VibePerformanceStats()

    def register_handler(self, handler: BaseHandler):
        """Register a language handler."""
        for ext in handler.supported_extensions:
            self._handlers[ext.lower()] = handler

    def get_handler(self, file_path: str) -> BaseHandler | None:
        """Get the appropriate handler for a file path."""
        ext = Path(file_path).suffix.lower()
        return self._handlers.get(ext, self._default_handler)

    def _cache_key(self, file_path: str, source_code: str, operation: str) -> str:
        """V10.23: Generate cache key from file and content."""
        # Use sha256 for cache key (non-security)
        content_hash = hashlib.sha256(source_code.encode()).hexdigest()[:16]
        return f"{operation}:{file_path}:{content_hash}"

    def _get_cached(self, cache: dict, key: str):
        """V10.23: Get from cache if not expired."""
        if key in cache:
            result, timestamp = cache[key]
            if time.time() - timestamp < self.CACHE_TTL_SECONDS:
                self._stats.cache_hits += 1
                return result
            else:
                del cache[key]  # Expired
        self._stats.cache_misses += 1
        return None

    def _set_cached(self, cache: dict, key: str, result):
        """V10.23: Add to cache with LRU eviction."""
        if len(cache) >= self.CACHE_MAX_SIZE:
            # Remove oldest entry
            oldest_key = min(cache.keys(), key=lambda k: cache[k][1])
            del cache[oldest_key]
        cache[key] = (result, time.time())

    def _track_time(self, handler_name: str, elapsed_ms: float):
        """V10.23: Track operation time per handler."""
        self._stats.total_time_ms += elapsed_ms
        if handler_name not in self._stats.handler_times:
            self._stats.handler_times[handler_name] = 0.0
        self._stats.handler_times[handler_name] += elapsed_ms

    def analyze_for_test_gen(self, file_path: str, source_code: str) -> TestGenResult:
        """Route test generation analysis to appropriate handler (V10.23: cached)."""
        handler = self.get_handler(file_path)
        if not handler:
            raise ValueError(
                T(
                    "vibe_unsupported_file_type",
                    suffix=Path(file_path).suffix,
                )
            )

        # V10.23: Check cache
        cache_key = self._cache_key(file_path, source_code, "test_gen")
        cached = self._get_cached(self._analysis_cache, cache_key)
        if cached:
            return cached

        # Execute with timing
        start = time.time()
        result = handler.analyze_for_test_gen(file_path, source_code)
        elapsed_ms = (time.time() - start) * 1000

        # V10.23: Track stats
        self._stats.total_analyses += 1
        self._track_time(handler.language_name, elapsed_ms)

        # V10.23: Cache result
        self._set_cached(self._analysis_cache, cache_key, result)

        return result

    def perform_code_review(
        self, file_path: str, source_code: str, focus: str = "all"
    ) -> ReviewResult:
        """Route code review to appropriate handler (V10.23: cached)."""
        handler = self.get_handler(file_path)
        if not handler:
            raise ValueError(
                T(
                    "vibe_unsupported_file_type",
                    suffix=Path(file_path).suffix,
                )
            )

        # V10.23: Check cache (include focus in key)
        cache_key = self._cache_key(file_path, source_code, f"review_{focus}")
        cached = self._get_cached(self._review_cache, cache_key)
        if cached:
            return cached

        # Execute with timing
        start = time.time()
        result = handler.perform_code_review(file_path, source_code, focus)
        elapsed_ms = (time.time() - start) * 1000

        # V10.23: Track stats
        self._stats.total_reviews += 1
        self._track_time(handler.language_name, elapsed_ms)

        # V10.23: Cache result
        self._set_cached(self._review_cache, cache_key, result)

        return result

    def generate_test_code(self, result: TestGenResult, project_root: str) -> str:
        """Route test generation string creation."""
        handler = self.get_handler(result.file_path)
        if not handler:
            raise ValueError(T("vibe_no_handler_found", file_path=result.file_path))

        start = time.time()
        code = handler.generate_test_code(result, project_root)
        elapsed_ms = (time.time() - start) * 1000

        # V10.23: Track stats
        self._stats.total_test_gens += 1
        self._track_time(handler.language_name, elapsed_ms)

        return code

    def extract_dependencies(self, file_path: str, source_code: str) -> list[str]:
        """Route dependency extraction."""
        handler = self.get_handler(file_path)
        if not handler:
            return []
        return handler.extract_dependencies(file_path, source_code)

    def extract_documentation(self, file_path: str, source_code: str) -> DocResult:
        """Identify documentation and comments in code."""
        handler = self.get_handler(file_path)
        if not handler:
            return DocResult(file_path=file_path, module_doc="", items=[])
        return handler.extract_documentation(file_path, source_code)

    # =========================================================================
    # V10.23: Statistics and Cache Management
    # =========================================================================

    def get_stats(self) -> dict:
        """V10.23: Get performance statistics."""
        return {
            "total_analyses": self._stats.total_analyses,
            "total_reviews": self._stats.total_reviews,
            "total_test_gens": self._stats.total_test_gens,
            "cache_hit_rate": round(self._stats.cache_hit_rate, 3),
            "cache_hits": self._stats.cache_hits,
            "cache_misses": self._stats.cache_misses,
            "avg_operation_time_ms": round(self._stats.avg_operation_time_ms, 2),
            "handler_times": self._stats.handler_times,
            "analysis_cache_size": len(self._analysis_cache),
            "review_cache_size": len(self._review_cache),
        }

    def clear_cache(self):
        """V10.23: Clear all caches."""
        self._analysis_cache.clear()
        self._review_cache.clear()

    def get_stats_report(self) -> str:
        """V10.23: Get human-readable performance report."""
        stats = self.get_stats()
        lines = [
            "🚀 **Vibe Engine Performance (V10.23)**",
            f"- Total Operations: {stats['total_analyses'] + stats['total_reviews'] + stats['total_test_gens']}",
            f"- Cache Hit Rate: {stats['cache_hit_rate']:.1%}",
            f"- Avg Operation Time: {stats['avg_operation_time_ms']:.1f}ms",
            "",
            "**Handler Breakdown:**",
        ]
        for handler, time_ms in stats["handler_times"].items():
            lines.append(f"  - {handler}: {time_ms:.1f}ms total")

        return "\n".join(lines)
register_handler(handler)

Register a language handler.

Source code in src/boring/vibe/engine.py
def register_handler(self, handler: BaseHandler):
    """Register a language handler."""
    for ext in handler.supported_extensions:
        self._handlers[ext.lower()] = handler
get_handler(file_path)

Get the appropriate handler for a file path.

Source code in src/boring/vibe/engine.py
def get_handler(self, file_path: str) -> BaseHandler | None:
    """Get the appropriate handler for a file path."""
    ext = Path(file_path).suffix.lower()
    return self._handlers.get(ext, self._default_handler)
analyze_for_test_gen(file_path, source_code)

Route test generation analysis to appropriate handler (V10.23: cached).

Source code in src/boring/vibe/engine.py
def analyze_for_test_gen(self, file_path: str, source_code: str) -> TestGenResult:
    """Route test generation analysis to appropriate handler (V10.23: cached)."""
    handler = self.get_handler(file_path)
    if not handler:
        raise ValueError(
            T(
                "vibe_unsupported_file_type",
                suffix=Path(file_path).suffix,
            )
        )

    # V10.23: Check cache
    cache_key = self._cache_key(file_path, source_code, "test_gen")
    cached = self._get_cached(self._analysis_cache, cache_key)
    if cached:
        return cached

    # Execute with timing
    start = time.time()
    result = handler.analyze_for_test_gen(file_path, source_code)
    elapsed_ms = (time.time() - start) * 1000

    # V10.23: Track stats
    self._stats.total_analyses += 1
    self._track_time(handler.language_name, elapsed_ms)

    # V10.23: Cache result
    self._set_cached(self._analysis_cache, cache_key, result)

    return result
perform_code_review(file_path, source_code, focus='all')

Route code review to appropriate handler (V10.23: cached).

Source code in src/boring/vibe/engine.py
def perform_code_review(
    self, file_path: str, source_code: str, focus: str = "all"
) -> ReviewResult:
    """Route code review to appropriate handler (V10.23: cached)."""
    handler = self.get_handler(file_path)
    if not handler:
        raise ValueError(
            T(
                "vibe_unsupported_file_type",
                suffix=Path(file_path).suffix,
            )
        )

    # V10.23: Check cache (include focus in key)
    cache_key = self._cache_key(file_path, source_code, f"review_{focus}")
    cached = self._get_cached(self._review_cache, cache_key)
    if cached:
        return cached

    # Execute with timing
    start = time.time()
    result = handler.perform_code_review(file_path, source_code, focus)
    elapsed_ms = (time.time() - start) * 1000

    # V10.23: Track stats
    self._stats.total_reviews += 1
    self._track_time(handler.language_name, elapsed_ms)

    # V10.23: Cache result
    self._set_cached(self._review_cache, cache_key, result)

    return result
generate_test_code(result, project_root)

Route test generation string creation.

Source code in src/boring/vibe/engine.py
def generate_test_code(self, result: TestGenResult, project_root: str) -> str:
    """Route test generation string creation."""
    handler = self.get_handler(result.file_path)
    if not handler:
        raise ValueError(T("vibe_no_handler_found", file_path=result.file_path))

    start = time.time()
    code = handler.generate_test_code(result, project_root)
    elapsed_ms = (time.time() - start) * 1000

    # V10.23: Track stats
    self._stats.total_test_gens += 1
    self._track_time(handler.language_name, elapsed_ms)

    return code
extract_dependencies(file_path, source_code)

Route dependency extraction.

Source code in src/boring/vibe/engine.py
def extract_dependencies(self, file_path: str, source_code: str) -> list[str]:
    """Route dependency extraction."""
    handler = self.get_handler(file_path)
    if not handler:
        return []
    return handler.extract_dependencies(file_path, source_code)
extract_documentation(file_path, source_code)

Identify documentation and comments in code.

Source code in src/boring/vibe/engine.py
def extract_documentation(self, file_path: str, source_code: str) -> DocResult:
    """Identify documentation and comments in code."""
    handler = self.get_handler(file_path)
    if not handler:
        return DocResult(file_path=file_path, module_doc="", items=[])
    return handler.extract_documentation(file_path, source_code)
get_stats()

V10.23: Get performance statistics.

Source code in src/boring/vibe/engine.py
def get_stats(self) -> dict:
    """V10.23: Get performance statistics."""
    return {
        "total_analyses": self._stats.total_analyses,
        "total_reviews": self._stats.total_reviews,
        "total_test_gens": self._stats.total_test_gens,
        "cache_hit_rate": round(self._stats.cache_hit_rate, 3),
        "cache_hits": self._stats.cache_hits,
        "cache_misses": self._stats.cache_misses,
        "avg_operation_time_ms": round(self._stats.avg_operation_time_ms, 2),
        "handler_times": self._stats.handler_times,
        "analysis_cache_size": len(self._analysis_cache),
        "review_cache_size": len(self._review_cache),
    }
clear_cache()

V10.23: Clear all caches.

Source code in src/boring/vibe/engine.py
def clear_cache(self):
    """V10.23: Clear all caches."""
    self._analysis_cache.clear()
    self._review_cache.clear()
get_stats_report()

V10.23: Get human-readable performance report.

Source code in src/boring/vibe/engine.py
def get_stats_report(self) -> str:
    """V10.23: Get human-readable performance report."""
    stats = self.get_stats()
    lines = [
        "🚀 **Vibe Engine Performance (V10.23)**",
        f"- Total Operations: {stats['total_analyses'] + stats['total_reviews'] + stats['total_test_gens']}",
        f"- Cache Hit Rate: {stats['cache_hit_rate']:.1%}",
        f"- Avg Operation Time: {stats['avg_operation_time_ms']:.1f}ms",
        "",
        "**Handler Breakdown:**",
    ]
    for handler, time_ms in stats["handler_times"].items():
        lines.append(f"  - {handler}: {time_ms:.1f}ms total")

    return "\n".join(lines)

Vibe Analysis (分析器)

boring.vibe.analysis

Vibe Analysis Data Structures.

Defines the common data objects used across different language handlers.

CodeIssue dataclass

Represents a single issue found during code review.

Source code in src/boring/vibe/analysis.py
@dataclass
class CodeIssue:
    """Represents a single issue found during code review."""

    category: str  # e.g., "Naming", "Error Handling", "Performance", "Security"
    message: str
    severity: str  # "high", "medium", "low"
    line: int
    suggestion: str | None = None

CodeFunction dataclass

Represents a function definition.

Source code in src/boring/vibe/analysis.py
@dataclass
class CodeFunction:
    """Represents a function definition."""

    name: str
    args: list[str]
    docstring: str | None
    lineno: int
    is_async: bool = False
    is_exported: bool = True  # For JS/TS

CodeClass dataclass

Represents a class definition.

Source code in src/boring/vibe/analysis.py
@dataclass
class CodeClass:
    """Represents a class definition."""

    name: str
    methods: list[str]
    docstring: str | None
    lineno: int
    is_exported: bool = True

DocItem dataclass

Documentation for a code element (function/class).

Source code in src/boring/vibe/analysis.py
@dataclass
class DocItem:
    """Documentation for a code element (function/class)."""

    name: str
    type: str  # function, class, method
    docstring: str
    signature: str
    line_number: int
    params: list[str] = field(default_factory=list)

DocResult dataclass

Documentation extraction result.

Source code in src/boring/vibe/analysis.py
@dataclass
class DocResult:
    """Documentation extraction result."""

    file_path: str
    module_doc: str
    items: list[DocItem] = field(default_factory=list)
    score: int = 100  # 0-100 score based on issues

ReviewResult dataclass

Result of a code review analysis.

Source code in src/boring/vibe/analysis.py
@dataclass
class ReviewResult:
    """Result of a code review analysis."""

    file_path: str
    issues: list[CodeIssue] = field(default_factory=list)
    score: int = 100  # 0-100 score based on issues

TestGenResult dataclass

Result of test generation analysis.

Source code in src/boring/vibe/analysis.py
@dataclass
class TestGenResult:
    """Result of test generation analysis."""

    file_path: str
    functions: list[CodeFunction] = field(default_factory=list)
    classes: list[CodeClass] = field(default_factory=list)
    module_name: str = ""
    source_language: str = "python"  # python, javascript, typescript, etc.