/**
* Managed markdown blocks delimited by HTML comments — the mechanism behind the
* `ai-coding/` canon bootloaders. A bootloader is hand-written tool-specific
* content PLUS one generated block fenced by:
*
*
* …generated…
*
*
* Regenerating replaces only the fenced region, so a human's edits outside the
* block survive and re-running with the same body is byte-identical (idempotent).
* This is the markdown analogue of {@link upsertManagedBlock} in envfile.ts.
*/
export interface ManagedBlock {
/** Stable marker id, e.g. "ai-canonical:shared". */
marker: string;
/** Parenthetical note on the BEGIN line (e.g. the generated-from source path). */
note: string;
/** The block body (markdown), without the surrounding markers. */
body: string;
}
export declare function beginLine(marker: string, note: string): string;
export declare function endLine(marker: string): string;
/**
* Upsert a managed block into `existing` (`undefined` = the file does not exist
* yet). Replaces the fenced region if present, appends it if the file exists
* without the markers, or creates the file as `preamble` + block when `existing`
* is undefined. Everything outside the markers is preserved verbatim, and the
* file's existing EOL style (CRLF vs LF) is kept. Deterministic for a given body.
*/
export declare function mergeManagedBlock(existing: string | undefined, block: ManagedBlock, preamble: string): string;
/**
* Remove a managed block (and the blank lines hugging it) from `existing`, leaving
* everything OUTSIDE the fence verbatim and preserving the file's EOL style. The
* inverse of {@link mergeManagedBlock}: `aih prune` uses it to SUBTRACT aih's
* canonical block from a co-owned bootloader when the CLI is dropped, so the
* tool-specific preamble and any human edits survive. Returns `existing` unchanged
* when the marker is absent (no-op), and `""` when the block was the file's entire
* content. It never deletes the file — the caller writes the stripped remainder in
* place (the bootloader has no reliable "pure-aih remainder" signal, so we keep it).
*/
export declare function stripManagedBlock(existing: string, marker: string): string;
/**
* Extract a managed block's body (trimmed) from `text`, or `undefined` if the
* markers are absent. Used by the drift check: compare the on-disk body to the
* freshly generated one and fail if they differ.
*/
export declare function extractManagedBlock(text: string, marker: string): string | undefined;
/**
* True when `text` OPENS a managed block for `marker` — the BEGIN line alone, with no
* matching END required. It recognizes exactly the same BEGIN line
* {@link extractManagedBlock} does; it just asks the weaker question.
*
* {@link extractManagedBlock} needs a well-formed pair because it returns a body. A
* caller about to OVERWRITE a file needs the opposite bias: a bootloader whose END line
* was truncated or hand-deleted is still owned by `marker`, and a file someone already
* damaged is the one you least want silently replaced. Ownership checks guarding a
* destructive write use this and fail closed; anything that reads the body keeps using
* {@link extractManagedBlock}.
*/
export declare function hasManagedBlockStart(text: string, marker: string): boolean;
/** The sub-marker that fences a human "project extension" inside a managed block. */
export declare const PROJECT_EXTENSION_MARKER = "project-extension";
/**
* Carve the human "project extension" out of an on-disk managed-block body — the
* core of `aih adopt`'s non-destructive reconcile. A brownfield bootloader (e.g.
* eicp) folded project-specific guidance INTO the shared block; regenerating the
* block from the canonical source would silently delete it. This isolates exactly
* those human lines so the caller can re-home them to a project-owned file BEFORE
* the block is regenerated clean.
*
* Two strategies (the decided "diff-inferred now + sub-marker going forward"):
* 1. **Sub-marker (precise)** — if `onDisk` fences a region with
* `…`, that
* region's content IS the extension, verbatim and order-preserving.
* 2. **Diff-inferred (legacy)** — otherwise, the extension is the set of on-disk
* lines whose trimmed form is absent from `canonical`, kept in on-disk order
* with their original text. Whitespace-only and pure-structure lines that also
* appear in canonical are dropped, so a reordering alone yields no false extension.
*
* Returns the extension as a trimmed markdown string, or `""` when there is none
* (i.e. the on-disk body is canonical — already adopted).
*/
export declare function splitManagedBody(onDisk: string, canonical: string): string;