import { AgentProfile } from '@tangle-network/agent-interface';
import { a as ProfileArtifact, A as ArtifactKind, b as ArtifactStatus, c as ArtifactInput, E as EvalRunner, d as EvalResult, G as GenerateContext, C as CandidateGenerator, e as PromotionVerdict, P as PromotionGate } from './generator-YkAQrOoD.js';
export { f as ArtifactPayloads, H as HeldOutPromotionGateOptions, M as MarginalLift, g as MeasureMarginalLiftOptions, h as heldOutPromotionGate, m as measureMarginalLift, t as thresholdPromotionGate } from './generator-YkAQrOoD.js';
import { LlmClientOptions, AnalystFinding } from '@tangle-network/agent-eval';
import { M as McpServeSpec } from './mcp-serve-verifier-FL7-ZEb_.js';
import { L as LocalHarness } from './local-harness-sI0S_XNA.js';
import '@tangle-network/agent-eval/campaign';
import 'node:child_process';

/**
 * `applyArtifact` — merge one `ProfileArtifact` onto an `AgentProfile`.
 *
 * This is the deterministic bridge between the artifact catalog and the §1.5
 * profile law: each `ArtifactKind` lands on exactly one profile field. The merge
 * is shallow-immutable — the input profile is never mutated; a new profile with
 * the artifact applied is returned. This is the ONE place that knows how a
 * `kind` maps to a profile field, so both the registry's `compose` and
 * `measureMarginalLift`'s with/without ablation share a single source of truth.
 */

/**
 * Return a new profile with `artifact` merged onto `base`. Keyed kinds
 * (`tool`/`mcp`/`hook`/`subagent`) land under `artifact.key` (falling back to
 * `artifact.id`). `prompt` appends an instruction line; `skill` appends a
 * resource ref. Existing keys are overwritten by the artifact (the artifact is
 * the candidate being measured/promoted, so it wins on conflict).
 */
declare function applyArtifact(base: AgentProfile, artifact: ProfileArtifact): AgentProfile;
/** Apply many artifacts left-to-right; later artifacts win on key conflicts. */
declare function applyArtifacts(base: AgentProfile, artifacts: readonly ProfileArtifact[]): AgentProfile;

/**
 * `ArtifactRegistry` — a typed catalog of profile artifacts with stable ids.
 *
 * The registry is the lifecycle's source of truth for "what pieces could go into
 * this agent's profile". It holds `register` / `list` / `get` / `promote`, assigns
 * stable ids, and can `compose` a subset of artifacts onto a baseline profile via
 * the single `applyArtifact` bridge. It owns NO measurement, NO gate, NO LLM — it
 * is a pure in-memory store so callers can persist/snapshot it however they like.
 */

/** Filter for `list`. Omit a field to leave that dimension unconstrained. */
interface ArtifactQuery {
    kind?: ArtifactKind;
    status?: ArtifactStatus;
}
/**
 * The metadata key under which the registry stores an artifact's measured held-
 * back lift. This is the registry INVARIANT's anchor: an artifact is `active`
 * IFF this key holds a finite number — see `promoteWithLift` and `liftOf`. The
 * lifecycle never promotes by status flag alone; the lift score is the receipt.
 * `driftWatch` overwrites it with the latest re-measure so `liftOf` always
 * reflects the most recent evidence.
 */
declare const liftMetadataKey = "measuredLift";
/**
 * The metadata key under which the registry records WHY an artifact left the
 * active set — the human-readable reason a `demote` (→ decayed) or `retire`
 * (→ retired) carried. Kept so a demotion/retirement is auditable, not silent.
 */
declare const lifecycleReasonKey = "lifecycleReason";
/**
 * A typed, in-memory registry of `ProfileArtifact`s with stable ids.
 *
 * Ids are stable for the life of the registry: `register` assigns one (or honors
 * a caller-supplied id idempotently), and no later operation reassigns it.
 * Re-registering the same id REPLACES the artifact's mutable fields but preserves
 * the id, so a re-proposed candidate keeps its identity across generations.
 */
