/** Parse a `.bulb.md` file: strict Markdown bundle with YAML frontmatter and `**filename**` blocks. */ import { type SubscriptKind } from './registry.js'; export declare const FENCE_OPEN_RE: RegExp; /** The closing-fence test for a given opening fence (the fence chars alone, trailing whitespace ok). */ export declare const fenceCloseRe: (fence: string) => RegExp; export interface BulbFrontmatter { format: string; name: string; } export interface ParsedBulb { frontmatter: BulbFrontmatter; /** Block contents keyed by filename (e.g. `code.tsx`). */ files: Map; /** * 1-based line number, in the `.bulb.md`, of each block's FIRST content line (the line after its * opening fence), keyed by filename. A bulb is a container: every tool inside it — tsc, lint, a * browser stack trace — reports block coordinates, while the only file the user can open and link * to is the bulb. This is the offset that maps one to the other (TB-CLI.md, One coordinate space). */ starts: Map; /** Structural defects tolerated during parse (an unterminated fence); empty when well-formed. */ warnings: string[]; /** * Line index (0-based, into the parsed content's `split('\n')`) just past the last *captured* block's * closing fence — i.e. where the bulb's body ends. NOT end-of-content: trailing lines that set no block * (prose, a stray `---`) sit beyond it. Equals the line after the frontmatter when no block was captured. * Lets a caller slice a bulb out of surrounding prose without swallowing what follows it (see * `findEmbeddedBulbs`). */ bodyEndLine: number; } /** Structured per-block content, keyed by kind. */ export type BulbData = { name: string; } & Record; /** Parse a `.bulb.md` file into frontmatter and file contents, or null if malformed. */ export declare function parseBulb(content: string): ParsedBulb | null; /** * Structural problems parseBulb tolerates silently — chiefly an unterminated code fence, which makes * the blocks below it fall *inside* the open one. parseBulb still "succeeds" (it just produces wrong * blocks), so on its own a malformed bulb compiles and renders as if clean — the gap a caller needs * flagged. A thin read over parseBulb's own structural pass (same single walk, so the two can't drift); * `null` (not a bulb at all) has no fence warnings to report. Empty when well-formed; never throws. */ export declare function validateBulbStructure(content: string): string[]; /** A bulb found sitting "naked" in prose — frontmatter and blocks dumped straight into the text with no * enclosing ````bulb```` fence. `start`/`end` are the half-open `[start, end)` line range (0-based, into * `content.split('\n')`); `source` is that slice, ready to feed back to `parseBulb` or a renderer. */ export interface EmbeddedBulb { start: number; end: number; source: string; } /** * Find bulbs embedded unfenced in arbitrary prose. The normal path wraps a bulb in a ````bulb```` fence * (and the mislabel-tolerant host promotes a fence whose body parses); but some non-SOTA models — Kimi * notably — skip the fence entirely and dump the raw frontmatter + blocks into the message, using `---` * thematic breaks as ad-hoc delimiters, so no fence token ever wraps the bulb. This scans for that. * * The frontmatter gate (`---\nformat: typebulb…`) is the same near-zero-false-positive signal the fenced * mislabel tolerance leans on, so we anchor on a `---` line, run `parseBulb` from there, and accept it * only if it yields at least one real block. The extent is `parseBulb`'s own `bodyEndLine` (just past the * last captured block) — NOT end-of-text — so trailing prose after the bulb (Kimi's closing `---`, a * follow-up paragraph) stays prose instead of being swallowed into the embed. Returned spans are * non-overlapping and in document order; the caller slices the surrounding prose around them. */ export declare function findEmbeddedBulbs(content: string): EmbeddedBulb[]; /** Convert a parsed bulb to a structured per-kind object (missing blocks become ''). */ export declare function toBulbData(parsed: ParsedBulb): BulbData; //# sourceMappingURL=parse.d.ts.map