/**
 * The ONE folding engine every listing frame renders through — the `<skills>` block, the skills drift
 * frame's add arm, the agent-type roster and its drift frame's add arm. A listing is an intact-class
 * turn attachment (`turn-attachments.ts` `ATTACHMENT_DELIVERY_CLASS`): the delivery lane never clips
 * it, so this engine is the frame's whole bound, byte-exact over the caller's `frame` (headers, fences,
 * markers, joiners included).
 *
 * Three honesty tiers over ONE set of items, each chosen with the LATER tiers' fixed overhead already
 * reserved so the final render never blows the budget it was sized against:
 *   A. everything fits → every item gets its full line;
 *   B. reserve the cap marker + EVERY item's name-only line first, then spend the remaining slack on
 *      full lines in PRIORITY order (`rank` ascending; absent ⇒ index), admitting each full line whose
 *      incremental cost still fits and skipping (not stopping at) the ones that do not — every item stays
 *      listed, the low-priority ones lose their detail;
 *   C. even all-name-only overflows → the longest name-only prefix that fits, closed by the caller's
 *      overflow count line.
 * Pure: the same items, spec and frame always render the same bytes.
 */
export interface ListingFoldSpec<T> {
    /** The whole frame's byte budget, honoured as given. */
    blockMaxBytes: number;
    /** One item's full line (tier A, and tier B's admitted lines). */
    full: (item: T) => string;
    /** One item's name-only line (tier B's degraded form, tier C's listed prefix). */
    nameOnly: (item: T) => string;
    /** The raw name reported for an item the budget degraded (host-facing data, not prompt text). */
    nameOf: (item: T) => string;
    /** Priority for keeping the full line: ascending, 0 = first. Absent ⇒ the item's index. */
    rank?: (item: T, index: number) => number;
    /** The marker line that opens a degraded (tier B/C) body. */
    capMarker: string;
    /** Tier C's closing line for `n` items that could not be listed at all. */
    overflowLine: (n: number) => string;
    /** Renders body lines into the lane's frame; its fixed cost is priced once by rendering it empty. */
    frame: (lines: readonly string[]) => string;
}
/** What one fold produced: the frame, and which items the budget degraded (display order). */
export interface ListingFoldRender {
    text: string;
    /** Items listed WITHOUT their full line. */
    nameOnly: readonly string[];
    /** Items the frame could not list at all (tier C's overflow tail). */
    dropped: readonly string[];
}
export declare function foldListingWithin<T>(items: ReadonlyArray<T>, spec: ListingFoldSpec<T>): ListingFoldRender | undefined;
/** The removal arm's FLOOR — the departure fact with none of the names; constant-size, which is what
 *  keeps the fact from being starved by a budget the names cannot fit. */
export declare function removalArmFloor(header: string, count: number): string;
/**
 * A listing frame's REMOVAL arm rendered INSIDE a byte budget: every departed name when they fit,
 * otherwise the longest prefix that does, closed by an honest count line — tier C over a list whose
 * lines have one form, so there is no name-only tier between them. Names are neutralized on the way
 * out: the announced map holds raw names from the commit half. Cost of the bound, stated: a name that
 * does not fit is never announced (the commit half advances past it), so the model can still hold an
 * entry that is gone — one failed call, against a frame that would otherwise never fit its budget.
 */
export declare function foldRemovalArmWithin(removed: readonly string[], header: string, maxBytes: number): string;