declare class ArtifactRegistry {
    private readonly artifacts;
    private counter;
    /**
     * Register an artifact, returning the stored record (with its assigned id).
     * When `input.id` is set it is honored (idempotent re-registration replaces
     * the record under the same id); otherwise a stable id is minted as
     * `<kind>-<n>`. `status` defaults to `'candidate'`.
     */
    register<K extends ArtifactKind>(input: ArtifactInput<K>): ProfileArtifact<K>;
    /** Get an artifact by id, or `undefined` if it was never registered. */
    get(id: string): ProfileArtifact | undefined;
    /**
     * List artifacts, optionally filtered by `kind` and/or `status`. Returns a new
     * array in registration order; callers may safely sort/mutate the result.
     */
    list(query?: ArtifactQuery): ProfileArtifact[];
    /**
     * Mark an artifact `active`. Fails loud on an unknown id — promoting a
     * non-existent artifact is a caller bug, not a no-op. Returns the updated
     * record. Idempotent: promoting an already-active artifact is a no-op return.
     *
     * NOTE: the artifact-lifecycle INVARIANT (no measured lift ⇒ not active) is
     * enforced by `promoteWithLift`, the path the closed loop uses. This bare
     * `promote` exists for callers that gate elsewhere and just flip the flag; it
     * does NOT record a lift score, so `liftOf` returns `undefined` and a
     * lift-ranked `composeProfile` will skip it. Prefer `promoteWithLift`.
     */
    promote(id: string): ProfileArtifact;
    /**
     * Promote an artifact AND record the measured held-back lift that earned it.
     * This is the closed loop's promotion path and the enforcement point of the
     * lifecycle invariant: an artifact becomes `active` only WITH a finite lift
     * number stamped under `liftMetadataKey`. A non-finite `lift` (NaN/Infinity)
     * fails loud — promoting on a broken measurement is exactly the silent-zero the
     * doctrine forbids. Re-promotes a `decayed` artifact whose lift recovered.
     * Returns the updated record.
     */
    promoteWithLift(id: string, lift: number): ProfileArtifact;
    /**
     * Demote an `active` artifact to `decayed`: it was promoted, but a later
     * re-measure (`driftWatch`) found its held-back lift fell below the keep-bar.
     * Records the latest re-measured `lift` (so `liftOf` reflects current evidence)
     * and the `reason` (so the demotion is auditable). The artifact stays in the
     * registry — `decayed`, not deleted — so it can be re-promoted if a future
     * re-measure recovers the lift. Fails loud on an unknown id. Demoting a
     * non-`active` artifact fails loud too: only the active set decays.
     */
    demote(id: string, reason: string, lift?: number): ProfileArtifact;
    /**
     * Retire an artifact to the terminal `retired` state: it is permanently out of
     * the active set (`dedupeArtifacts` retires the weaker half of a non-stacking
     * pair). Records the `reason` for the audit trail. Unlike `demote`, this is
     * terminal — a retired artifact is never re-promoted by the loop. Idempotent on
     * an already-retired artifact; fails loud on an unknown id.
     */
    retire(id: string, reason: string): ProfileArtifact;
    /**
     * The measured held-back lift recorded at promotion time (and overwritten by
     * the latest `driftWatch` re-measure), or `undefined` when the artifact was
     * never promoted WITH a lift (a fresh candidate, or one promoted via the bare
     * `promote`). The lifecycle invariant in one accessor: `liftOf(id) ===
     * undefined` ⇒ the artifact has no measured lift ⇒ it is not eligible for a
     * lift-ranked compose. Note this returns the recorded lift regardless of status
     * — `composeProfile` separately filters to `active`, so a `decayed` artifact's
     * stale lift is visible for audit but never folded into a profile.
     */
    liftOf(id: string): number | undefined;
    /**
     * Compose a set of registered artifacts onto a baseline profile. With no ids
     * given, composes every `active` artifact (the "ship the passing set"
     * default). With explicit ids, composes exactly those (in id order given),
     * failing loud on any unknown id. The applied order is the order passed (or
     * registration order for the active-default), and later artifacts win on key
     * conflicts — same semantics as `applyArtifacts`.
     */
    compose(base: AgentProfile, ids?: readonly string[]): AgentProfile;
    /** Number of registered artifacts (any status). */
    get size(): number;
    private mintId;
}
/** Construct an empty `ArtifactRegistry`. */
declare function createArtifactRegistry(): ArtifactRegistry;

/**
 * `composeProfile` — fold the top-k active artifacts back into a profile.
 *
 * This is the "give it all the passing options at once" step. After the loop has
 * generated, measured, and promoted artifacts, `composeProfile` selects the
 * highest-lift ACTIVE ones (those promoted WITH a measured held-back lift) and
 * applies them onto a baseline profile via the single `applyArtifact` bridge.
 *
 * It differs from the registry's raw `compose` in two ways the lifecycle needs:
 *   1. It ranks by MEASURED LIFT and takes the top `k`, rather than applying
 *      every promoted artifact in registration order. The best pieces go in
 *      first; a `k` budget keeps the composed profile from accreting marginal
 *      wins without bound.
 *   2. It enforces the lifecycle INVARIANT — only artifacts with a finite
 *      `liftOf` are eligible. An artifact flipped to `promoted` without a lift
 *      receipt is invisible here, by construction.
 */

interface ComposeProfileOptions {
    /** Cap on how many artifacts to fold in. Default: all eligible. */
    k?: number;
    /** Restrict to one surface (e.g. only fold in skills). Default: all kinds. */
    kind?: ArtifactKind;
}
/**
 * Return a new profile with the top-`k` active artifacts (highest measured lift
 * first) applied onto `base`.
 *
 * "Active" = promoted WITH a finite measured lift (`registry.liftOf` returns a
 * number) — the lifecycle invariant. Ties in lift fall back to registration
 * order (stable). With no `k`, every eligible artifact is folded in.
 *
 * @param registry the catalog the loop populated
 * @param base     the baseline profile to fold artifacts onto (the empty profile
 *                 on a cold start)
 * @param opts     `k` (top-k budget) and an optional `kind` filter
 *
 * @example Cold start — fold the single best distilled skill back in:
 *   const composed = composeProfile(registry, emptyProfile, { kind: 'skill', k: 1 })
 */
declare function composeProfile(registry: ArtifactRegistry, base: AgentProfile, opts?: ComposeProfileOptions): AgentProfile;

/**
 * `dedupeArtifacts` — retire the redundant half of a non-stacking pair.
 *
 * The lifecycle promotes each artifact on its OWN marginal lift, in isolation.
 * But two artifacts can each earn lift alone yet teach the agent the SAME thing —
 * a distilled "check state first" skill and a "verify before acting" prompt line,
 * say. Composed together they don't add up: the agent already learned the tactic
 * from the first, so the second buys little. Keeping both is wasted profile
 * surface (more context, more cost, more ways to conflict) for no extra score.
 *
 * `dedupeArtifacts` is the judge that catches this. For each pair of `active`
 * artifacts it measures whether their lifts STACK: it scores the baseline, each
 * artifact alone, and BOTH together, then compares the combined lift against the
 * sum of the individual lifts. When `combined < (a + b) − tolerance`, the pair
 * overlaps — they do not stack — and the weaker member (lower individual lift) is
 * `retire`d. Retirement is terminal: the kept member already delivers the shared
 * value, so the loop should not re-promote the redundant one.
 *
 * The "judge" is a MEASUREMENT, not an LLM verdict — it reuses the same ablation
 * machinery (`measureMarginalLift` + the caller's `EvalRunner`) the rest of the
 * lifecycle runs on, so the selector≠judge firewall holds and there is no new
 * execution model. It is surface-agnostic: any two artifacts (skill+prompt,
 * tool+tool, …) are compared identically, because stacking is measured on the
 * composed profile via the one `applyArtifacts` bridge.
 */

