/** * Execute-stage step handlers (invariant #2). The pipeline routes each Step to the first * handler that `supports` it (DispatcherServlet-style) — built-in kinds and product-defined * `custom` actions resolve through the same `StepHandler` seam, so adding an action means * registering a handler, never editing a stage. Depends only on core ports/types. */ import type { CustomAction, Driver, StepHandler } from "./ports.js"; import type { Step, WaitUntil } from "./types.js"; /** * Locale prefixes eligible for `urlReached`'s locale-stripping FALLBACK. Deliberately small and * conservative: "any two-letter first segment is a locale" is a trait of particular apps, not a web * fact — promoting it to a heuristic swallowed real routes like /my (#86). Which prefixes are * locales is something only the consumer knows, so the set is injectable (`UrlMatchOptions`, * surfaced as `RunHarnessOptions.localePrefixes`) — same seam pattern as the benign lists. A region * variant matches its base language ("en-US" counts as "en"). */ export declare const DEFAULT_LOCALE_PREFIXES: readonly string[]; /** URL-matching knobs — consumer-injected, never guessed from the URL itself. */ export interface UrlMatchOptions { /** First-path-segment prefixes treated as locales in the stripping fallback. * Default: `DEFAULT_LOCALE_PREFIXES`. Pass `[]` to disable the fallback. */ localePrefixes?: readonly string[]; } /** Whether `finalUrl` reached `want`, matched at a path boundary (not raw substring) — a parent * path ("…/en") never counts as reaching "…/en/signin". `want` may be a full host+path or a bare * suffix. Two stages (#86): first a DIRECT match with no locale interpretation — so a real route * that merely looks like a locale ("/my", "/go") matches as itself; only when that fails, retry * with consumer-approved locale prefixes stripped — so a frozen destination still matches when the * environment serves another locale. */ export declare function urlReached(finalUrl: string, want: string, opts?: UrlMatchOptions): boolean; /** Handles cairn's built-in step vocabulary — every kind except product-defined `custom`. */ export declare class BuiltinStepHandler implements StepHandler { supports(step: Step): boolean; execute(step: Step, driver: Driver): Promise; } /** Handles product-defined `{ kind: "custom", name }` steps via a name→action registry. */ export declare class CustomStepHandler implements StepHandler { private readonly actions; constructor(actions?: Record); supports(step: Step): boolean; execute(step: Step, driver: Driver): Promise; } /** The engine's default Execute-stage chain: built-ins first, then product `custom` actions. */ export declare function defaultStepHandlers(actions?: Record): StepHandler[]; /** * Poll the Driver's own observation until every field of `until` holds, or throw on timeout. * Uses only `observe()`/`snapshot()`, so any Driver works and replay stays deterministic (no LLM, * invariant #4). This is the explicit-wait primitive the heuristic `settle()` can't express — * e.g. "wait until /me returns 200" before the next step, instead of racing the app's readiness. */ export declare function waitForCondition(driver: Driver, until: WaitUntil, timeoutMs?: number): Promise; /** * Poll `conditionMet` until it holds or the deadline passes; returns whether it held. The readiness * primitive `waitForCondition` and the per-step `expect` check both build on this — a step's * post-condition is *waited for*, not checked once, so an async effect (a submit's request landing, a * deferred re-render) is caught instead of raced. Returns immediately when the condition already holds. */ export interface PollOptions { pollMs?: number; /** Only count requests at/after this index of the run's request log for `requestStatus` — a * per-step watermark, so an earlier step's request can't satisfy this step's post-condition. */ sinceRequestIndex?: number; /** Consumer-injected URL-matching knobs (locale prefixes) for `until.url` (#86). */ urlMatch?: UrlMatchOptions; } export declare function pollCondition(driver: Driver, until: WaitUntil, timeoutMs: number, opts?: PollOptions): Promise; /** Whether every field of `until` holds now (Driver observation only, no LLM). Polled by `waitFor` * and checked once per step for `expect` verification (spec/core/surgical-heal.md). `requestStatus` * is event evidence over a cumulative log, so callers verifying a single step pass a watermark. */ export declare function conditionMet(driver: Driver, until: WaitUntil, sinceRequestIndex?: number, urlMatch?: UrlMatchOptions): Promise;