frigg 0.3.2

Local-first MCP server for code understanding.
Documentation
#[derive(Debug, Clone)]
pub(super) struct QueryContext {
    query: String,
}

impl QueryContext {
    pub(super) fn new(query_text: &str) -> Self {
        Self {
            query: query_text.trim().to_ascii_lowercase(),
        }
    }

    pub(super) fn has_any(&self, needles: &[&str]) -> bool {
        needles.iter().any(|needle| self.query.contains(needle))
    }

    pub(super) fn has_any_token(&self, needles: &[&str]) -> bool {
        needles.iter().any(|needle| self.has_token(needle))
    }

    fn has_token(&self, needle: &str) -> bool {
        self.query
            .split(|ch: char| !(ch.is_ascii_alphanumeric() || matches!(ch, '.' | '_' | '-')))
            .any(|token| !token.is_empty() && token == needle)
    }

    pub(super) fn has_blade_ui_surface_terms(&self) -> bool {
        self.has_any(&[
            "component",
            "components",
            "view",
            "views",
            "slot",
            "section",
        ])
    }

    pub(super) fn has_ui_runtime_surface_terms(&self) -> bool {
        self.has_any(&[
            "canvas",
            "dashboard",
            "editor",
            "layout",
            "message",
            "messages",
            "node details",
            "panel",
            "panels",
            "screen",
            "viewmodel",
        ])
    }

    pub(super) fn has_backend_runtime_surface_terms(&self) -> bool {
        self.backend_runtime_surface_signal_count() >= 2
    }

    pub(super) fn has_blade_form_action_terms(&self) -> bool {
        self.has_any(&[
            "form", "forms", "modal", "modals", "partial", "partials", "table", "tables",
        ])
    }

    pub(super) fn has_manifest_hint(&self) -> bool {
        self.has_any(&[
            "cargo",
            "pyproject",
            "composer",
            "requirements",
            "pipfile",
            "tsconfig",
            "go.mod",
            "go.sum",
            "pnpm-workspace",
            "turbo",
            "gradle",
            "nimble",
            "rockspec",
            "mix.exs",
        ])
    }

    pub(super) fn mentions_rust_family(&self) -> bool {
        self.has_any(&[
            "cargo",
            "cargo.toml",
            "cargo.lock",
            "rust",
            "crate",
            "crates",
        ])
    }

    pub(super) fn mentions_php_family(&self) -> bool {
        self.has_any(&[
            "php", "composer", "artisan", "laravel", "blade", "livewire", "flux",
        ])
    }

    pub(super) fn mentions_typescript_family(&self) -> bool {
        self.has_any(&[
            "typescript",
            "tsconfig",
            "tsx",
            "vitest",
            "vite",
            "jest",
            "playwright",
            "nextjs",
            "deno",
            "vue",
            "js sdk",
            "pnpm",
            "turbo",
            "node-cli",
        ])
    }

    pub(super) fn mentions_supported_language_family(&self) -> bool {
        self.mentions_rust_family()
            || self.mentions_php_family()
            || self.mentions_typescript_family()
            || self.mentions_python_family()
            || self.mentions_go_family()
            || self.mentions_kotlin_family()
            || self.mentions_lua_family()
            || self.mentions_roc_family()
            || self.mentions_nim_family()
    }

    pub(super) fn mentions_python_family(&self) -> bool {
        self.has_any(&[
            "python",
            "pyproject",
            "pipfile",
            "requirements.txt",
            "pytest",
        ])
    }

    pub(super) fn mentions_go_family(&self) -> bool {
        self.has_any(&["main.go", "go.mod", "go.sum", "go module"]) || self.has_token("golang")
    }

    pub(super) fn mentions_kotlin_family(&self) -> bool {
        self.has_any(&[
            "kotlin",
            "gradle",
            "gradle.kts",
            "android",
            "viewmodel",
            "compose",
        ])
    }

    pub(super) fn mentions_lua_family(&self) -> bool {
        self.has_any(&["lua", "luarocks", "rockspec", "neovim", "nvim"])
    }

    pub(super) fn mentions_roc_family(&self) -> bool {
        self.has_any(&["roc-lang", "main.roc"]) || self.has_token("roc")
    }

    pub(super) fn mentions_nim_family(&self) -> bool {
        self.has_any(&["nimble", ".nim", ".nims"]) || self.has_token("nim")
    }

    pub(super) fn is_runtime_config_shorthand(&self) -> bool {
        matches!(self.query.as_str(), "config" | "configuration")
    }

    pub(super) fn mentions_laravel_ui(&self) -> bool {
        self.has_any(&["blade", "livewire", "flux"])
            && (self.has_blade_ui_surface_terms() || self.has_blade_form_action_terms())
    }

    pub(super) fn has_strong_test_focus_terms(&self) -> bool {
        self.has_any(&[
            "fixture",
            "fixtures",
            "integration",
            "scenario",
            "assert",
            "coverage",
            "parity",
            "replay",
            "conformance",
            "inspector",
        ])
    }

    pub(super) fn has_runtime_supporting_terms(&self) -> bool {
        self.has_any(&[
            "test",
            "tests",
            "playwright",
            "cli",
            "command",
            "commands",
            "bootstrap",
            "startup",
            "handler",
            "handlers",
            "transport",
            "request",
            "requests",
        ])
    }

    pub(super) fn mentions_model_data_surface(&self) -> bool {
        self.has_any(&[
            "model",
            "models",
            "migration",
            "migrations",
            "seeder",
            "seeders",
            "factory",
            "factories",
            "policy",
            "policies",
            "validation",
            "database",
            "schema",
            "table",
            "tables",
        ])
    }

    pub(super) fn mentions_playbooks(&self) -> bool {
        self.has_any(&["playbook", "playbooks"])
    }

    fn backend_runtime_surface_signal_count(&self) -> usize {
        [
            self.has_any(&["api"]),
            self.has_any(&["controller", "controllers"]),
            self.has_any(&["route", "routes", "router", "routers"]),
            self.has_any(&["service", "services"]),
            self.has_any(&["worker", "workers"]),
            self.has_any(&["webhook", "webhooks"]),
            self.has_any(&["execution", "executions", "executor", "executors"]),
            self.has_any(&["task runner", "task-runner", "task runners", "task-runners"]),
            self.has_any(&["sdk", "sdks"]),
            self.has_any(&["client", "clients"]),
            self.has_any(&["crawl", "crawler", "crawlers"]),
            self.has_any(&["scrape", "scraper", "scrapers"]),
            self.has_any(&["batch", "batches"]),
        ]
        .into_iter()
        .filter(|matched| *matched)
        .count()
    }
}