interface DedupeOptions {
    /** The registry whose `active` artifacts are pairwise stack-tested. Mutated in
     *  place: the weaker member of each non-stacking pair is retired. */
    registry: ArtifactRegistry;
    /** The baseline profile the stacking ablation runs on top of. The "without"
     *  arm is scored once and shared across every pair. */
    baseline: AgentProfile;
    /** Scores a profile on the held-back split. Called for the baseline, each
     *  artifact alone, and each candidate pair together. */
    evalRunner: EvalRunner;
    /**
     * The stacking tolerance. A pair is judged non-stacking (redundant) when the
     * combined lift falls SHORT of the sum of individual lifts by more than this:
     * `combined < a + b − tolerance`. A small positive tolerance absorbs eval
     * noise so only a real overlap retires an artifact. Default 0 — any shortfall
     * counts as non-stacking (use a positive value on noisy live evals).
     */
    tolerance?: number;
    /** Restrict dedupe to one surface (only compare skills against skills, …).
     *  Default: every `active` artifact is a candidate, across kinds. */
    kind?: ProfileArtifact['kind'];
    /** A pre-computed baseline result, to skip the shared "without" run. */
    baselineResult?: EvalResult;
    /** Cooperative cancellation, forwarded to every `evalRunner` call. */
    signal?: AbortSignal;
}
/** The stacking verdict for one pair of active artifacts. */
interface PairStackCheck {
    /** Ids of the two artifacts compared, in (a, b) order as examined. */
    pair: [string, string];
    /** Individual held-back lift of the first artifact alone (re-measured). */
    liftA: number;
    /** Individual held-back lift of the second artifact alone (re-measured). */
    liftB: number;
    /** Held-back lift of BOTH artifacts composed together. */
    combinedLift: number;
    /** `combinedLift − (liftA + liftB)`: ≥ −tolerance ⇒ they stack; below ⇒ they
     *  overlap (redundant). */
    stackGap: number;
    /** Whether the pair was judged non-stacking (redundant). */
    redundant: boolean;
    /** The id retired when redundant (the weaker member), else `undefined`. */
    retiredId?: string;
}
interface DedupeResult {
    /** One verdict per examined pair, in iteration order. Pairs where one member
     *  was already retired by an earlier pair this cycle are skipped. */
    checks: PairStackCheck[];
    /** Ids retired this cycle (the weaker member of each non-stacking pair). */
    retired: string[];
    /** The shared baseline eval (the "without" arm, measured once). */
    baselineResult: EvalResult;
}
/**
 * Pairwise stack-test the `active` artifacts and retire the redundant half of
 * each non-stacking pair.
 *
 * For every unordered pair of active artifacts (optionally within one `kind`),
 * the combined lift is compared against the sum of individual lifts. A pair is
 * non-stacking when `combinedLift < liftA + liftB − tolerance`; the lower-lift
 * member is retired (ties retire the second-examined). An artifact retired by one
 * pair is removed from the remaining comparisons that cycle, so a cluster of
 * three mutually-redundant artifacts collapses to its single strongest member.
 *
 * Cost is one shared baseline run, one re-measure per active artifact (cached
 * across the pairs it appears in), and one combined run per still-eligible pair.
 *
 * @example Retire skills that teach the same tactic as a stronger one:
 *   const out = await dedupeArtifacts({ registry, baseline, evalRunner, kind: 'skill' })
 *   if (out.retired.length) report(`retired ${out.retired.length} redundant skills`)
 */
declare function dedupeArtifacts(opts: DedupeOptions): Promise<DedupeResult>;

/**
 * `driftWatch` — the scheduled re-measure that DEMOTES decayed artifacts.
 *
 * Promotion is a one-time decision on the evidence available THEN; the world
 * moves on. A skill that earned its lift against last month's task mix, a tool
 * grant the underlying model has since internalized, a prompt line another active
 * artifact now subsumes — each can quietly stop pulling its weight. An artifact
 * that no longer earns its keep but stays `active` is dead weight in every
 * composed profile and a lie in the registry's lift receipt.
 *
 * `driftWatch` closes that gap. It re-runs the SAME `measureMarginalLift`
 * ablation the loop used to promote each `active` artifact — over the CURRENT
 * baseline and the CURRENT eval — and demotes any whose re-measured held-back
 * lift fell below the keep-bar. Demotion moves the artifact `active` → `decayed`
 * (reversible: a later re-measure that recovers the lift can re-promote it), so
 * it drops out of `composeProfile` immediately while staying in the registry as
 * an auditable record.
 *
 * This is NOT a new execution model — it is the existing ablation, run on a
 * schedule, against the active set. The schedule itself is the caller's cron;
 * this module is the one re-measure-and-demote step that cron invokes. It is
 * surface-agnostic (skills, tools, prompts, MCP all re-measure identically) — the
 * only per-surface logic lives, as everywhere in the lifecycle, behind the
 * artifact's own `applyArtifact` bridge, which `measureMarginalLift` already uses.
 */

