Ctrl K
ComunidadGuías…

butler/tools/project_tools_ops.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Best-effort helpers for project tool allowlists (P0-A)."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any

from butler.core.best_effort import safe_best_effort

if TYPE_CHECKING:
    from butler.project import Project

logger = logging.getLogger(__name__)


def opencode_tool_enabled() -> bool:
    def _run() -> bool:
        from butler.extensions.opencode import opencode_enabled

        return bool(opencode_enabled())

    result = safe_best_effort(_run, label="project_tools.opencode_enabled", default=False)
    return bool(result)


_DEV_EXTRA_TOOLS = frozenset({
    "dev_status",
    "dev_verify",
    "dev_review",
    "dev_rollback",
    "dev_search_symbols",
    "run_pytest",
})


def dev_engine_extra_tools() -> set[str]:
    def _run() -> set[str]:
        from butler.dev_engine.dev_tools import dev_engine_enabled

        if not dev_engine_enabled():
            return set()
        return set(_DEV_EXTRA_TOOLS)

    result = safe_best_effort(_run, label="project_tools.dev_engine_enabled", default=set())
    return result if isinstance(result, set) else set()


def mcp_tool_allowed(name: str) -> bool:
    def _run() -> bool:
        from butler.mcp.naming import is_mcp_registered_name

        return bool(is_mcp_registered_name(name))

    result = safe_best_effort(_run, label="project_tools.mcp_allowed", default=False)
    return bool(result)


def workflow_step_tool_allowlist(project: "Project | None") -> set[str] | None:
    def _run() -> set[str] | None:
        from pathlib import Path

        from butler.execution_context import get_current_workflow_step
        from butler.permissions import get_workflow_step_tool_allowlist

        step_id = get_current_workflow_step()
        if not step_id:
            return None
        ws = Path(project.workspace) if project is not None else None
        allowlist = get_workflow_step_tool_allowlist(step_id, workspace=ws)
        return allowlist if isinstance(allowlist, set) else None

    result = safe_best_effort(
        _run,
        label="project_tools.workflow_step_allowlist",
        default=None,
    )
    return result if result is None or isinstance(result, set) else None


def optimize_tool_definitions_safe(filtered: list[dict[str, Any]]) -> list[dict[str, Any]]:
    def _run() -> list[dict[str, Any]]:
        from butler.core.schema_optimizer import optimize_tool_definitions

        return optimize_tool_definitions(filtered) or filtered

    result = safe_best_effort(
        _run,
        label="project_tools.optimize_schema",
        default=filtered,
    )
    return result if isinstance(result, list) else filtered