/** Thrown by `shiftHeadings` when it finds a heading it cannot safely renumber: a SETEXT heading * (`Title\n===`/`Title\n---` — no `#` run to adjust; converting it to ATX risks corrupting text * that merely looked like an underline, e.g. a thematic break glued to a preceding paragraph) or * an ATX heading whose shifted level would leave the valid `#`-run range [1,6]. Callers treat * this as "this item cannot be safely spliced" rather than attempting a lossy rewrite. */ export declare class HeadingShiftError extends Error { } /** Renumber every REAL ATX heading (mdast/CommonMark heading detection — a `#` inside a fenced or * indented code block is not a heading) inside `text` by `delta` levels, leaving everything else * byte-identical. `delta === 0` is still validated (still throws on a setext heading) so a * caller that relies on "shiftHeadings succeeded" as a writability signal gets it even when the * shift is a no-op (an L=1 document item, whose read/write shift delta is 0). */ export declare function shiftHeadings(text: string, delta: number): string; export interface DecomposedSection { /** The section's first line, verbatim (the heading, e.g. `## DOC-1 — Alpha item`). */ headingLineRaw: string; /** Heading line through the end of the consumed header block (if any), including its * terminating blank-line run up to the first content line. Always starts with * `headingLineRaw` verbatim. */ prefixRaw: string; /** The item's real content — what `shiftHeadings(±(level-1))` operates on. */ middle: string; /** The trailing run of blank lines at the very end of the section (before the next heading, or * end of file). */ suffixBlanks: string; /** The header block's fields, or `null` when no header block was present (never started, or * aborted — see the module comment). Only `status`/`assignee` are recognized here; a `title:` * line is NOT part of this grammar (the heading owns the title) and aborts the block exactly * like any other non-matching line. */ header: { status?: string; assignee?: string; } | null; /** 0-based line index (within `raw.split('\n')`) of each header field's OWN line — lets a * caller (spliceStatusLine, below) rewrite exactly one field's value without re-deriving the * header-block scan. Empty when `header` is `null`; a key is present iff `header` has it. */ headerLineIndex: { status?: number; assignee?: number; }; /** ZTB-23 dev/04: set when a header block was genuinely IN PROGRESS (at least one `status:`/ * `assignee:` line already matched) but then discarded because a non-blank, non-header-shaped * line followed instead of the blank line the block needs to terminate — e.g. `assignee: me` * immediately followed by prose, no blank line in between. `header` is `null` in this case, * same as "there was never a header block at all"; this field is what lets a caller ( * DocumentSource) tell the two apart and emit a diagnostic instead of silently losing the * metadata (mirrors `fileToRecord`'s `loose_header_ignored`, src/check.ts). The offending * line, verbatim. Undefined whenever there was no partial match to discard (no header * attempted at all, or a clean header + blank line). */ discardedHeaderLine?: string; } /** Decompose one parsed issue's section text (heading + subtree — `DocumentParsedIssue.raw`/ * `.body` in the common non-excised case) into prefix/middle/suffix. Pure string manipulation — * no markdown parsing — since the header-block grammar is a fixed two-field line scan (mirrors * `parseHeaderBlock` in documentParser.ts / `fileToRecord` in check.ts), not a markdown construct. */ export declare function decomposeSection(raw: string): DecomposedSection; /** The write-side inverse of `decomposeSection` + `shiftHeadings`: given a FRESHLY re-read * section `raw` (so `prefixRaw`/`suffixBlanks` are re-derived from disk, never from a possibly * stale construction-time snapshot), a `newTitle` (possibly unchanged) and a `newBody` (already * in the CanonicalIssue's presented, unshifted shape), produce the new section text. * * Title handling: if `newTitle === storedTitle`, the heading line is reused verbatim (byte-exact * — no re-derivation risk). Otherwise `storedTitle` must be a non-empty, exact SUFFIX of the * heading line; that suffix is replaced. A title that isn't a clean suffix (pathological * spacing) throws — callers fail the whole write closed rather than guess. */ export declare function spliceSectionText(freshRaw: string, level: number, storedTitle: string, newTitle: string, newBody: string): string; /** Thrown by `spliceStatusLine` when the section has no `status:` header line to rewrite. No * position is invented for a missing header — `decomposeSection` records no insertion point for * one (see `DecomposedSection.headerLineIndex`, only ever populated for a field that's actually * present), so a document item with no `status:` line fails this splice closed; the caller * (documentSource.ts's `write()`) turns this into a fail-closed error naming the file/issue. */ export declare class NoStatusHeaderError extends Error { } /** ZTB-16 dev/03: the write-side analogue of `spliceSectionText`, scoped to ONE header field — * given a FRESHLY re-read section `raw` (same staleness contract as `spliceSectionText`), rewrite * ONLY the existing `status:` header line's VALUE, leaving every other byte untouched: the rest * of that same line (key casing, colon spacing, trailing whitespace), the `assignee:` line if * present, the heading, the body, everything. Composes with `spliceSectionText`: call this FIRST * on the section's raw text, then feed the result in as `spliceSectionText`'s `freshRaw` — the * updated status line rides along inside `prefixRaw`, which `spliceSectionText` otherwise copies * verbatim. */ export declare function spliceStatusLine(raw: string, newStatus: string): string; /** Thrown when a partially recognized, malformed header makes insertion ambiguous. */ export declare class NoAssigneeInsertionPointError extends Error { } /** Rewrite, add, or remove one document item's `assignee:` header line. * * - Existing line + non-null value: rewrite only its value, preserving casing and whitespace. * - Existing line + null: remove only that line. * - Missing line + non-null value: insert after an existing `status:` line, or create a clean * one-field header at the section's deterministic heading/content boundary. * - Missing line + null: byte-identical no-op. * * A partially recognized header that was discarded by the parser still fails closed; inserting * into that ambiguous shape could accidentally reclassify user prose as metadata. */ export declare function spliceAssigneeLine(raw: string, newAssignee: string | null): string;