interface DriftWatchOptions {
    /** The registry whose `active` artifacts are re-measured. Mutated in place:
     *  artifacts that fail the keep-bar are demoted to `decayed`. */
    registry: ArtifactRegistry;
    /** The baseline profile each artifact is re-measured ON TOP OF — the SAME
     *  ablation shape as promotion. Pass the CURRENT baseline (the world the
     *  artifact lives in now), which may differ from the one it was promoted on. */
    baseline: AgentProfile;
    /** Scores a profile on the held-back split. The shared baseline arm is run
     *  once and reused across every artifact's ablation (the "without" arm). */
    evalRunner: EvalRunner;
    /**
     * The absolute keep-bar: an artifact stays `active` only while its re-measured
     * held-back lift is STRICTLY ABOVE this floor. Default 0 — an artifact that no
     * longer adds anything (or now subtracts) decays. Mirrors `thresholdPromotionGate`'s
     * `minDelta` so the keep-bar and the promote-bar can be set consistently.
     */
    minLift?: number;
    /**
     * The relative keep-bar: an artifact also decays if its re-measured lift fell
     * to below this FRACTION of the lift recorded at promotion (`registry.liftOf`).
     * E.g. `0.5` demotes an artifact that lost more than half its original lift,
     * even if it still clears `minLift`. Default: unset (no relative check — only
     * the absolute `minLift` floor applies). Ignored for an artifact with no
     * recorded prior lift (a bare `promote`), which is judged on `minLift` alone.
     */
    maxRelativeDecay?: number;
    /** Restrict the watch to one surface (e.g. re-measure only skills). Default:
     *  every `active` artifact, regardless of kind. */
    kind?: ProfileArtifact['kind'];
    /** A pre-computed baseline result, to skip the shared "without" run when the
     *  caller already scored the current baseline this cycle. */
    baselineResult?: EvalResult;
    /** Cooperative cancellation, forwarded to every `evalRunner` call. */
    signal?: AbortSignal;
}
/** Per-artifact record of what the re-measure found and decided. */
interface DriftCheck {
    /** The re-measured artifact (status reflects the decision: still `active`, or
     *  now `decayed`). */
    artifact: ProfileArtifact;
    /** The lift recorded at promotion time (`registry.liftOf` before the check),
     *  or `undefined` if it was promoted without a lift receipt. */
    priorLift: number | undefined;
    /** The freshly re-measured held-back lift (with − without composite). */
    currentLift: number;
    /** Whether this re-measure demoted the artifact (`active` → `decayed`). */
    demoted: boolean;
    /** Human-readable reason the artifact was kept or demoted (the same string
     *  recorded under `lifecycleReasonKey` on a demotion). */
    reason: string;
}
interface DriftWatchResult {
    /** One check per `active` artifact examined, in registry order. */
    checks: DriftCheck[];
    /** Ids of the artifacts demoted to `decayed` this cycle. */
    demoted: string[];
    /** The shared baseline eval (the "without" arm, measured once). */
    baselineResult: EvalResult;
}
/**
 * Re-measure every `active` artifact and demote those whose held-back lift
 * decayed below the keep-bar.
 *
 * For each `active` artifact (optionally filtered to one `kind`), this re-runs
 * `measureMarginalLift` over the supplied `baseline`, then applies the keep-bar:
 *
 *   - ABSOLUTE: `currentLift > minLift` (default `> 0`), and
 *   - RELATIVE (when `maxRelativeDecay` is set AND a prior lift exists):
 *     `currentLift >= priorLift * (1 − maxRelativeDecay)`.
 *
 * An artifact failing EITHER bar is demoted to `decayed` (recording the
 * re-measured lift + reason) and drops out of `composeProfile`. An artifact that
 * passes both bars stays `active`, with its recorded lift refreshed to the latest
 * measurement so `liftOf` never reports stale evidence.
 *
 * The baseline "without" arm is scored ONCE and shared across all artifacts, so
 * the cost is `1 + (number of active artifacts)` eval runs.
 *
 * @example A nightly cron that demotes any active artifact that lost its lift:
 *   const out = await driftWatch({ registry, baseline, evalRunner, minLift: 0 })
 *   if (out.demoted.length) report(`demoted ${out.demoted.length} decayed artifacts`)
 */
declare function driftWatch(opts: DriftWatchOptions): Promise<DriftWatchResult>;

/**
 * `promptGenerator` — the `CandidateGenerator` for the PROMPT surface.
 *
 * It is to the prompt surface what `skillGenerator` is to skills: the thin
 * per-surface adapter that turns the agent's history into fresh, unmeasured
 * prompt-instruction candidates the surface-agnostic `runLifecycle` loop then
 * measures, gates, and promotes. Each candidate is a `prompt` artifact carrying
 * one `{ instruction }` line that `applyArtifact` appends to
 * `profile.prompt.instructions`.
 *
 * Two candidate sources, run together each generation:
 *
 *   1. REFINE (incumbent-grounded) — drive agent-eval's `gepaProposer`, the
 *      reflective prompt-tier proposer. It reflects on the incumbent prompt +
 *      the trace findings and proposes TARGETED rewrites. This is the exploit
 *      arm: it polishes the framing the agent already has.
 *
 *   2. SEED (basin escape) — author N genuinely DIVERSE fresh instruction
 *      lines from the TASK SPEC, NOT from the incumbent. A reflective proposer
 *      only ever perturbs the current surface, so on its own it can polish a
 *      local minimum forever — it never tries a fundamentally different framing.
 *      The seed arm authors several rewrites that each take a DIFFERENT stance
 *      (imperative vs. checklist vs. failure-mode-first, …) so the search can
 *      JUMP basins instead of only descending the one it starts in. This is the
 *      explore arm, and it is the piece `gepaProposer` structurally cannot do.
 *
 * Both seams are INJECTED (per the §1.5 law: the generator AUTHORS profile
 * pieces, it does not embed a specific LLM loop). `refine` wraps `gepaProposer`;
 * `authorDiverseSeeds` wraps an LLM author. A test injects pure stubs for both,
 * keeping the closed loop deterministically testable; production wires the real
 * router-backed engines (see `productionPromptGenerator`).
 */

