import { type McpAttachment } from "./mcp-bridge.js"; export declare const GROVE_TOOL_PREFIX = "mcp__grove__"; export declare const GROVE_EXPLORE_TOOL = "mcp__grove__explore"; /** * True when the project is configured for grove's delegated local-LLM mode * (`mode: "mcp-llm"` in `.grove/config.json`). This mirrors grove's own surface * decision (`active_mode` in grove's `core/src/config.rs`, reached by * `determine_surface` in grove's `cli/src/mcp.rs`): the declared `mode` in * `.grove/config.json` is the single source of truth. * * Resolution (matches grove's `ModeChoice::None` branch): * 1. `.grove/config.json` present → explore iff `mode === "mcp-llm"`. A stale * legacy `.grove/explore.json` sitting alongside it is IGNORED — grove no * longer sniffs `explore.json` once `config.json` exists (GROVE-S03-T03), so * a project that declares `mode: "mcp"` but keeps an old `explore.json` is * served the standard structural surface, not explore-mode. * 2. `.grove/config.json` absent but legacy `.grove/explore.json` present → * true. grove auto-migrates `explore.json` → `config.json` (mode=mcp-llm) on * first load, so this transient pre-migration state still means explore. * 3. Neither file → false. * * A malformed/unreadable `config.json` degrades to false (structural surface), * matching grove's own fallback. Provisioning stays the user's job (grove's * interactive `init --as mcp-llm` TUI writes `config.json`); forge-cli only * detects it. */ export declare function isGroveExploreProject(cwd: string): boolean; /** * Decide whether to attach grove in explore-mode for this session. * * - An explicit `explore` override (from AttachGroveOptions) always wins. * - `FORGE_GROVE_NO_EXPLORE=1` forces the standard structural surface even in a * provisioned explore project (escape hatch, mirrors FORGE_GROVE_NO_AUTOINIT). * - Otherwise: explore-mode iff the project declares it (see * [`isGroveExploreProject`] — `mode: "mcp-llm"` in `.grove/config.json`, with * a legacy `.grove/explore.json` fallback). * * Note this only decides which surface to *ask* grove for. Grove's own health * probe has the final say: `serve --explore` with a down local LLM transparently * falls back to the 7 structural tools, and the bridge registers whatever grove * actually advertised — so a stale/unavailable explore config still degrades * cleanly with no extra logic here. */ export declare function shouldUseExplore(cwd: string, explicit?: boolean): boolean; /** * The grove code-navigation steering block — injected ONCE into the system * prompt (via project-orientation, which reaches both the main thread and * subagents) when grove is attached. This is the "fragment" that replaces * grove's CLAUDE.md INVARIANT: the steering lives in the host's system prompt, * so the user's project files (CLAUDE.md) stay untouched. Per-tool * `promptGuidelines` are deliberately NOT used — pi concatenates them across * every active tool with no cross-tool dedup, so a shared block would repeat * once per grove tool. * * The block branches on the ACTUAL discovered roster, not on the requested mode: * if grove served its explore-mode surface (`mcp__grove__explore` present) the * locator steering is emitted; otherwise the structural procedure. Because grove * falls back to the 7 structural tools when the local LLM is down, keying off the * real roster keeps the steering honest even when explore was requested but * couldn't be served. */ export declare function buildGroveSteering(toolNames: string[]): string; /** * Resolve a usable grove binary, or null if none works. * Precedence: explicit arg → FORGE_GROVE_BIN env → `grove` on PATH. * "Usable" means ` --version` exits 0. */ export declare function resolveGroveBin(explicit?: string): string | null; export interface GroveReadiness { /** Resolved grove binary, or null when grove is unavailable. */ bin: string | null; /** True when the project has a grove.lock (grammars provisioned). */ initialized: boolean; /** True when this call ran `grove init` to provision the project. */ ranInit: boolean; } export interface EnsureGroveOptions { /** Project root grove operates against. */ cwd: string; /** Explicit binary override. */ bin?: string; /** * Implicit init path: when the project has no grove.lock, run * `grove init --as skill` to fetch grammars + write grove.lock. Off by * default — provisioning (a network fetch) is opt-in, "when needed". */ runInit?: boolean; /** Timeout for the init subprocess (default 60s — grammar download). */ initTimeoutMs?: number; } /** * Detect grove and, optionally, provision it for a project. Never throws — a * missing binary or a failed init returns a readiness object the caller reads. */ export declare function ensureGroveReady(opts: EnsureGroveOptions): GroveReadiness; export interface AttachGroveOptions { /** Project root grove operates against (grove resolves paths from here). */ cwd: string; /** Explicit binary override. */ bin?: string; /** Override the tool name prefix (default "mcp__grove__"). */ namePrefix?: string; /** Run the implicit init path if the project isn't provisioned yet. */ autoInit?: boolean; /** Per-call request timeout for grove tools (default 15s). */ requestTimeoutMs?: number; /** * Force explore-mode (`grove serve --explore`) on/off. Undefined (default) * auto-detects via `shouldUseExplore`: explore-mode iff the project has * `.grove/explore.json` and FORGE_GROVE_NO_EXPLORE isn't set. */ explore?: boolean; } /** * Attach grove to a pi session: detect → (optionally) provision → spawn * `grove serve` → discover tools → synthesize pi ToolDefinitions. * * Returns null — a graceful no-op — when grove is unavailable or the handshake * fails. Callers register the returned tools on the host session and inject them * into subagent dispatch. */ export declare function attachGrove(opts: AttachGroveOptions): Promise;