/** Where a candidate engine came from. Printed verbatim in failures. */ export type EngineCandidateSource = "UE_MCP_TEST_ENGINE_ROOT" | "UE_BUILD_TOOL_PATH" | "editor.buildToolPath" | "UE_EDITOR_PATH" | "editor.path" | "EngineAssociation path" | "project-relative engine tree" | "EngineAssociation" | "last editor launch" | "default engine install"; /** * A place an engine might be, before anything has been probed. * * `buildTool` is set only when the source names a build script directly, which * is the one case where a usable tool can exist without a recognisable engine * root above it. */ export interface EngineCandidate { source: EngineCandidateSource; engineRoot: string | null; buildTool: string | null; /** True when a person configured this explicitly, so a miss is their typo. */ explicit: boolean; } export interface SelectedEngine { source: EngineCandidateSource; engineRoot: string | null; buildTool: string | null; editorExecutable: string | null; } export interface EngineLookup { /** Path to the .uproject. Everything project-relative needs it. */ projectPath?: string | null; /** EngineAssociation, when the caller already parsed the .uproject. */ engineAssociation?: string | null; /** `editor.buildToolPath` from the project's ue-mcp.yml (#817). */ configBuildToolPath?: string | null; /** `editor.path` from the project's ue-mcp.yml (#817). */ configEditorPath?: string | null; env?: NodeJS.ProcessEnv; platform?: NodeJS.Platform; hooks?: Partial; } /** * The I/O the resolver does, injectable so the ordering can be tested against * synthetic layouts without a registry, a launcher manifest or an editor log. */ export interface EngineLookupHooks { exists(candidatePath: string): boolean; /** GUID -> registered build, version string -> launcher install. */ associationInstall(association: string): string | null; /** The engine a project's own log says it was last opened with. */ lastEngineRoot(projectPath: string): string | null; } /** The Build.bat / Build.sh an engine root would hold on this platform. */ export declare function engineBuildTool(engineRoot: string, platform?: NodeJS.Platform): string; /** The editor binaries an engine root would hold, best first. */ export declare function engineEditorBinaries(engineRoot: string, platform?: NodeJS.Platform): string[]; /** * Walk up from a path inside an engine tree to the root that contains `Engine`. * Covers build scripts and editor binaries on every platform. */ export declare function engineRootFromEnginePath(enginePath: string, platform?: NodeJS.Platform): string | null; export declare function protectedEngineRoots(env?: NodeJS.ProcessEnv): string[]; /** Thrown when nothing usable was found. `tried` is every path probed. */ export declare class EngineResolutionError extends Error { readonly tried: string[]; constructor(message: string, tried: string[]); } /** * Every place this project's engine might be, in order, before probing. * * Exported so a caller can report the search without triggering it, and so the * ordering can be asserted directly in tests. */ export declare function engineCandidates(lookup?: EngineLookup, probed?: string[]): EngineCandidate[]; /** * What a selection needs: a usable build script, a launchable editor, or a * readable engine source tree. They are asked for separately because an engine * can satisfy one and not another - a binary-only distribution launches but * cannot answer engine-source questions. */ export type EngineNeed = "buildTool" | "editor" | "engineRoot"; /** * Pick the engine for one project, or throw an error naming every path probed. * * An explicitly configured location that does not exist is reported on its own * rather than quietly falling through to a default install nobody asked for. */ export declare function selectEngine(lookup?: EngineLookup, need?: EngineNeed): SelectedEngine; /** `selectEngine` without the throw, for callers that have their own fallback. */ export declare function trySelectEngine(lookup?: EngineLookup, need?: EngineNeed): SelectedEngine | null; /** * The engine root for reading engine source, or null. * * Callers that used `findEngineInstall(association)` want this: it still * honours the association, it just no longer stops there. */ export declare function resolveEngineRoot(lookup?: EngineLookup): string | null;