/** A proposed prompt instruction line plus the WHY behind it. The `rationale`
 *  rides into the artifact metadata so a promotion decision is auditable. */
interface PromptDraft {
    /** The instruction line appended to `profile.prompt.instructions`. */
    instruction: string;
    /** Short human label for review surfaces. */
    label: string;
    /** Why this line was proposed — which failure / framing it targets. */
    rationale: string;
}
/**
 * REFINE — incumbent-grounded rewrites. Given the lifecycle context, return
 * targeted edits OF the current prompt framing. The production implementation
 * drives `gepaProposer`; a test injects a pure function. Returns zero or more
 * drafts.
 */
type RefinePrompt = (ctx: GenerateContext) => Promise<PromptDraft[]> | PromptDraft[];
/**
 * SEED — author N genuinely DIVERSE fresh instruction lines from the task spec,
 * NOT mutations of the incumbent. This is the local-minimum escape: each seed
 * MUST take a different framing so the population spans multiple basins. The
 * production implementation makes one LLM call at a non-trivial temperature; a
 * test injects a pure function. Returns up to `count` drafts.
 */
type AuthorDiverseSeeds = (ctx: GenerateContext, count: number) => Promise<PromptDraft[]> | PromptDraft[];
interface PromptGeneratorOptions {
    /** OPTIONAL — the exploit arm (incumbent-grounded rewrites via `gepaProposer`).
     *  Omit to run seeds-only. */
    refine?: RefinePrompt;
    /** OPTIONAL — the explore arm (diverse fresh seeds). Omit to run refine-only. */
    authorDiverseSeeds?: AuthorDiverseSeeds;
    /** How many diverse seeds the explore arm authors each generation. Default 3.
     *  Zero disables seeding even when `authorDiverseSeeds` is set. */
    diverseSeedCount?: number;
}
/**
 * Build a `CandidateGenerator` for the prompt surface. Each generation it pools
 * the refine arm (incumbent rewrites) and the seed arm (diverse fresh framings),
 * de-duplicates by instruction text, and emits each as a `prompt` artifact.
 *
 * At least one of `refine` / `authorDiverseSeeds` MUST be provided — a generator
 * with neither has no way to produce a candidate and is a wiring bug, so it
 * throws at construction rather than silently returning `[]` every round.
 *
 * @example Production wiring (refine = gepaProposer, seed = LLM author):
 *   promptGenerator({
 *     refine: gepaRefine(llm, model),
 *     authorDiverseSeeds: routerSeedAuthor(llm, model),
 *   })
 */
declare function promptGenerator(opts: PromptGeneratorOptions): CandidateGenerator<'prompt'>;
interface ProductionPromptGeneratorOptions {
    /** Router transport (baseUrl/apiKey) for both the refine and seed arms. */
    llm: LlmClientOptions;
    /** Model that performs reflection + seed authoring. Default `deepseek-v4-flash`. */
    model?: string;
    /** Population size handed to `gepaProposer`'s `propose`. Default 3. */
    refinePopulation?: number;
    /** Diverse-seed count. Default 3. */
    diverseSeedCount?: number;
    /** Seed-authoring temperature — high on purpose so the seeds spread across
     *  framings rather than collapsing onto one. Default 1.0. */
    seedTemperature?: number;
}
/**
 * Production `promptGenerator`: refine via `gepaProposer`, seed via a
 * router-backed diverse author. The one call a consumer makes to grow prompt
 * artifacts with the real engines.
 */
declare function productionPromptGenerator(opts: ProductionPromptGeneratorOptions): CandidateGenerator<'prompt'>;
/**
 * Wrap `gepaProposer` as a `RefinePrompt`. The proposer reflects on the
 * incumbent prompt (`ctx.baseline.prompt.systemPrompt`) and the trace findings
 * to propose `population` targeted rewrites. We feed it the generation-0
 * `ProposeContext` (no scored history yet inside one lifecycle round), so it
 * reflects on the current surface against its mutation primitives — exactly the
 * "polish the framing you already have" arm.
 */
declare function gepaRefine(llm: LlmClientOptions, model: string, population: number): RefinePrompt;
/**
 * A router-backed `AuthorDiverseSeeds`: one structured LLM call that authors
 * `count` instruction lines, each REQUIRED to take a distinct framing. The
 * prompt is grounded in the task spec (the incumbent system prompt as the spec
 * of WHAT the agent must do) plus the trace findings (what it gets wrong) — but
 * the model is told to author FRESH lines, not edits, so the output spans
 * basins the incumbent's neighborhood never reaches.
 */
declare function routerSeedAuthor(llm: LlmClientOptions, model: string, temperature: number): AuthorDiverseSeeds;

/**
 * `runLifecycle` — the ONE closed-loop orchestrator: generate → measure →
 * promote → store.
 *
 * It is surface-agnostic: it knows nothing about skills vs tools vs prompts. All
 * per-surface logic lives behind the `CandidateGenerator` seam. The loop:
 *
 *   1. GENERATE   — ask each generator for candidate artifacts from the agent's
 *                   history (traces/findings). Register them as `candidate`s.
 *   2. MEASURE    — for each candidate, run `measureMarginalLift` on the held-
 *                   back split (the with/without ablation, baseline shared across
 *                   candidates so the "without" arm runs once).
 *   3. PROMOTE    — run the `PromotionGate` (default: the held-back exam). On a
 *                   pass, `promoteWithLift` records the measured lift — the
 *                   registry invariant: no measured lift ⇒ never active.
 *   4. STORE      — every candidate (promoted or not) lands in the registry with
 *                   provenance (domain, generation, generator kind, gate verdict)
 *                   + its lift in metadata, so the decision is auditable.
 *
 * Compose is intentionally NOT part of this loop — folding the promoted set back
 * into a profile is a separate, explicit `composeProfile` call the caller makes
 * when it wants a deployable profile. Keeping them separate means a caller can
 * run the loop to grow the catalog without committing a profile change.
 */

