/** * locate.ts — the one place that answers "where do flows live, and what are * they called". * * It sits in the engine, next to `flowFileCandidates` / `loadAllFlowEntries`, * because both sides of the question have to agree: the CLI's *listing* * surfaces (`flow list`, completions) and the *resolution* surfaces that live * in this tree (`resume`, sub-flow `run.flow` targets, `serve`). They used to * hold two hand-maintained candidate lists, and only one of them ever grew. */ /** * Roots that only the *resolution* surfaces prepend: the project's own * `ai-assets/` tree, so a workspace can shadow a built-in flow. * * Returns at most one root — the nearest `ai-assets/` at or above `projectDir`. * Listing deliberately does **not** include it; see `cli/src/flow-discovery.ts`. * * @docLink packages/flow-engine/concepts#flow-loading */ export declare function projectAiAssetsRoots(projectDir: string): string[]; /** * Every root a flow lookup walks, in priority order: the project's own * `ai-assets/` tree first, then every shared content root. * * `aiResourceRoots(projectDir)` is a **subset** of this — that is the documented * relationship between "a flow `flow list` shows" and "a flow `resume` / * sub-flow targets / `serve` can find", and the reason both go through here. * * The authored `ai-assets/` tree leading is deliberate and is what `skaile run` * has always done: a workspace must be able to shadow a built-in flow. It is the * opposite of {@link aiResourceRoots}'s own ordering, where the deployed * `.skaile/` copy leads because `deployAll` applies `patches:` to it — so for a * flow id present in *both*, resolution takes the authored source. Resume must * execute the bytes `run` executed; that agreement is the point of this module. * * @param projectDir - Project whose `.skaile/` and `ai-assets/` roots to * include (default: `process.cwd()`). * @docLink packages/flow-engine/concepts#flow-loading */ export declare function flowLookupRoots(projectDir?: string): string[]; /** * Why a conventional candidate that exists on disk was still not accepted — * the difference between "no such flow" and "that file is right there but * declares something else", which a bare "not found" used to hide. * * @docLink packages/flow-engine/concepts#flow-loading */ export interface FlowLookupMiss { path: string; reason: "unparseable" | "id-mismatch"; declaredId?: string; error?: string; } /** * Locate the file of the flow whose **declared id** is `flowId`, across `roots`. * * Per root: the conventional paths first (both content-root layouts via * `assetSearchDirs`, both flow layouts and all four extensions via * `flowFileCandidates`), then the full enumeration `loadAllFlowEntries` — the * same one `discoverFlows` lists from, which is what keeps listing and * resolution agreeing by construction. The fallback stays *inside* the loop so * an earlier root always wins over a later one. * * A candidate that resolves outside the search dir it was built from is * **skipped, not thrown**: this is on the `skaile run ""` * path, where a miss is normal and must fall through to single-shot mode. * * @param opts.onMiss - Called for a conventional candidate that exists but was * rejected. Discovery warnings are suppressed regardless. * @docLink packages/flow-engine/concepts#flow-loading */ export declare function findFlowFileInRoots(flowId: string, roots: string[], opts?: { onMiss?: (miss: FlowLookupMiss) => void; }): string | undefined; //# sourceMappingURL=locate.d.ts.map