interface RunLifecycleOptions {
    /** The baseline profile candidates are proposed and measured on top of. On a
     *  cold start this is the empty (or near-empty) profile. */
    baseline: AgentProfile;
    /** The agent/domain id — namespaces provenance + scopes generators. */
    domain: string;
    /** The per-surface candidate generators. One per surface the loop grows; the
     *  loop runs them in order and pools their candidates. */
    generators: ReadonlyArray<CandidateGenerator>;
    /** Scores a profile on the HELD-BACK split. Run by `measureMarginalLift` —
     *  once for the shared baseline, once per candidate. */
    evalRunner: EvalRunner;
    /** The promotion gate (the held-back exam). Default-free on purpose: the
     *  caller chooses the policy (`thresholdPromotionGate` / `heldOutPromotionGate`). */
    gate: PromotionGate;
    /** Trace-analyst findings the generators distill/propose from. */
    findings?: ReadonlyArray<AnalystFinding>;
    /** Raw captured traces for generators (e.g. a skill `distill`). Opaque. */
    traces?: unknown;
    /** Generation counter for provenance. Default 0. */
    generation?: number;
    /** An existing registry to grow across generations. Default: a fresh one. */
    registry?: ArtifactRegistry;
    /** Cooperative cancellation. */
    signal?: AbortSignal;
}
/** The per-candidate record of what the loop decided and why. */
interface CandidateOutcome {
    /** The stored artifact (status reflects the gate verdict). */
    artifact: ProfileArtifact;
    /** The surface this candidate targeted. */
    kind: ArtifactKind;
    /** Measured held-back lift (with − without composite). */
    scoreDelta: number;
    /** Measured extra USD cost the artifact adds. */
    costDelta: number;
    /** The gate's verdict. */
    verdict: PromotionVerdict;
    /** Whether the candidate was promoted into the registry as active. */
    promoted: boolean;
}
interface RunLifecycleResult {
    /** The registry, grown with this generation's candidates + promotions. */
    registry: ArtifactRegistry;
    /** One outcome per candidate the generators produced, in generation order. */
    outcomes: CandidateOutcome[];
    /** Ids of the artifacts promoted this generation. */
    promoted: string[];
    /** The shared baseline eval (the "without" arm, measured once). */
    baselineResult: EvalResult;
}
/**
 * Run ONE generation of the artifact lifecycle.
 *
 * @example Cold start on a fixture domain (the closed loop in one call):
 *   const out = await runLifecycle({
 *     baseline: emptyProfile,
 *     domain: 'support-bot',
 *     generators: [skillGenerator({ distill, refine })],
 *     evalRunner: scoreOnHeldBackSplit,
 *     gate: thresholdPromotionGate(),
 *     traces: seededTraces,
 *   })
 *   const composed = composeProfile(out.registry, emptyProfile, { kind: 'skill' })
 */
declare function runLifecycle(opts: RunLifecycleOptions): Promise<RunLifecycleResult>;

/**
 * `skillGenerator` — the reference `CandidateGenerator` for the SKILL surface,
 * and the literal answer to "an empty profile has no skills, so what creates
 * one?".
 *
 * It is a two-step pipeline:
 *
 *   1. DISTILL — read the agent's traces/findings and WRITE a new skill document
 *      (a reusable how-to note: "check state before acting", "verify after every
 *      edit"). This is the CREATE step. It is the piece `skillOpt` cannot do —
 *      an optimizer refines an existing skill, it cannot conjure one from
 *      nothing. The production `distill` is `reflectiveGenerator`-style: an LLM
 *      reflection over the trace produces the first draft.
 *
 *   2. REFINE — take the distilled draft and improve its wording/structure. The
 *      production `refine` drives agent-eval's `skillOptProposer` (the uniform
 *      skill-surface proposer factory from `@tangle-network/agent-eval/campaign`,
 *      the same source as `gepaProposer` for the prompt surface). Refinement is
 *      optional: with no `refine`, the distilled draft IS the candidate.
 *
 * Both steps are INJECTED seams, not hardcoded engines — per the §1.5 law, the
 * generator AUTHORS a profile piece; it does not embed a specific LLM loop. That
 * keeps the closed loop deterministically testable (inject pure stubs) while
 * production wires the real distill + skillOpt. The generator emits a `skill`
 * artifact (an inline `SKILL.md` resource ref) the orchestrator measures + gates.
 */

/** A distilled skill draft: a name + the `SKILL.md` body. */
interface SkillDraft {
    /** Skill name — becomes the inline resource ref name + the artifact name. */
    name: string;
    /** The `SKILL.md` document body (markdown). */
    content: string;
    /** Optional one-line description for review surfaces. */
    description?: string;
}
/**
 * DISTILL — create new skill drafts from the agent's history. Returns zero or
 * more drafts (zero is valid: nothing worth distilling this round). The
 * production implementation reflects over `ctx.traces` / `ctx.findings` with an
 * LLM; a test injects a pure function.
 */
type DistillSkills = (ctx: GenerateContext) => Promise<SkillDraft[]> | SkillDraft[];
/**
 * REFINE — improve ONE distilled draft (wording, structure, examples). The
 * production implementation drives `skillOptProposer`. Returns the refined draft;
 * when omitted from `skillGenerator`, the distilled draft is used as-is.
 */
type RefineSkill = (draft: SkillDraft) => Promise<SkillDraft> | SkillDraft;
interface SkillGeneratorOptions {
    /** REQUIRED — the create step. Without it there is no skill to optimize. */
    distill: DistillSkills;
    /** OPTIONAL — the optimize step. Omit to ship distilled drafts unrefined. */
    refine?: RefineSkill;
}
/**
 * Build a `CandidateGenerator` for the skill surface that distills new skills
 * from history, then (optionally) refines them, and emits each as a `skill`
 * artifact carrying an inline `SKILL.md` resource ref.
 *
 * @example Production wiring (distill = LLM reflection, refine = skillOptProposer):
 *   skillGenerator({
 *     distill: reflectiveDistill,   // creates the draft from traces
 *     refine: skillOptRefine,       // optimizes the draft via skillOptProposer
 *   })
 */
declare function skillGenerator(opts: SkillGeneratorOptions): CandidateGenerator<'skill'>;

/**
 * `buildableGenerator` — the `CandidateGenerator` for the BUILDABLE surfaces
 * (`tool` and `mcp`), and the answer to "a profile can't *write* a new tool from
 * a prompt rewrite — who builds it?".
 *
 * Unlike the prompt and skill surfaces, where a candidate is a piece of TEXT an
 * LLM authors in one call, a tool or an MCP server is CODE that must compile,
 * pass its tests, and — for an MCP server — actually boot and serve. You cannot
 * one-shot that reliably. So this generator is a SUPERVISOR DISPATCH, not a
 * single author:
 *
 *   1. FAN OUT  — spawn N parallel candidate implementations, each built in its
 *                 OWN git worktree by a real coding harness (research → implement
 *                 → test → prove it compiles / actually serves). The per-candidate
 *                 build is the `buildCandidate` seam; production wires it to the
 *                 shipped `improvementDriver` + `agenticGenerator` + a verifier
 *                 (`commandVerifier` for a tool, `mcpServeVerifier` for an MCP).
 *   2. FILTER   — keep only the VERIFIED builds. An unverified worktree is never a
 *                 candidate (the verifier is the gate — same valid-only discipline
 *                 as `worktreeFanout`'s `selectValidWinner`). A build that never
 *                 compiles/serves is discarded, never ranked.
 *   3. RANK     — score each verified survivor by `measureMarginalLift` against
 *                 `ctx.baseline` (the with/without held-back ablation — the SAME
 *                 selector the rest of the lifecycle uses; never a judge).
 *   4. EMIT     — return the single best survivor as ONE `tool` / `mcp` artifact,
 *                 carrying the measured lift + the winning worktree ref as
 *                 auditable provenance in metadata.
 *
 * Steps 2–4 (filter, lift-rank, emit) are surface-agnostic and live here; only
 * `buildCandidate` (the per-candidate worktree build) varies, and it is INJECTED
 * — production wires the real harness fan-out, a test injects pure stubs so the
 * dispatch is deterministically exercisable without spawning processes or models.
 *
 * NB the lifecycle orchestrator (`runLifecycle`) STILL measures + gates whatever
 * this returns. The rank here is an INTERNAL selection — "which of the N parallel
 * builds is the best candidate to put forward" — not the promotion gate. A
 * generator that puts forward a measured-best candidate and an orchestrator that
 * re-measures it on the held-back exam are not redundant: the first picks among
 * siblings, the second decides whether the winner clears the bar to ship.
 */

/** The buildable surfaces — the kinds whose candidate IS code that must compile
 *  / serve, so building one is a fan-out-and-verify dispatch, not a one-shot. */
type BuildableKind = 'tool' | 'mcp';
/**
 * The result of building ONE candidate in its own worktree. A build either
 * verified (compiled + tests passed, or — for an MCP — booted and served) or it
 * did not; an unverified build is dropped before ranking, so `verified:false`
 * carries the reason for the audit trail but never becomes a candidate.
 */
interface BuiltCandidate {
    /** A short label for this candidate (worktree branch / trace node). */
    label: string;
    /** Did the build compile + pass its verifier? Only verified builds rank. */
    verified: boolean;
    /** The worktree path / git ref holding the built change (provenance). */
    worktreeRef: string;
    /**
     * For an `mcp` candidate: how to START the built server (stdio transport).
     * Becomes the `AgentProfileMcpServer` the artifact carries. REQUIRED for an
     * `mcp` build; ignored for a `tool` build.
     */
    serve?: {
        command: string;
        args?: string[];
        cwd?: string;
        env?: Record<string, string>;
    };
    /**
     * For a `tool` candidate: the tool name the grant lands under (the profile
     * `tools` key). REQUIRED for a `tool` build; ignored for an `mcp` build.
     */
    toolName?: string;
    /** Why the build failed verification, when `verified` is false (audit only). */
    failureReason?: string;
    /** Free-form provenance to ride into the artifact metadata (build summary, …). */
    metadata?: Record<string, unknown>;
}
/**
 * BUILD ONE candidate. Given the lifecycle context and the index in the fan-out,
 * produce a fresh worktree implementation and report whether it verified. The
 * production implementation drives a real coding harness in a fresh worktree
 * (`worktreeBuildCandidate`); a test injects a pure function.
 *
 * MUST NOT measure lift, gate, or register — that is the dispatch's / the
 * orchestrator's job. It only builds + verifies ONE sibling.
 */
type BuildCandidate = (ctx: GenerateContext, index: number, signal: AbortSignal) => Promise<BuiltCandidate>;
interface BuildableGeneratorOptions {
    /** The buildable surface this generator targets (`tool` or `mcp`). */
    kind: BuildableKind;
    /** The per-candidate build seam (the fan-out leaf). REQUIRED. */
    buildCandidate: BuildCandidate;
    /** How many candidate implementations to build in parallel each generation.
     *  Default 3. Must be >= 1. The conserved-budget / live-worker caps that bound
     *  the real fan-out live in the production `buildCandidate` wiring. */
    fanout?: number;
    /** Scores a profile on the held-back split — used to RANK the verified
     *  siblings by `measureMarginalLift`. REQUIRED: without it there is no way to
     *  pick the best of N, and "best" is the whole point of a fan-out. */
    evalRunner: EvalRunner;
}
/**
 * Build a `CandidateGenerator` for a buildable surface (`tool` / `mcp`). Each
 * generation it fans out `fanout` parallel worktree builds, keeps the verified
 * ones, ranks them by held-back marginal lift, and emits the single best as one
 * artifact. Returns `[]` when no build verifies — the surface had nothing
 * shippable to contribute this round (a valid, common outcome for hard builds).
 *
 * @example Production wiring (build = real harness fan-out, rank = held-back eval):
 *   buildableGenerator({
 *     kind: 'mcp',
 *     buildCandidate: worktreeBuildCandidate({ repoRoot, harness: 'claude' }),
 *     evalRunner: scoreOnHeldBackSplit,
 *     fanout: 4,
 *   })
 */
declare function buildableGenerator(opts: BuildableGeneratorOptions): CandidateGenerator<BuildableKind>;

/**
 * `worktreeBuildCandidate` — the PRODUCTION `BuildCandidate`: one fan-out leaf
 * that builds a real tool / MCP server in a fresh git worktree with a real
 * coding harness, and verifies it by the surface's intrinsic check.
 *
 * It is the wiring that makes `buildableGenerator`'s dispatch real, composed
 * entirely from shipped engines — NO new execution model:
 *
 *   - `gitWorktreeAdapter` (agent-eval/campaign) cuts the isolated worktree.
 *   - `improvementDriver` (this repo) owns the worktree lifecycle (create →
 *     generate → finalize/discard) and drives ONE candidate.
 *   - `agenticGenerator` (this repo) runs the coding harness IN the worktree
 *     with the surface's build-prompt (`toolBuildPrompt` / `mcpBuildPrompt`):
 *     research → implement → test, multi-shot resume-on-failure.
 *   - the surface's verifier proves the result: `commandVerifier('pnpm', ['test'])`
 *     for a tool (compiles + tests pass), `mcpServeVerifier(serve)` for an MCP
 *     (boots over stdio + answers `tools/list`). A build that never verifies is
 *     dropped by `agenticGenerator` (no `CodeSurface` finalized) → `verified:false`.
 *
 * Kept out of `tool-generator.ts` so the dispatch core stays process-free and
 * unit-testable; this file is the one call a consumer makes to wire the real
 * harness fan-out.
 */

interface WorktreeBuildOptions {
    /** The buildable surface to build (`tool` / `mcp`). */
    kind: BuildableKind;
    /** Absolute path to the git checkout each candidate worktree is cut from. */
    repoRoot: string;
    /** Which local coding harness drives the build. Default `claude`. */
    harness?: LocalHarness;
    /** Base ref each worktree forks from. Default `main`. */
    baseRef?: string;
    /** Max harness shots per candidate (the depth dial — resume-on-failure). Default 3. */
    maxShots?: number;
    /** Per-shot wall-clock timeout (ms). Forwarded to `agenticGenerator`. */
    timeoutMs?: number;
    /**
     * For a `tool` build: the verify command (run in the worktree, exit 0 = pass)
     * and the tool name the resulting grant lands under. Default command
     * `pnpm test`.
     */
    tool?: {
        verifyCommand?: string;
        verifyArgs?: string[];
        toolName: string;
    };
    /**
     * For an `mcp` build: how to BOOT the built server (the boot-and-probe spec)
     * — used both to verify it serves AND as the artifact's start command. The
     * `cwd` defaults to the candidate worktree.
     */
    mcp?: McpServeSpec;
}
/**
 * Build the production per-candidate seam for `buildableGenerator`. Each call to
 * the returned `BuildCandidate` cuts a fresh worktree, drives the harness to
 * implement + verify the surface, and reports the verified worktree (or
 * `verified:false` with the reason) back to the dispatch for ranking.
 */
declare function worktreeBuildCandidate(opts: WorktreeBuildOptions): BuildCandidate;

export { ArtifactInput, ArtifactKind, type ArtifactQuery, ArtifactRegistry, ArtifactStatus, type AuthorDiverseSeeds, type BuildCandidate, type BuildableGeneratorOptions, type BuildableKind, type BuiltCandidate, CandidateGenerator, type CandidateOutcome, type ComposeProfileOptions, type DedupeOptions, type DedupeResult, type DistillSkills, type DriftCheck, type DriftWatchOptions, type DriftWatchResult, EvalResult, EvalRunner, GenerateContext, type PairStackCheck, type ProductionPromptGeneratorOptions, ProfileArtifact, PromotionGate, PromotionVerdict, type PromptDraft, type PromptGeneratorOptions, type RefinePrompt, type RefineSkill, type RunLifecycleOptions, type RunLifecycleResult, type SkillDraft, type SkillGeneratorOptions, type WorktreeBuildOptions, applyArtifact, applyArtifacts, buildableGenerator, composeProfile, createArtifactRegistry, dedupeArtifacts, driftWatch, gepaRefine, lifecycleReasonKey, liftMetadataKey, productionPromptGenerator, promptGenerator, routerSeedAuthor, runLifecycle, skillGenerator, worktreeBuildCandidate };
