@hawkeyexl/manni 0.0.0-bootstrap.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1623 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import { InferenceProvider } from '@hawkeyexl/inference';
3
+
4
+ /**
5
+ * The error every tool under the umbrella throws for an operational failure.
6
+ *
7
+ * Each tool keeps its own subclass (`DocmetaError`, …) so its tests and
8
+ * library callers can match on it. The base is what the shared bin runner
9
+ * matches on: a `ToolError` is reported as one line and exit 2, anything else
10
+ * is a bug and keeps its stack trace.
11
+ */
12
+ declare class ToolError extends Error {
13
+ /** clig.dev: 2 is operational/usage; 1 is reserved for findings. */
14
+ readonly exitCode: number;
15
+ constructor(message: string);
16
+ }
17
+
18
+ /**
19
+ * Shared types for docmeta.
20
+ *
21
+ * The pipeline is: load files -> extract metadata (format-specific) ->
22
+ * resolve a schema set per file -> validate against each schema -> report.
23
+ * Everything after extraction operates only on `ExtractedMetadata`, so new
24
+ * input formats never touch validation, resolution, or reporting.
25
+ */
26
+
27
+ /** Result of pulling a metadata block out of a single document. */
28
+ interface ExtractedMetadata {
29
+ /** Parsed metadata key/values. `{}` when a block is present but empty. */
30
+ data: Record<string, unknown>;
31
+ /** Whether a metadata block was found at all. */
32
+ present: boolean;
33
+ /**
34
+ * Whether the metadata came from a removable fenced front matter block.
35
+ * A per-extraction fact, deliberately not an extractor capability: RST and
36
+ * AsciiDoc read a fenced block when one exists and fall back to native
37
+ * docinfo/attribute parsing when not, so the same extractor yields both
38
+ * answers. Absent (element-backed, native-header) means `DELETE FROM docs`
39
+ * has no block whose removal would leave the document whole, and refuses.
40
+ */
41
+ fenced?: boolean;
42
+ /** Name of the extractor/format that produced this (e.g. "markdown"). */
43
+ format: string;
44
+ /**
45
+ * Map a JSON Pointer (Ajv `instancePath`, e.g. "/tags/0") or a bare top-level
46
+ * key to its 1-based source line, for precise annotations. Returns undefined
47
+ * when no position is known.
48
+ */
49
+ lineFor(this: void, pointer: string): number | undefined;
50
+ /**
51
+ * The column counterpart of {@link lineFor}, 1-based, resolving the same
52
+ * pointer forms.
53
+ *
54
+ * **Optional on purpose.** `lineFor` is required and public, so widening it
55
+ * to return a position pair would break every consumer that implements
56
+ * `MetadataExtractor` outside this repository. A format that cannot cheaply
57
+ * give a column simply omits this — today that is every frontmatter-based
58
+ * extractor, whose `yaml` node offsets would need an offset -> line/col
59
+ * conversion first. `html` and `xml` implement it.
60
+ */
61
+ colFor?(this: void, pointer: string): number | undefined;
62
+ }
63
+ /** Fenced front matter flavors, in fence order: `---`, `+++`, `;;;`. */
64
+ type FrontmatterFlavor = "yaml" | "toml" | "json";
65
+ /** Top-level metadata keys to set. Keys with `undefined` values are ignored. */
66
+ type MetadataPatch = Record<string, unknown>;
67
+ interface ApplyOptions {
68
+ /** Flavor to use when creating a block from scratch. Default "yaml". */
69
+ newBlockFlavor?: FrontmatterFlavor;
70
+ /**
71
+ * Top-level keys to remove entirely — deletion, where `patch` can only set
72
+ * (`undefined` values there are ignored by contract). Removing a key that
73
+ * is already absent is a no-op. Writers that cannot remove a key ignore
74
+ * this option, so a caller that needs certainty must re-extract and check —
75
+ * `runQuery`'s apply phase does exactly that and refuses the run on a
76
+ * survivor.
77
+ */
78
+ deletions?: readonly string[];
79
+ /**
80
+ * The document's path, when the caller knows it. `extract` receives one and
81
+ * `apply` did not, which left a writer unable to use the extension as a
82
+ * signal — the XML writer needs it to tell a DITA topic from hand-rolled XML
83
+ * that happens to have a `<task>` root.
84
+ */
85
+ filePath?: string;
86
+ /**
87
+ * The same `elements:` paths extraction was given.
88
+ *
89
+ * A writer re-reads the document to find where each key came from, and a read
90
+ * without these paths would not produce a config-declared key at all — so the
91
+ * writer would treat it as absent and create it somewhere else. That is the
92
+ * asymmetry proposal 0018 calls a loop, arriving through the options object
93
+ * rather than through the code.
94
+ */
95
+ elements?: readonly string[];
96
+ }
97
+ /** Per-run inputs to extraction, beyond the document itself. */
98
+ interface ExtractOptions {
99
+ /**
100
+ * Extra element paths to lift, from `elements:` config. Slash-separated from
101
+ * the document root, optionally ending in `@attribute`. These *extend* the
102
+ * per-format convention: a path producing a key the convention already filled
103
+ * is a no-op, so naming one cannot retype a key a content model typed exactly.
104
+ */
105
+ elements?: readonly string[];
106
+ }
107
+ /** A pluggable metadata extractor for one document format. */
108
+ interface MetadataExtractor {
109
+ /** Stable name, also used as `ExtractedMetadata.format`. */
110
+ name: string;
111
+ /** Lowercase file extensions this extractor handles, incl. dot (e.g. ".md"). */
112
+ extensions: string[];
113
+ /**
114
+ * Whether this extractor can *read* — false for a format that is registered
115
+ * but not yet wired up. Every registered extractor sets it true today; it is
116
+ * kept because it is a distinct capability from writability, which is the
117
+ * presence of `apply`. A format can read without writing, and one being
118
+ * added could be declared before it can do either.
119
+ */
120
+ implemented: boolean;
121
+ /**
122
+ * Extract metadata from raw file content.
123
+ *
124
+ * `this: void` — as on `apply` below, and on `ExtractedMetadata`'s
125
+ * `lineFor`/`colFor`. Every implementation in this repo is a plain function
126
+ * in an object literal and none of them reads `this`, so pulling one out
127
+ * (`const apply = extractor.apply`) is the ordinary thing it looks like
128
+ * rather than a binding hazard. Declaring that is what lets a reader — and
129
+ * `unbound-method` — know it.
130
+ *
131
+ * Retyping these as properties holding functions would say the same thing,
132
+ * and was tried first. It is the more expensive way: a property's parameters
133
+ * are contravariant where a method's are bivariant, so on an *exported*
134
+ * interface that swap silently narrows what an outside implementation may
135
+ * be, which is a semver-visible change bought for a lint fix. `this: void`
136
+ * leaves assignability exactly as it was.
137
+ */
138
+ extract(this: void, content: string, filePath: string, options?: ExtractOptions): ExtractedMetadata;
139
+ /**
140
+ * Return new content with every key in `patch` set at the top level. Pure:
141
+ * no IO, no mutation, deterministic; returns `content` itself for a no-op.
142
+ *
143
+ * Absent means the format is read-only. Present but throwing `DocmetaError`
144
+ * means this particular document cannot be rewritten safely.
145
+ */
146
+ apply?(this: void, content: string, patch: MetadataPatch, options?: ApplyOptions): string;
147
+ }
148
+ /** A single schema violation for one file, attributed to one schema. */
149
+ interface FieldError {
150
+ /** Schema id/ref that produced this error (e.g. "google:okf:0.1"). */
151
+ schema: string;
152
+ /** Ajv instancePath, e.g. "/tags/0" or "" for the root. */
153
+ instancePath: string;
154
+ /** Human-readable message. */
155
+ message: string;
156
+ /**
157
+ * Ajv keyword that failed (e.g. "required", "format", "pattern"), or
158
+ * "parse"/"schema" for the synthetic errors the command layer raises.
159
+ *
160
+ * This and `subject` are the machine-stable half of a violation's identity:
161
+ * `message` is generated prose that an Ajv upgrade may reword, so nothing
162
+ * durable — a baseline fingerprint, a SARIF `ruleId` — may be built from it.
163
+ */
164
+ keyword: string;
165
+ /**
166
+ * Discriminator within that keyword, when it is a stable identifier: the
167
+ * missing property, the additional property, the format name, the expected
168
+ * type. Deliberately unset for keywords whose parameter is a schema-authored
169
+ * *value* (`pattern`'s regex, `enum`'s list, `minLength`'s number), which
170
+ * changes whenever the schema is edited.
171
+ */
172
+ subject?: string;
173
+ /** 1-based source line, when known. */
174
+ line?: number;
175
+ /** 1-based column, when known. */
176
+ col?: number;
177
+ }
178
+ /** Validation outcome for a single file. */
179
+ interface ValidationResult {
180
+ /** Absolute or cwd-relative path of the file. */
181
+ file: string;
182
+ /** Extractor/format used. */
183
+ format: string;
184
+ /** Whether validation passed against every schema in the set. */
185
+ ok: boolean;
186
+ /** Schema ids/refs the file was validated against. */
187
+ schemas: string[];
188
+ /** All violations, across every schema in the set. */
189
+ errors: FieldError[];
190
+ /**
191
+ * Findings a baseline suppressed for this file. Absent when no baseline
192
+ * governed the run, or when it forgave nothing here.
193
+ */
194
+ baselined?: number;
195
+ }
196
+ /** How a baseline shaped the run. Present only when one governed it. */
197
+ interface BaselineSummary {
198
+ /** Baseline file path, spelled the way the user would type it. */
199
+ path: string;
200
+ /** Whether this run wrote the file (`--write-baseline`) or only read it. */
201
+ written: boolean;
202
+ /**
203
+ * Fingerprints the baseline holds. On a read this counts only the files the
204
+ * run checked, so validating one file does not report the rest as prunable.
205
+ */
206
+ recorded: number;
207
+ /** Findings the baseline suppressed. */
208
+ suppressed: number;
209
+ /** Recorded fingerprints for checked files that no longer occur. */
210
+ stale: number;
211
+ /** Fingerprints this write added. Write only. */
212
+ added?: number;
213
+ /** Fingerprints this write dropped. Write only. */
214
+ removed?: number;
215
+ }
216
+ /** Aggregate run summary. */
217
+ interface RunSummary {
218
+ files: number;
219
+ passed: number;
220
+ failed: number;
221
+ /** Violations reported. Baselined ones are excluded — see `baseline`. */
222
+ errors: number;
223
+ /**
224
+ * Candidate documents `.gitignore` removed from the walk. Omitted when it
225
+ * removed none. Reported because silent removal is what makes the filter
226
+ * dangerous — a counted removal is auditable.
227
+ */
228
+ gitignoreSkipped?: number;
229
+ baseline?: BaselineSummary;
230
+ }
231
+ /** An operational/usage failure that should map to exit code 2. */
232
+ declare class DocmetaError extends ToolError {
233
+ constructor(message: string);
234
+ }
235
+
236
+ /** What a schema reference is measured against when it names a local file. */
237
+ interface FingerprintContext {
238
+ /** Working directory a relative file ref was written against. */
239
+ cwd: string;
240
+ /** Directory canonical paths are expressed relative to: the config's, else `cwd`. */
241
+ base: string;
242
+ /**
243
+ * Directory a `ValidationResult.file` label is relative to. Usually `base`,
244
+ * but a run that took positional paths resolves them against `cwd` instead,
245
+ * so the two genuinely differ. Defaults to `base` when omitted.
246
+ */
247
+ runBase?: string;
248
+ }
249
+
250
+ interface SchemaOverride {
251
+ /**
252
+ * The glob, or globs, this override governs. A file matches when **any** of
253
+ * them matches, so a list groups path shapes that brace expansion cannot
254
+ * express as one pattern: a per-skill `SKILL.md` one directory down and a
255
+ * flat `.claude/agents` file share a schema set but have no common stem.
256
+ *
257
+ * Kept as written rather than normalized to a list, because a programmatic
258
+ * caller may hand `runValidate` a config object it built itself, and that
259
+ * caller's bare string must keep working. Read it through `overrideGlobs`
260
+ * rather than directly — that is the one place the two shapes collapse.
261
+ */
262
+ files: string | string[];
263
+ schemas: string[];
264
+ /**
265
+ * Optional collection name (proposal 0027): the override group becomes a
266
+ * SQL view of that name over the `docs` projection, holding exactly the
267
+ * files this override won schema resolution for. Any string is legal —
268
+ * view names are quoted identifiers — except the refusals `parseConfig`
269
+ * makes: a duplicate, `docs` (the table every query already reads), a
270
+ * blank name, and a name starting `sqlite_` (SQLite reserves the prefix).
271
+ * A `name:` also requires `schemas:`, because a schema-less override never
272
+ * wins resolution and its view would be empty by construction.
273
+ */
274
+ name?: string;
275
+ /**
276
+ * Extra element paths for files matching `files`. Unlike `schemas`, which the
277
+ * first matching override *replaces* because a schema set is a complete
278
+ * statement, these accumulate: every matching override contributes, on top of
279
+ * the top-level `elements:`. A list of extra places to look is additive by
280
+ * nature, and an override that silently dropped the repo-wide ones would be a
281
+ * trap.
282
+ */
283
+ elements?: string[];
284
+ }
285
+ /**
286
+ * A `schemas:` entry in its long form: a reference plus where it came from and
287
+ * what it must hash to.
288
+ *
289
+ * Written by `manni meta schemas vendor`, which downloads a remote schema into the
290
+ * repository and records both. `source` keeps the provenance the URL used to
291
+ * carry, so a re-vendor knows where to look and an error can say what to
292
+ * re-download; `integrity` makes an edited or corrupted copy a loud failure
293
+ * rather than a silently changed contract.
294
+ */
295
+ interface SchemaRefEntry {
296
+ /** What is loaded: a built-in id, a local `.json` path, or a URL. */
297
+ ref: string;
298
+ /** Where `ref` was vendored from — a URL, or a path for a local copy. */
299
+ source?: string;
300
+ /** `sha256-<64 hex>` over the bytes of `ref`. Local files only. */
301
+ integrity?: string;
302
+ }
303
+ /**
304
+ * One `schemas:` entry. A bare string is the original form and is unchanged by
305
+ * 0008; the mapping form adds provenance and a pin.
306
+ */
307
+ type SchemaEntry = string | SchemaRefEntry;
308
+ /**
309
+ * What a **document** is allowed to name in its own `$schema`.
310
+ *
311
+ * - `any` — the default, and today's behavior: a built-in id, a file in the
312
+ * repository, or a URL. `schemaTrust.hosts` narrows the URL case.
313
+ * - `local` — a built-in id or a file in the repository; a URL is refused.
314
+ * - `none` — the document's `$schema` is ignored and config decides, with a
315
+ * notice on stderr naming the file whose key was dropped.
316
+ */
317
+ type DocumentRefTrust = "any" | "local" | "none";
318
+ /**
319
+ * How far a **document** is trusted to choose the contract it is judged by.
320
+ *
321
+ * Nothing here touches a ref an *operator* supplied: `schemas:`,
322
+ * `overrides[].schemas`, and `-s/--schema` are never filtered, in any mode. A
323
+ * person who can edit the config or pass a flag is not the attacker this key
324
+ * has in mind — a pull request against a public docs repo is.
325
+ */
326
+ interface SchemaTrustConfig {
327
+ /** Defaults to `any`, which is exactly what docmeta has always done. */
328
+ documentRefs?: DocumentRefTrust;
329
+ /**
330
+ * Hosts a document-supplied URL may name. Consulted **only** under
331
+ * `documentRefs: any`; absent means any host, as before.
332
+ *
333
+ * A convenience for pointing at one known publisher, not a security
334
+ * boundary: `fetch` follows redirects, so an allowlisted host that answers
335
+ * `302` sends the fetch anywhere it likes. A repo that genuinely distrusts
336
+ * its contributors wants `documentRefs: local`.
337
+ */
338
+ hosts?: string[];
339
+ }
340
+ /**
341
+ * One named corpus check (proposal 0026): SQL run over the `docs` projection
342
+ * by `validate`, whose result rows are findings under the id `check:<name>`.
343
+ */
344
+ interface CheckConfig {
345
+ /** The check's name — the durable half of its findings' identity. */
346
+ name: string;
347
+ /** One SQL statement whose rows follow the finding column convention. */
348
+ query: string;
349
+ }
350
+ /** Defaults for the `fill` command; every key is overridable by a CLI flag. */
351
+ interface FillConfig {
352
+ provider?: string;
353
+ model?: string;
354
+ /** Minimum self-reported confidence to write a value (0-1). */
355
+ confidenceThreshold?: number;
356
+ /** Stop after this many inference calls. Counts calls, not files. */
357
+ maxTurns?: number;
358
+ /** Characters of document per call. Default 12000. */
359
+ chunkChars?: number;
360
+ concurrency?: number;
361
+ }
362
+ /** Settings for the cross-run cache of schemas fetched over `http(s)`. */
363
+ interface SchemaCacheConfig {
364
+ /**
365
+ * Hours a cached schema is served before it is re-fetched. `0` disables the
366
+ * cache entirely, in both directions.
367
+ */
368
+ ttlHours?: number;
369
+ }
370
+ interface DocmetaConfig {
371
+ paths?: string[];
372
+ exclude?: string[];
373
+ /**
374
+ * The default schema set. Each entry is either a reference string or a
375
+ * `{ ref, source?, integrity? }` mapping — see `SchemaEntry`.
376
+ */
377
+ schemas?: SchemaEntry[];
378
+ overrides?: SchemaOverride[];
379
+ /**
380
+ * Named corpus checks `validate` runs after the per-file schemas, when the
381
+ * run's file set is the config-resolved corpus. See `CheckConfig`.
382
+ */
383
+ checks?: CheckConfig[];
384
+ /**
385
+ * Element paths to lift in addition to each format's convention. See
386
+ * `parseElementPath` for the syntax.
387
+ */
388
+ elements?: string[];
389
+ fill?: FillConfig;
390
+ /**
391
+ * Path to a validation baseline, relative to **this config file**. Setting it
392
+ * implies `--baseline` on every run; `--no-baseline` suppresses it for one.
393
+ */
394
+ baseline?: string;
395
+ /**
396
+ * Treat an input set that resolves to zero files as success rather than an
397
+ * operational error. Off by default: a glob that stops matching would
398
+ * otherwise leave a permanently green gate that checks nothing.
399
+ */
400
+ allowEmpty?: boolean;
401
+ /**
402
+ * Skip files `.gitignore` covers when expanding directories and globs. On by
403
+ * default; set false to check generated or vendored documents the repo does
404
+ * not track. Setting it **true** explicitly also asks to be told when git
405
+ * cannot answer — see `GITIGNORE_UNAVAILABLE`.
406
+ */
407
+ respectGitignore?: boolean;
408
+ /** Defaults for the cross-run schema cache. See `SchemaCacheConfig`. */
409
+ schemaCache?: SchemaCacheConfig;
410
+ /**
411
+ * Never fetch a remote schema. A URL reference resolves from the schema
412
+ * cache; an uncached one is an operational error naming the URL. Built-in and
413
+ * local-file references are unaffected — neither touches the network.
414
+ */
415
+ offline?: boolean;
416
+ /**
417
+ * How far a document's own `$schema` is trusted. Absent means `any` — every
418
+ * setup that exists today, unchanged. See `SchemaTrustConfig`.
419
+ */
420
+ schemaTrust?: SchemaTrustConfig;
421
+ }
422
+ /**
423
+ * Parse and validate config YAML text whose top level *is* the metadata
424
+ * tool's config — a pre-family `docmeta.config.yaml`, or a section already
425
+ * cut out of the family file.
426
+ */
427
+ declare function parseConfig(text: string, source: string): DocmetaConfig;
428
+ interface LoadedConfig {
429
+ config: DocmetaConfig;
430
+ /** Absolute path to the file the config was read from. */
431
+ path: string;
432
+ /**
433
+ * Directory holding that file. Relative paths written *in* the config —
434
+ * `paths:`, `exclude:`, local-file schema refs — are meaningful relative to
435
+ * this, not to the directory the command happened to be invoked from.
436
+ */
437
+ dir: string;
438
+ /**
439
+ * The family-file key the config was read from under (`"meta"`), when it
440
+ * was. Absent for a pre-family file, whose top level is the config. A
441
+ * command that writes the file back (`schemas vendor`) needs to know.
442
+ */
443
+ section?: string;
444
+ }
445
+
446
+ /**
447
+ * The directory a **document-supplied** local schema path must stay inside.
448
+ *
449
+ * The git root rather than the config's directory, so a monorepo package whose
450
+ * documents reference `../shared/x.json` keeps working — that path is still
451
+ * inside the repository, which is what "a schema in this project" means.
452
+ *
453
+ * `source` is not decoration, and it has **three** values rather than a
454
+ * boolean: with no repository the boundary falls back to the config's
455
+ * directory, and with no config either it falls back to the run's `cwd`. Those
456
+ * are progressively narrower and less obvious rules, and the refusal message
457
+ * has to name the one it actually applied — telling someone with no config file
458
+ * that "the config's own directory is the boundary" sends them looking for a
459
+ * file that is not there.
460
+ *
461
+ * Same reasoning as `SARIF_NO_GIT_ROOT`: "there is no repository" and "the
462
+ * repository root is where you are standing" must stay distinguishable.
463
+ */
464
+ interface SchemaTrustRoot {
465
+ /** Absolute directory the path must resolve inside. */
466
+ dir: string;
467
+ /** Which rule produced `dir`, so a refusal can name it accurately. */
468
+ source: "git" | "config" | "cwd";
469
+ }
470
+ /**
471
+ * Load config from an explicit path (error if missing) or by discovery.
472
+ *
473
+ * Discovery checks cwd and then each ancestor up to and including the nearest
474
+ * `.git` boundary. Within a directory the order is the family file
475
+ * (`manni.config.yaml`, then `.yml`, read at its `meta:` key), the pre-rename
476
+ * family file (`moose.config.yaml`), then `docmeta.config.yaml` and `.yml`
477
+ * whole. The **first file found wins** and the walk stops there — ancestor
478
+ * configs are never merged, because `schemas:` is a set a file must satisfy in
479
+ * full and `overrides:` is first-match-wins ordered, so a partial merge would
480
+ * silently redefine what "the contract" means. See src/shared/config-file.ts
481
+ * for the rest of the rules, the deprecation warnings included.
482
+ *
483
+ * Returns null when no config is found via discovery.
484
+ */
485
+ declare function loadConfig(explicitPath?: string, cwd?: string): Promise<LoadedConfig | null>;
486
+ /** Told to a caller once, when a run turns out to be governed by a config. */
487
+ interface ConfigNotice {
488
+ /** Absolute path to the config file. */
489
+ path: string;
490
+ /** Directory holding it. */
491
+ dir: string;
492
+ }
493
+ interface RunConfigOptions {
494
+ /** Defaults to `process.cwd()`, matching `loadConfig`. */
495
+ cwd?: string;
496
+ /** `-c/--config`. */
497
+ configPath?: string;
498
+ /** `--no-config`: skip discovery and run on the built-in defaults. */
499
+ noConfig?: boolean;
500
+ /** Positional inputs; empty means fall back to the config's `paths:`. */
501
+ inputs: string[];
502
+ onConfigLoaded?: (info: ConfigNotice) => void;
503
+ }
504
+ interface RunConfig {
505
+ /** The config, with its local file schema refs already rebased. */
506
+ config: DocmetaConfig | null;
507
+ /** What to resolve: the positional inputs, or the config's `paths:`. */
508
+ inputs: string[];
509
+ /**
510
+ * Directory those inputs — and so every resolved file path, and every file
511
+ * read — are relative to.
512
+ *
513
+ * A run uses *either* positional paths *or* config `paths:`, never both, so
514
+ * there is exactly one base per run and no ambiguity about which it is.
515
+ * Positional paths are typed by a person standing in a shell, so they stay
516
+ * relative to the working directory; `paths:` globs were written next to the
517
+ * config, so they resolve from there.
518
+ */
519
+ base: string;
520
+ /**
521
+ * Directory holding the config that governed the run, when one did.
522
+ *
523
+ * Distinct from `base`: `base` follows *the inputs*, so it is the working
524
+ * directory whenever positional paths were given. Anything written **in** the
525
+ * config — the `baseline:` path — is relative to the config itself no matter
526
+ * where the command was run from, which is the whole point of discovering an
527
+ * ancestor config in the first place.
528
+ */
529
+ configDir?: string;
530
+ /**
531
+ * Absolute path of the config file itself, when one governs the run. The
532
+ * one honest way to edit the governing config: discovery accepts both
533
+ * `docmeta.config.yaml` and `.yml`, `-c` accepts any name, and the file may
534
+ * live in an ancestor — so re-deriving the path from a directory plus an
535
+ * assumed filename names the wrong file in every one of those setups.
536
+ */
537
+ configPath?: string;
538
+ }
539
+ /**
540
+ * Settle the three things every command core needs from config before it can
541
+ * touch the filesystem: which config governs the run, what to resolve, and
542
+ * what those relative paths are relative to.
543
+ */
544
+ declare function resolveRunConfig(opts: RunConfigOptions): Promise<RunConfig>;
545
+
546
+ interface ValidateOptions {
547
+ inputs: string[];
548
+ cliSchemas?: string[];
549
+ exts?: string[];
550
+ exclude?: string[];
551
+ /** `--as` format override (extractor name). */
552
+ as?: string;
553
+ configPath?: string;
554
+ /** `--no-config`: skip config discovery and use the built-in defaults. */
555
+ noConfig?: boolean;
556
+ cwd?: string;
557
+ /** Content for the `-` (stdin) input, injected by the CLI/tests. */
558
+ stdinContent?: string;
559
+ /** Permit an input set that resolves to zero files (see `assertNonEmpty`). */
560
+ allowEmpty?: boolean;
561
+ /**
562
+ * `--no-gitignore` (false). Absent leaves config `respectGitignore:` in
563
+ * charge, which itself defaults to on.
564
+ */
565
+ respectGitignore?: boolean;
566
+ /** Diagnostics for the user; the CLI writes these to stderr. */
567
+ onNotice?: (message: string) => void;
568
+ /**
569
+ * `--baseline [path]`: compare findings against a recorded baseline and fail
570
+ * only on new ones. A string is a path relative to `cwd`; `true` means the
571
+ * default path; `false` is `--no-baseline`, which suppresses a baseline the
572
+ * config supplied. Absent means "whatever the config says".
573
+ */
574
+ baseline?: string | boolean;
575
+ /**
576
+ * `--write-baseline [path]`: record this run's findings as the baseline
577
+ * instead of comparing against one. Wins over `baseline`.
578
+ */
579
+ writeBaseline?: string | boolean;
580
+ /** Called once when a config governs the run, so the CLI can report it. */
581
+ onConfigLoaded?: (info: ConfigNotice) => void;
582
+ /**
583
+ * `--offline`: never fetch a remote schema. Absent leaves config `offline:`
584
+ * in charge, which itself defaults to off.
585
+ */
586
+ offline?: boolean;
587
+ /**
588
+ * `--no-checks` (false): skip the config's named corpus checks for this
589
+ * run. Absent leaves them on — they still only run when the resolved file
590
+ * set is the config-resolved corpus (proposal 0026).
591
+ */
592
+ checks?: boolean;
593
+ }
594
+ interface ValidateRun {
595
+ results: ValidationResult[];
596
+ summary: RunSummary;
597
+ /**
598
+ * Where the run stood: the working directory, the directory canonical paths
599
+ * are measured from, and the directory `results[].file` labels are relative
600
+ * to.
601
+ *
602
+ * Returned rather than kept private because a `ValidationResult.file` is only
603
+ * meaningful *with* it. A reporter that has to name a file the same way from
604
+ * anywhere — SARIF, whose `artifactLocation.uri` GitHub resolves against the
605
+ * repository root — cannot reconstruct this after the fact, and guessing puts
606
+ * it in the same false-green trap the baseline's canonical keys exist to
607
+ * avoid.
608
+ */
609
+ frame: FingerprintContext;
610
+ }
611
+ declare function runValidate(opts: ValidateOptions): Promise<ValidateRun>;
612
+
613
+ interface GetOptions {
614
+ fields: string[];
615
+ inputs: string[];
616
+ as?: string;
617
+ exclude?: string[];
618
+ exts?: string[];
619
+ configPath?: string;
620
+ /** `--no-config`: skip config discovery and use the built-in defaults. */
621
+ noConfig?: boolean;
622
+ cwd?: string;
623
+ /** Content for the `-` (stdin) input, injected by the CLI/tests. */
624
+ stdinContent?: string;
625
+ /** Permit an input set that resolves to zero files (see `assertNonEmpty`). */
626
+ allowEmpty?: boolean;
627
+ /**
628
+ * `--no-gitignore` (false). Absent leaves config `respectGitignore:` in
629
+ * charge, which itself defaults to on.
630
+ */
631
+ respectGitignore?: boolean;
632
+ /** Diagnostics for the user; the CLI writes these to stderr. */
633
+ onNotice?: (message: string) => void;
634
+ /** Called once when a config governs the run, so the CLI can report it. */
635
+ onConfigLoaded?: (info: ConfigNotice) => void;
636
+ /**
637
+ * `--offline`, accepted for surface parity with `validate` and `fill`.
638
+ *
639
+ * It has **no effect here**, and that is a property of the command rather
640
+ * than an omission: `get` prints extracted field values and never resolves or
641
+ * loads a schema, so it has no network dependency to suppress. Accepting it
642
+ * keeps one flag set across the three commands, so a script can pass
643
+ * `--offline` uniformly without knowing which subcommand needs it.
644
+ */
645
+ offline?: boolean;
646
+ }
647
+ interface GetFileResult {
648
+ file: string;
649
+ present: boolean;
650
+ values: Record<string, unknown>;
651
+ /**
652
+ * Why this file yielded no values, when it yielded none for a reason.
653
+ *
654
+ * Set only when the document's metadata block could not be read at all — the
655
+ * same throw `validate` turns into a `(parse)` finding. Absent on every file
656
+ * that parsed, including one with no metadata block and one where every
657
+ * requested field was unset: those are answers, and this is the absence of
658
+ * one. A run carrying any `error` exits 1.
659
+ */
660
+ error?: string;
661
+ }
662
+ declare function runGet(opts: GetOptions): Promise<GetFileResult[]>;
663
+
664
+ interface QueryOptions {
665
+ /**
666
+ * One SQL statement. The table is `docs`; see the system columns below.
667
+ * May be empty when `db` is set — export without querying.
668
+ */
669
+ sql: string;
670
+ /**
671
+ * `--db`: also write the built database to this file, for any SQLite
672
+ * front-end (sqlite3, Datasette, duckdb) to open afterwards. The file is a
673
+ * regenerated artifact: an existing SQLite file at the path is overwritten,
674
+ * anything else is refused.
675
+ */
676
+ db?: string;
677
+ inputs: string[];
678
+ as?: string;
679
+ exclude?: string[];
680
+ exts?: string[];
681
+ configPath?: string;
682
+ /** `--no-config`: skip config discovery and use the built-in defaults. */
683
+ noConfig?: boolean;
684
+ cwd?: string;
685
+ /** Content for the `-` (stdin) input, injected by the CLI/tests. */
686
+ stdinContent?: string;
687
+ /** Permit an input set that resolves to zero files (see `assertNonEmpty`). */
688
+ allowEmpty?: boolean;
689
+ /**
690
+ * `--no-gitignore` (false). Absent leaves config `respectGitignore:` in
691
+ * charge, which itself defaults to on.
692
+ */
693
+ respectGitignore?: boolean;
694
+ /** Diagnostics for the user; the CLI writes these to stderr. */
695
+ onNotice?: (message: string) => void;
696
+ /** Called once when a config governs the run, so the CLI can report it. */
697
+ onConfigLoaded?: (info: ConfigNotice) => void;
698
+ /**
699
+ * `--offline`, accepted for surface parity with the other commands. DDL
700
+ * statements do resolve the corpus's schema set (0024), but only from disk
701
+ * and the bundled built-ins — a URL ref refuses with "vendor it first"
702
+ * before anything could fetch — so there is still no network dependency to
703
+ * suppress.
704
+ */
705
+ offline?: boolean;
706
+ /**
707
+ * `--dry-run`: preview the statement's per-file changes — the diff it
708
+ * would make, files untouched. Without it a mutating statement applies,
709
+ * matching `fill`'s convention (proposal 0025; 0022 recorded the original
710
+ * preview-by-default surface this revises).
711
+ */
712
+ dryRun?: boolean;
713
+ /**
714
+ * Values for the statement's named parameters (`$name`, `:name`, `@name`),
715
+ * keyed by bare name (a `$`/`:`/`@` prefix on a key is tolerated). Each
716
+ * value passes through the same `bindValue` the projection loader uses —
717
+ * booleans become 1/0, arrays and objects JSON text — so a bound parameter
718
+ * compares against a stored cell under exactly the encoding the cell got
719
+ * (proposal 0029). A parameter the SQL references with no entry here
720
+ * refuses: unbound would silently bind NULL and match nothing.
721
+ */
722
+ params?: Record<string, unknown>;
723
+ /**
724
+ * `-s/--schema`, repeatable: the schema set the run's DDL evolves — CLI
725
+ * precedence for the DDL planner *only* (proposal 0030). The per-file
726
+ * resolution walk is skipped and the deduped refs are the set; every guard
727
+ * inside the set (single local file for ADD, sole declarer for
728
+ * DROP/RENAME, builtin fork, URL refusal, the trust boundary) runs
729
+ * unchanged. Collection views keep following the config's resolution. A
730
+ * run whose statement produces no DDL effect refuses before anything is
731
+ * applied — a flag that would silently mean nothing must refuse.
732
+ */
733
+ schemas?: string[];
734
+ }
735
+ /**
736
+ * One thing a statement changed, in file-space terms. Cell-level kinds carry
737
+ * a `key` (a set, a deletion via `SET k = NULL` / `ALTER DROP COLUMN`, or a
738
+ * key rename); file-level kinds carry the whole event (`cleared` — the block
739
+ * stripped by DELETE; `created` — a file INSERT made; `renamed` — a `_path`
740
+ * move). Exactly one kind per object.
741
+ */
742
+ type QueryChange = {
743
+ file: string;
744
+ written: boolean;
745
+ } & ({
746
+ key: string;
747
+ from: unknown;
748
+ to: unknown;
749
+ } | {
750
+ key: string;
751
+ from: unknown;
752
+ deleted: true;
753
+ } | {
754
+ key: string;
755
+ renamedFrom: string;
756
+ to: unknown;
757
+ } | {
758
+ cleared: true;
759
+ from: Record<string, unknown>;
760
+ } | {
761
+ created: true;
762
+ to: Record<string, unknown>;
763
+ } | {
764
+ renamed: string;
765
+ } | {
766
+ /** A DDL statement edited the schema itself (0024): `file` is the
767
+ * schema written — an in-place edit, or the fork of a builtin. */
768
+ schema: true;
769
+ op: "add" | "drop" | "rename";
770
+ key: string;
771
+ renamedTo?: string;
772
+ type?: string;
773
+ /** 0028: a declared type equal to a format name carries the format. */
774
+ format?: string;
775
+ /** 0028: a `CHECK (k IN (…))` on the added column carries the enum. */
776
+ enum?: (string | number)[];
777
+ required?: boolean;
778
+ forkedFrom?: string;
779
+ } | {
780
+ /** A DDL side effect on the governing config file: a fork repoints the
781
+ * `schemas:` entry (`key: "schemas"`), an in-place edit of a pinned
782
+ * schema refreshes its pin (`key: "integrity"`). Disclosed as a change
783
+ * because the preview must name every file `--write` will touch. */
784
+ config: true;
785
+ key: string;
786
+ from: unknown;
787
+ to: unknown;
788
+ });
789
+ interface QueryRun {
790
+ /** Result column names, in SELECT order — present even for zero rows. */
791
+ columns: string[];
792
+ rows: Record<string, unknown>[];
793
+ /** Set when `db` was written: where, and how big the table is. */
794
+ db?: {
795
+ path: string;
796
+ files: number;
797
+ columns: number;
798
+ };
799
+ /**
800
+ * Present when the statement was a metadata edit: every cell it changed
801
+ * (empty when a mutating statement matched nothing). Absent on reads.
802
+ */
803
+ changes?: QueryChange[];
804
+ /**
805
+ * Where the run stood, in the same shape `ValidateRun.frame` carries — the
806
+ * path-normalization frame SARIF and JUnit need before they can name a file
807
+ * the way the repository does (proposal 0026). Constructed from the run's
808
+ * `cwd`, its config directory, and the directory file labels resolve
809
+ * against; absent only when a caller built a `QueryRun` by hand.
810
+ */
811
+ frame?: FingerprintContext;
812
+ }
813
+ declare function runQuery(opts: QueryOptions): Promise<QueryRun>;
814
+
815
+ interface BuiltinInfo {
816
+ id: string;
817
+ title: string;
818
+ description: string;
819
+ }
820
+ declare function listBuiltins(): BuiltinInfo[];
821
+ type RefKind = "builtin" | "file" | "url";
822
+ declare function classifyRef(ref: string): {
823
+ kind: RefKind;
824
+ ref: string;
825
+ };
826
+ /**
827
+ * What a config recorded about one reference beyond the reference itself.
828
+ *
829
+ * Kept out of the ref string deliberately: the ref appears in every report,
830
+ * every baseline fingerprint, and `Validator`'s compile cache key, so it has to
831
+ * stay exactly the string the user wrote.
832
+ */
833
+ interface SchemaPin {
834
+ /** Where the reference was vendored from — a URL, or a local path. */
835
+ source?: string;
836
+ /** `sha256-<64 hex>` the file's bytes must hash to. */
837
+ integrity?: string;
838
+ }
839
+ interface LoadSchemaOptions {
840
+ /**
841
+ * Directory a **relative local-file** ref is resolved against.
842
+ *
843
+ * Omitted means `process.cwd()`, which is what the CLI wants and what this
844
+ * always did. A library caller passing `cwd` to a command core needs the
845
+ * ref measured from *that* directory instead: `rebaseConfigSchemaRefs`
846
+ * deliberately leaves refs untouched when the config already sits in the
847
+ * run's `cwd`, so `./schema/house.json` arrives here exactly as written and
848
+ * was then read against the wrong directory.
849
+ *
850
+ * Resolved at read time rather than by rewriting the ref, and that choice is
851
+ * load-bearing: the ref string is what reports name, what `Validator` keys
852
+ * its compile cache on, and what every baseline fingerprint is taken over.
853
+ * Rewriting it to an absolute path would silently move every recorded
854
+ * baseline. `canonicalSchemaRef` in `baseline.ts` already measures a relative
855
+ * ref from the run's `cwd`, so this makes loading agree with fingerprinting
856
+ * rather than introducing a new convention.
857
+ */
858
+ fileBase?: string;
859
+ /** Abort a remote fetch after this many ms (default 10_000). */
860
+ timeoutMs?: number;
861
+ /** Reject a remote schema whose body exceeds this many bytes (default 5 MB). */
862
+ maxBytes?: number;
863
+ /**
864
+ * Directory for the cross-run schema cache. Omitted means **no disk cache**:
865
+ * the registry never guesses a project root, so a library caller gets the
866
+ * in-process behavior until it opts in. The command cores pass
867
+ * `schemaCacheDir(configDir ?? cwd)`.
868
+ */
869
+ cacheDir?: string;
870
+ /** Hours a cached entry stays fresh; `0` disables the cache (default 24). */
871
+ ttlHours?: number;
872
+ /**
873
+ * Never touch the network. A URL ref resolves from the disk cache — ignoring
874
+ * the TTL, since there is no re-fetch to fall back on — and an uncached one
875
+ * fails naming the URL. Built-ins and local files are unaffected.
876
+ *
877
+ * This is a *durability* control, not a trust boundary, and it never was:
878
+ * whether a document may name a URL at all is decided upstream by
879
+ * `schemaTrust` in `resolveSchemaSet`, which is the last place that still
880
+ * knows a ref came from a document rather than from an operator (proposal
881
+ * 0015). `offline` used to block that case by accident and was the only thing
882
+ * standing there; it is now free to mean only what it says.
883
+ */
884
+ offline?: boolean;
885
+ /**
886
+ * Provenance and integrity pins, keyed on the reference exactly as it is
887
+ * passed to `loadSchema`. Built by `collectSchemaPins` from the **rebased**
888
+ * config, so both sides spell a local path the same way; a config with no
889
+ * mapping-form `schemas:` entries produces an empty map and none of this
890
+ * runs.
891
+ */
892
+ pins?: ReadonlyMap<string, SchemaPin>;
893
+ }
894
+ /** A fetched schema, with the bytes it arrived as. */
895
+ interface FetchedSchema {
896
+ /** Exactly what the server sent, undecoded. */
897
+ bytes: Buffer;
898
+ /** The same payload, parsed and guarded. */
899
+ schema: Record<string, unknown>;
900
+ }
901
+ /**
902
+ * Fetch, size-cap, parse, and guard a remote schema. At most two requests.
903
+ *
904
+ * Exported for `schemas vendor`, which needs the raw bytes to write and to
905
+ * hash. Sharing this path rather than fetching separately is what keeps
906
+ * vendoring subject to the same size cap, retry policy, and payload guard as
907
+ * validation — a vendored error envelope would otherwise be committed to the
908
+ * repository and pass every document from then on.
909
+ *
910
+ * Deliberately **not** routed through the disk cache or `offline`: vendoring is
911
+ * an explicit request to download, and the cache stores a parsed schema rather
912
+ * than the bytes a pin has to be taken over.
913
+ */
914
+ declare function fetchSchemaBytes(ref: string, options?: LoadSchemaOptions): Promise<FetchedSchema>;
915
+ /**
916
+ * Settle the remote-schema options for one run, from the config and the flag.
917
+ *
918
+ * Lives here rather than in a command core because all three commands need the
919
+ * same answer, and because "where does the cache live" is a property of schema
920
+ * loading, not of `validate`. `root` is the config's directory when a config
921
+ * governs the run, so a developer running from `docs/` shares the cache with
922
+ * CI running from the repo root instead of quietly keeping a second one.
923
+ */
924
+ declare function schemaLoadOptions(args: {
925
+ root: string;
926
+ /**
927
+ * Where a relative local-file schema ref is measured from — the run's `cwd`,
928
+ * not `root`. The two differ when a config was discovered in an ancestor, and
929
+ * a `--schema ./x.json` typed on the command line belongs to the directory
930
+ * the user was standing in, not to the config's.
931
+ */
932
+ fileBase?: string;
933
+ /** Config `schemaCache.ttlHours`. */
934
+ ttlHours?: number;
935
+ /** `--offline`, else config `offline:`. */
936
+ offline?: boolean;
937
+ /** From `collectSchemaPins(config)`; omitted when the config pins nothing. */
938
+ pins?: ReadonlyMap<string, SchemaPin>;
939
+ }): LoadSchemaOptions;
940
+ /** Load and return the JSON Schema object for a reference. */
941
+ declare function loadSchema(ref: string, options?: LoadSchemaOptions): Promise<Record<string, unknown>>;
942
+
943
+ interface SchemasInfo {
944
+ builtins: BuiltinInfo[];
945
+ formats: {
946
+ name: string;
947
+ extensions: string[];
948
+ implemented: boolean;
949
+ /** Whether `manni meta fill` can write metadata back to this format. */
950
+ writable: boolean;
951
+ }[];
952
+ }
953
+ declare function getSchemasInfo(): SchemasInfo;
954
+ /**
955
+ * Where a vendored schema lands by default.
956
+ *
957
+ * **Not** `.docmeta/`, which is gitignored wholesale and holds the schema and
958
+ * proposal caches. A vendored schema is the opposite kind of artifact: it has
959
+ * to be committed, because being in the consuming repository's own history is
960
+ * the entire point of vendoring.
961
+ */
962
+ declare const DEFAULT_VENDOR_DIR = "./schema";
963
+ interface VendorOptions {
964
+ /** The `http(s)` URL to download. */
965
+ url: string;
966
+ /** Directory for the vendored copy, relative to `cwd`. Default `./schema`. */
967
+ dir?: string;
968
+ /** `-c/--config`. Absent discovers a config, or creates one in `cwd`. */
969
+ configPath?: string;
970
+ cwd?: string;
971
+ /** Diagnostics for the user; the CLI writes these to stderr. */
972
+ onNotice?: (message: string) => void;
973
+ /** Fetch timeout, in ms. Defaults to the registry's. */
974
+ timeoutMs?: number;
975
+ /** Response size cap, in bytes. Defaults to the registry's. */
976
+ maxBytes?: number;
977
+ }
978
+ interface VendorResult {
979
+ /** The URL that was downloaded. */
980
+ url: string;
981
+ /** The vendored file, relative to `cwd`, posix-style. */
982
+ file: string;
983
+ /** The pin recorded for it. */
984
+ integrity: string;
985
+ /** Size of the vendored copy, in bytes. */
986
+ bytes: number;
987
+ /** The config that was written, relative to `cwd`, posix-style. */
988
+ config: string;
989
+ /** Whether that config had to be created. */
990
+ configCreated: boolean;
991
+ /** Whether an existing `schemas:` entry was replaced rather than appended. */
992
+ replaced: boolean;
993
+ /** Whether the downloaded bytes were identical to the copy already on disk. */
994
+ unchanged: boolean;
995
+ }
996
+ /**
997
+ * The filename for a vendored schema, derived from the URL's last path segment.
998
+ *
999
+ * Sanitized rather than trusted: the segment reaches the filesystem, so
1000
+ * anything that is not an ordinary filename character is replaced, and a
1001
+ * leading dot is prefixed away so the copy cannot land as a hidden file that
1002
+ * directory walks skip.
1003
+ */
1004
+ declare function vendorFileName(url: string): string;
1005
+ /**
1006
+ * Download a remote schema into the repository and pin it.
1007
+ *
1008
+ * The order of operations is the contract: everything that can refuse does so
1009
+ * *before* the network call or the write, so a refused run leaves the working
1010
+ * tree exactly as it found it.
1011
+ */
1012
+ declare function runVendorSchema(opts: VendorOptions): Promise<VendorResult>;
1013
+
1014
+ /** Shared shapes for the `fill` command, split out to keep imports acyclic. */
1015
+
1016
+ /** Why a proposed value was not written. */
1017
+ type SkipReason =
1018
+ /** Self-reported confidence was below the threshold. */
1019
+ "low-confidence"
1020
+ /** Writing it would leave the document failing its own schema. */
1021
+ | "schema-mismatch"
1022
+ /** The model declined to propose a value. */
1023
+ | "no-proposal";
1024
+ interface FilledField {
1025
+ /** JSON Pointer, e.g. "/title" — the same form `validate` reports. */
1026
+ field: string;
1027
+ required: boolean;
1028
+ confidence: number;
1029
+ reasoning: string;
1030
+ /** Absent when the field was skipped. */
1031
+ value?: unknown;
1032
+ written: boolean;
1033
+ skipReason?: SkipReason;
1034
+ }
1035
+ interface FillFileResult {
1036
+ file: string;
1037
+ format: string;
1038
+ schemas: string[];
1039
+ fields: FilledField[];
1040
+ /** Whether the file's content changed (false under --dry-run too). */
1041
+ changed: boolean;
1042
+ /** Parse failure, read-only format, or provider error. */
1043
+ error?: string;
1044
+ /** The filled document. Populated only when the caller asks for it. */
1045
+ content?: string;
1046
+ }
1047
+ interface FillSummary {
1048
+ files: number;
1049
+ changed: number;
1050
+ written: number;
1051
+ skipped: number;
1052
+ /** Skipped fields that the schema lists as required — drives exit code 1. */
1053
+ requiredSkipped: number;
1054
+ errors: number;
1055
+ costUsd: number;
1056
+ cached: number;
1057
+ }
1058
+ interface FillRun {
1059
+ results: FillFileResult[];
1060
+ summary: FillSummary;
1061
+ /** Echoed so JSON consumers and CI can assert which gate actually ran. */
1062
+ threshold: number;
1063
+ dryRun: boolean;
1064
+ provider: string;
1065
+ model: string;
1066
+ /** True when the call cap stopped the run before every file was seen. */
1067
+ turnsSpent: boolean;
1068
+ }
1069
+ interface FillOptions {
1070
+ inputs: string[];
1071
+ cliSchemas?: string[];
1072
+ exts?: string[];
1073
+ exclude?: string[];
1074
+ /** `--as` format override (extractor name). */
1075
+ as?: string;
1076
+ configPath?: string;
1077
+ /** `--no-config`: skip config discovery and use the built-in defaults. */
1078
+ noConfig?: boolean;
1079
+ cwd?: string;
1080
+ /** Content for the `-` (stdin) input, injected by the CLI/tests. */
1081
+ stdinContent?: string;
1082
+ /** Permit an input set that resolves to zero files (see `assertNonEmpty`). */
1083
+ allowEmpty?: boolean;
1084
+ /**
1085
+ * `--no-gitignore` (false). Absent leaves config `respectGitignore:` in
1086
+ * charge, which itself defaults to on.
1087
+ */
1088
+ respectGitignore?: boolean;
1089
+ /** Diagnostics for the user; the CLI writes these to stderr. */
1090
+ onNotice?: (message: string) => void;
1091
+ /** Called once when a config governs the run, so the CLI can report it. */
1092
+ onConfigLoaded?: (info: ConfigNotice) => void;
1093
+ /**
1094
+ * `--offline`: never fetch a remote **schema**. Absent leaves config
1095
+ * `offline:` in charge.
1096
+ *
1097
+ * Scoped to schema loading only. It says nothing about the inference
1098
+ * provider, which is a separate network dependency with its own controls
1099
+ * (`--provider mock`, `--dry-run`).
1100
+ */
1101
+ offline?: boolean;
1102
+ /** Restrict proposals to these top-level fields. */
1103
+ fields?: string[];
1104
+ /** Minimum self-reported confidence to write (0-1). Default 0.7. */
1105
+ confidence?: number;
1106
+ /** Report proposals without writing them. */
1107
+ dryRun?: boolean;
1108
+ provider?: string;
1109
+ model?: string;
1110
+ /** Use the on-disk proposal cache. Default true. */
1111
+ cache?: boolean;
1112
+ /** Refuse a hosted provider: inference must run on this machine. */
1113
+ local?: boolean;
1114
+ /** Stop after this many inference calls. Counts calls, not files. */
1115
+ maxTurns?: number;
1116
+ /** Characters of document per call. Default 12000. */
1117
+ chunkChars?: number;
1118
+ /** Files inferred in parallel. Default 4. */
1119
+ concurrency?: number;
1120
+ /** Include the filled document on each result (used for stdin and tests). */
1121
+ includeContent?: boolean;
1122
+ /** Test seam: bypasses `makeProvider`, so no API key is needed. */
1123
+ inferenceProvider?: InferenceProvider;
1124
+ }
1125
+
1126
+ declare function runFill(opts: FillOptions): Promise<FillRun>;
1127
+
1128
+ declare class Validator {
1129
+ private readonly schemaOptions;
1130
+ /**
1131
+ * How this validator's schemas are loaded: the disk cache location, its TTL,
1132
+ * and `--offline`. Held per instance rather than read from module state, so
1133
+ * two differently-configured validations in one process each get their own
1134
+ * settings.
1135
+ *
1136
+ * That is not full isolation, and the difference matters to a library
1137
+ * caller: `schema-registry` keeps a process-wide memo of fetched schemas, so
1138
+ * one validator's successful fetch is visible to another. `offline` is
1139
+ * excluded from that sharing on purpose — an offline validator will not be
1140
+ * served something this process pulled over the network — but the memo is
1141
+ * still shared, so a URL fetched once is not re-fetched per instance.
1142
+ */
1143
+ constructor(schemaOptions?: LoadSchemaOptions);
1144
+ private ajvByDialect;
1145
+ /**
1146
+ * Keyed on the in-flight *promise*, not the resolved validator. Caching the
1147
+ * result made this a check-then-act race: `fill` walks files through a worker
1148
+ * pool, so every worker missed the cache while the first `loadSchema` was
1149
+ * still pending and they all then compiled the same schema into the one
1150
+ * shared per-dialect Ajv. Ajv registers a schema's `$id` on the first compile
1151
+ * and rejects the second with "schema with key or id ... already exists",
1152
+ * which took down any multi-file run against an $id-bearing schema. Storing
1153
+ * the promise before the first await lets the losers await the one compile.
1154
+ */
1155
+ private cache;
1156
+ private ajvFor;
1157
+ /**
1158
+ * Synchronous by design: the `cache.set` has to happen in the same tick as
1159
+ * the miss, or a second caller can slip in before the entry exists.
1160
+ */
1161
+ private compile;
1162
+ private compileUncached;
1163
+ /**
1164
+ * Validate `data` against every schema in `refs`. Returns all violations,
1165
+ * each tagged with the schema that produced it and a source line via
1166
+ * `lineFor`.
1167
+ *
1168
+ * `colFor` is optional and additive: this signature is public, so a fourth
1169
+ * *required* parameter — or a widened third one — would be a consumer break.
1170
+ * Callers with an extractor that supplies no column pass nothing and get the
1171
+ * previous behavior exactly.
1172
+ */
1173
+ validate(data: Record<string, unknown>, refs: string[], lineFor: (pointer: string) => number | undefined, colFor?: (pointer: string) => number | undefined): Promise<FieldError[]>;
1174
+ }
1175
+
1176
+ /**
1177
+ * Applied when nothing else resolves. Seven-Action is safe to include here
1178
+ * because it constrains `action` — a key documents don't otherwise carry — and
1179
+ * does not require it, so adding it fails nothing that passed before.
1180
+ * Diataxis is deliberately absent: it both requires and constrains `type`, so
1181
+ * defaulting it would fail every repo not already on Diataxis.
1182
+ */
1183
+ declare const DEFAULT_SCHEMAS: readonly string[];
1184
+ /**
1185
+ * The reference a `schemas:` entry loads, in either form.
1186
+ *
1187
+ * The ref *string* is what `resolveSchemaSet` returns and therefore what every
1188
+ * report names, what every baseline fingerprint is taken over, and what keys
1189
+ * `Validator`'s compile cache. Widening those to carry a mapping would have
1190
+ * changed all three; the `{source, integrity}` sidecar travels separately, in
1191
+ * the pin map below.
1192
+ */
1193
+ declare function schemaEntryRef(entry: SchemaEntry): string;
1194
+ /**
1195
+ * The ref → pin map for a config, for `loadSchema` to consult.
1196
+ *
1197
+ * Only entries that actually carry `source` or `integrity` are recorded, so a
1198
+ * config written entirely in the string form produces an empty map and nothing
1199
+ * about how it loads changes.
1200
+ *
1201
+ * Keyed on the ref exactly as `resolveSchemaSet` will hand it to `loadSchema`,
1202
+ * which means this must be built from the **rebased** config — the same
1203
+ * absolute spelling on both sides, or the pin silently fails to apply.
1204
+ */
1205
+ declare function collectSchemaPins(config: DocmetaConfig | null | undefined): Map<string, SchemaPin>;
1206
+ /**
1207
+ * Re-point a config's **local file** schema refs at the config's own directory.
1208
+ *
1209
+ * `schemas: ["./house.schema.json"]` means the file next to the config; that is
1210
+ * what the person editing the config can see. But `loadSchema` reads a file ref
1211
+ * relative to the process's working directory, so once the config lives
1212
+ * somewhere other than where the command was invoked — via `-c ../x.yaml`, or
1213
+ * via discovery finding an ancestor — the same ref points at nothing.
1214
+ *
1215
+ * Only refs the *config* supplied are rebased. A document's own `$schema` and a
1216
+ * `--schema` on the command line were both written by someone standing in the
1217
+ * working directory, so they keep resolving from there. Built-in ids and URLs
1218
+ * have no base to speak of and pass through untouched.
1219
+ *
1220
+ * When the config's directory *is* the working directory — every setup that
1221
+ * works today — the config object is returned unchanged, so nothing about an
1222
+ * existing run moves, right down to the ref strings that appear in reports.
1223
+ * The rebased form is absolute rather than relative on purpose: relative would
1224
+ * only be correct while `process.cwd()` matched `cwd`, which is true of the CLI
1225
+ * but not of `runValidate` called as a library.
1226
+ */
1227
+ declare function rebaseConfigSchemaRefs(config: DocmetaConfig, configDir: string, cwd: string): DocmetaConfig;
1228
+ interface ResolveParams {
1229
+ /** File path (relative is fine) used for override glob matching. */
1230
+ filePath: string;
1231
+ /** `$schema` value pulled from the file's metadata. */
1232
+ fileSchema?: unknown;
1233
+ /** Repeatable `--schema` values; non-empty means override. */
1234
+ cliSchemas?: string[];
1235
+ /** Loaded config, if any. */
1236
+ config?: DocmetaConfig | null;
1237
+ /**
1238
+ * Directory a **relative document-supplied** file ref is measured from — the
1239
+ * run's `cwd`, matching `LoadSchemaOptions.fileBase`. Only the containment
1240
+ * check below reads it; the ref string itself is never rewritten.
1241
+ */
1242
+ fileBase?: string;
1243
+ /**
1244
+ * The repository a document-supplied local path may not escape. Supplied by
1245
+ * the command cores via `schemaTrustRoot`.
1246
+ *
1247
+ * **Omitting it skips containment.** The resolver is synchronous and pure,
1248
+ * and finding a git root is a filesystem walk — so the root is settled once
1249
+ * per run by the caller rather than rediscovered per file. `runValidate` and
1250
+ * `runFill` both pass it, and `test/commands.test.ts` proves they do end to
1251
+ * end; a library caller that resolves refs itself opts in the same way.
1252
+ */
1253
+ trustRoot?: SchemaTrustRoot;
1254
+ /**
1255
+ * Diagnostics for the user. Used by `documentRefs: none`, which must say
1256
+ * which document's `$schema` it dropped — discarding input in silence is the
1257
+ * failure mode this key exists to remove.
1258
+ */
1259
+ onNotice?: (message: string) => void;
1260
+ }
1261
+ declare function resolveSchemaSet(params: ResolveParams): string[];
1262
+
1263
+ /** What a well-formed pin looks like, for error messages. */
1264
+ declare const INTEGRITY_SHAPE = "sha256-<64 hex characters>";
1265
+ /**
1266
+ * The pin for a byte sequence.
1267
+ *
1268
+ * Hashes the **bytes**, never a string: decoding to UTF-8 and re-encoding is
1269
+ * lossy for a payload that is not valid UTF-8, which would make the pin wrong
1270
+ * in exactly the case an integrity check exists to catch.
1271
+ */
1272
+ declare function integrityOf(bytes: Uint8Array): string;
1273
+ /** Whether `value` is a pin this version can verify. */
1274
+ declare function isIntegrity(value: string): boolean;
1275
+
1276
+ /**
1277
+ * Where the cache lives, relative to the project root.
1278
+ *
1279
+ * `.manni/` is already ignored wholesale, and `fill` writes its proposal
1280
+ * cache to `.manni/meta/cache` — a different directory, so the two never collide.
1281
+ */
1282
+ declare const SCHEMA_CACHE_DIR = ".manni/meta/schema-cache";
1283
+ /** The only entry format this version understands. */
1284
+ declare const SCHEMA_CACHE_VERSION = 1;
1285
+ /** How long a cached schema is served before it is re-fetched. */
1286
+ declare const DEFAULT_TTL_HOURS = 24;
1287
+ /** The cache directory for a project rooted at `root`. */
1288
+ declare function schemaCacheDir(root: string): string;
1289
+ /** What one cache file holds. */
1290
+ interface SchemaCacheEntry {
1291
+ version: number;
1292
+ /** The URL this entry was fetched from; re-checked on read. */
1293
+ url: string;
1294
+ /**
1295
+ * When it was fetched, ISO-8601. **Diagnostic only** — freshness is measured
1296
+ * on the file's mtime, which a restored cache or a clock change cannot make
1297
+ * disagree with the filesystem the way an embedded timestamp can.
1298
+ */
1299
+ fetchedAt: string;
1300
+ schema: Record<string, unknown>;
1301
+ }
1302
+ interface ReadOptions {
1303
+ /**
1304
+ * Serve an entry regardless of age. What `--offline` needs: there is no
1305
+ * re-fetch available, so a stale copy beats failing the run outright.
1306
+ */
1307
+ ignoreTtl?: boolean;
1308
+ }
1309
+ declare class SchemaCache {
1310
+ private readonly dir;
1311
+ private readonly ttlHours;
1312
+ constructor(dir: string, ttlHours?: number);
1313
+ /** A TTL of 0 disables the cache in both directions. */
1314
+ get enabled(): boolean;
1315
+ /**
1316
+ * The file an entry lives in.
1317
+ *
1318
+ * Keyed on a hex digest of the URL, never on the URL itself: a URL carries
1319
+ * `/`, `..`, `:`, and a query string, so `join(dir, url + ".json")` lets the
1320
+ * *server's* address decide where the write lands. A digest cannot escape the
1321
+ * directory.
1322
+ */
1323
+ entryPath(url: string): string;
1324
+ /**
1325
+ * The cached schema for `url`, or null.
1326
+ *
1327
+ * Every malformation — an unreadable file, unparseable JSON, an unknown
1328
+ * version, an envelope naming a different URL, a payload that is not an
1329
+ * object — degrades to a **miss**. A cache is an optimization, and a corrupt
1330
+ * entry must cost one fetch, never a failed run that no `docmeta` command
1331
+ * explains how to fix.
1332
+ */
1333
+ read(url: string, options?: ReadOptions): Promise<Record<string, unknown> | null>;
1334
+ /**
1335
+ * Record a freshly fetched schema.
1336
+ *
1337
+ * A failure to write is swallowed. A read-only checkout, a full disk, or a
1338
+ * sandbox with no write access must cost the *next* run one fetch, not this
1339
+ * run its result.
1340
+ *
1341
+ * Returns whether the entry actually landed on disk, which is a different
1342
+ * question from whether the run should continue.
1343
+ */
1344
+ write(url: string, schema: Record<string, unknown>): Promise<boolean>;
1345
+ }
1346
+
1347
+ interface SarifOptions {
1348
+ /** The run's path frame. Without one, `file` labels are emitted as they are. */
1349
+ frame?: FingerprintContext;
1350
+ /** Diagnostics for the user; the CLI writes these to stderr. */
1351
+ onNotice?: (message: string) => void;
1352
+ }
1353
+ declare function renderSarif(results: ValidationResult[], opts?: SarifOptions): string;
1354
+
1355
+ /**
1356
+ * JUnit XML — what CI systems parse for the "Tests" tab.
1357
+ *
1358
+ * There is no authoritative JUnit schema; Jenkins, GitLab, CircleCI, and Azure
1359
+ * each accept a different superset. This writer sticks to the attributes all of
1360
+ * them honor (`name`, `tests`, `failures`, `errors`, `classname`, `type`,
1361
+ * `message`) and avoids the contested ones — `time`, which would be meaningless
1362
+ * here, `system-out`, and nested suites. That is a compatibility judgement, not
1363
+ * a specification.
1364
+ *
1365
+ * **One `<testcase>` per file, one `<failure>` per violation.** So the tab reads
1366
+ * "2 tests, 1 failed" and matches `2 files checked, 1 failed`.
1367
+ * Violation-as-testcase would make the test count rise and fall with document
1368
+ * quality, which reads as a suite someone broke.
1369
+ *
1370
+ * Escaping is the one thing a hand-rolled writer gets wrong. Messages carry
1371
+ * schema-authored text — a `pattern` regex may hold `<`, `&`, and quotes — and
1372
+ * paths can hold `&`. Every attribute value goes through `xmlEscape`; nothing
1373
+ * is interpolated raw.
1374
+ */
1375
+
1376
+ interface JunitOptions {
1377
+ /**
1378
+ * The `classname` each `<testcase>` carries: which docmeta command produced
1379
+ * these findings. Defaults to `docmeta.validate`, the only producer before
1380
+ * proposal 0026 made `query --check` a second one — whose findings must not
1381
+ * ship under validate's name.
1382
+ */
1383
+ classname?: string;
1384
+ /**
1385
+ * The run's path frame, used only to canonicalize a local-file schema ref in
1386
+ * `<failure type>`.
1387
+ *
1388
+ * Without it the attribute carries the ref exactly as the run received it —
1389
+ * `./my.schema.json` from the repo root, `../my.schema.json` from a
1390
+ * subdirectory, or a machine-absolute path once config discovery has rebased
1391
+ * it. SARIF's `ruleId` is already canonical, so a consumer correlating the two
1392
+ * for one run would find them disagreeing on the same violation.
1393
+ */
1394
+ frame?: FingerprintContext;
1395
+ }
1396
+ declare function renderJunit(results: ValidationResult[], opts?: JunitOptions): string;
1397
+
1398
+ /**
1399
+ * Reporters render validation results to a string. The command layer writes
1400
+ * the result to stdout; diagnostics go to stderr separately.
1401
+ */
1402
+
1403
+ /**
1404
+ * Every value `--format` accepts, in the order help and error messages list
1405
+ * them.
1406
+ *
1407
+ * The list is stated **once**. It used to live in five unlinked places — this
1408
+ * union, a separate `Set<string>` in the CLI, the error message, the option
1409
+ * description, and the docs — and the `Set` was not tied to the union at all,
1410
+ * so widening the union alone type-checked and still rejected the new value at
1411
+ * runtime. Deriving the union from the array makes that drift impossible.
1412
+ */
1413
+ declare const REPORT_FORMATS: readonly ["pretty", "json", "github", "sarif", "junit"];
1414
+ type ReportFormat = (typeof REPORT_FORMATS)[number];
1415
+ declare function isReportFormat(value: string): value is ReportFormat;
1416
+ /**
1417
+ * The formats **every** command produces.
1418
+ *
1419
+ * `get` and `schemas` accept exactly these two, and each used to spell the pair
1420
+ * out inline in `src/cli.ts` as `format !== "pretty" && format !== "json"` with
1421
+ * a hand-written "Use pretty or json." beside it — the same stringly-typed
1422
+ * drift this module's `REPORT_FORMATS` comment describes, reproduced three more
1423
+ * times. Stated once, the guard and the message cannot disagree.
1424
+ */
1425
+ declare const COMMON_FORMATS: readonly ["pretty", "json"];
1426
+ type CommonFormat = (typeof COMMON_FORMATS)[number];
1427
+ declare function isCommonFormat(value: string): value is CommonFormat;
1428
+ /**
1429
+ * The formats `query` accepts, one six-value list with per-value gates:
1430
+ * `pretty | json | csv` render result rows unconditionally (csv is proposal
1431
+ * 0029), and the findings three — `github | sarif | junit` — are legal only
1432
+ * under `--check` (proposal 0026).
1433
+ *
1434
+ * A list of its own rather than `REPORT_FORMATS`: `validate`'s list and
1435
+ * `query`'s grow independently — `csv` lives here and not there — and one
1436
+ * shared const would make every addition to either a change to both.
1437
+ */
1438
+ declare const QUERY_FORMATS: readonly ["pretty", "json", "csv", "github", "sarif", "junit"];
1439
+ type QueryFormat = (typeof QUERY_FORMATS)[number];
1440
+ declare function isQueryFormat(value: string): value is QueryFormat;
1441
+ interface ReportOptions extends SarifOptions, JunitOptions {
1442
+ color?: boolean;
1443
+ /** In pretty output, omit passing files. */
1444
+ quiet?: boolean;
1445
+ }
1446
+
1447
+ declare function render(format: ReportFormat, results: ValidationResult[], summary: RunSummary, opts?: ReportOptions): string;
1448
+
1449
+ /**
1450
+ * Every value `fill -f` accepts, in the order help and error messages list
1451
+ * them. Derived union, one statement of the list — the same rule
1452
+ * `REPORT_FORMATS` documents at length in ./index.ts, which this file used to
1453
+ * break by spelling `"pretty" | "json"` out a second time.
1454
+ *
1455
+ * `sarif` and `junit` are deliberately absent: they describe *findings in
1456
+ * files*, and a skipped optional property is a proposal with a confidence
1457
+ * score, not a finding. See 0003 § stress test 8.
1458
+ */
1459
+ declare const FILL_FORMATS: readonly ["pretty", "json", "github"];
1460
+ type FillReportFormat = (typeof FILL_FORMATS)[number];
1461
+ declare function isFillFormat(value: string): value is FillReportFormat;
1462
+ interface FillReportOptions {
1463
+ color?: boolean;
1464
+ /**
1465
+ * In pretty output, omit files with nothing to report.
1466
+ *
1467
+ * "Nothing" is narrow on purpose — see `renderFillPretty`.
1468
+ */
1469
+ quiet?: boolean;
1470
+ }
1471
+ /**
1472
+ * GitHub Actions annotations for the work `fill` could **not** do.
1473
+ *
1474
+ * One `::error` per property the schema requires that was not filled — the same
1475
+ * set that drives `fill`'s exit code 1. Optional skips stay silent, matching
1476
+ * the exit-code rule: a skipped optional property is a normal outcome, and
1477
+ * annotating it would make every run look broken.
1478
+ *
1479
+ * No `line=`. A `FilledField` carries no location — unlike a validation error,
1480
+ * a proposal is about a property that is *missing* from the document, so there
1481
+ * is nothing to point at. GitHub anchors a file-only annotation to line 1.
1482
+ *
1483
+ * The escaping is `escapeWorkflowCommandMessage`, shared with `validate`'s
1484
+ * renderer rather than re-derived: the `%`-before-newline ordering is the part
1485
+ * that is easy to get wrong.
1486
+ */
1487
+ declare function renderFillGithub(run: FillRun): string;
1488
+ declare function renderFill(format: FillReportFormat, run: FillRun, opts?: FillReportOptions): string;
1489
+
1490
+ /**
1491
+ * Reporter for `get`.
1492
+ *
1493
+ * `render()` in ./index.ts is keyed to ValidationResult/RunSummary, so `get`
1494
+ * gets its own renderer, exactly as `fill` does. It lived inline in
1495
+ * `src/cli.ts` until `--quiet` arrived and made the question "who decides what
1496
+ * is printed?" answerable in two places at once.
1497
+ *
1498
+ * `--quiet` is a **reporter** concern, not a core one. `GetOptions` /
1499
+ * `GetFileResult` are public API, and a programmatic caller handed a silently
1500
+ * filtered array cannot tell a filtered run from an empty one — so `runGet`
1501
+ * returns every file it read, and the filtering happens here, where it only
1502
+ * affects text a person is reading.
1503
+ */
1504
+
1505
+ interface GetReportOptions {
1506
+ color?: boolean;
1507
+ /** In pretty output, omit files where every requested field is unset. */
1508
+ quiet?: boolean;
1509
+ }
1510
+ /** `(unset)` for a missing field; JSON for anything that is not a string. */
1511
+ declare function stringifyValue(value: unknown): string;
1512
+ /**
1513
+ * One `<file>: <field>=<value>` line per requested field per file.
1514
+ *
1515
+ * `quiet` hides a file only when **every** requested field is unset. A file
1516
+ * where one field resolved and another did not is still printed, `(unset)`
1517
+ * included: the flag hides files, never values, so `--quiet` can never be the
1518
+ * reason a value the user asked for went missing.
1519
+ */
1520
+ declare function renderGet(results: GetFileResult[], fields: string[], opts?: GetReportOptions): string;
1521
+
1522
+ /**
1523
+ * Reporter for `query`.
1524
+ *
1525
+ * Same split as `get`: `runQuery` returns every row, and presentation —
1526
+ * alignment, the row count, the `--check` verdict — happens here, where it
1527
+ * only affects text a person is reading. `json` output never passes through
1528
+ * this module; the CLI prints the bare row array, mirroring `get`'s bare
1529
+ * array, and the exit code (not the envelope) carries the `--check` verdict.
1530
+ */
1531
+
1532
+ interface QueryReportOptions {
1533
+ color?: boolean;
1534
+ /** `--check`: append a ✓/✗ verdict line instead of the plain count. */
1535
+ check?: boolean;
1536
+ /** `--dry-run` (or `--check`): the changes were previewed, not applied. */
1537
+ dryRun?: boolean;
1538
+ }
1539
+ /**
1540
+ * An aligned table (header + rows) and a trailing count line. The last column
1541
+ * is never padded, so no line carries trailing spaces. A metadata edit
1542
+ * renders as its per-file diff instead of a row table (0022).
1543
+ */
1544
+ declare function renderQuery(run: QueryRun, opts?: QueryReportOptions): string;
1545
+ declare function renderQueryCsv(run: Pick<QueryRun, "columns" | "rows">): string;
1546
+
1547
+ type Flavor = FrontmatterFlavor;
1548
+ /**
1549
+ * Character offsets bracketing the leading fenced block, measured against the
1550
+ * *original* content — BOM included, CRLF intact. Writing metadata back is a
1551
+ * surgical splice of `[innerStart, innerEnd)`, so everything outside that range
1552
+ * (the BOM, both fences, the whole body, the file's final-newline state) is
1553
+ * preserved byte for byte by construction rather than by careful reassembly.
1554
+ */
1555
+ interface FrontmatterLocation {
1556
+ /** Which flavor the opening fence selected. */
1557
+ flavor: Flavor;
1558
+ /** Offset of the opening fence's first char (1 when a BOM precedes it). */
1559
+ openStart: number;
1560
+ /** Offset just past the opening fence's terminator == start of inner text. */
1561
+ innerStart: number;
1562
+ /** Offset of the closing fence line's first char == end of inner text. */
1563
+ innerEnd: number;
1564
+ /** Offset just past the closing fence's terminator (or EOF). */
1565
+ closeEnd: number;
1566
+ /** Line terminator of the opening fence line — the block's EOL on re-emission. */
1567
+ eol: "\n" | "\r\n";
1568
+ /** 1-based file line of the first content line (always 2). */
1569
+ firstContentLine: number;
1570
+ }
1571
+ /**
1572
+ * Locate the leading fenced front matter block, if any. Returns null when there
1573
+ * is no opening fence *or* no matching closing fence — an unterminated fence is
1574
+ * not front matter (see the rst extractor, which relies on that distinction).
1575
+ */
1576
+ declare function locateFrontmatter(content: string): FrontmatterLocation | null;
1577
+ /**
1578
+ * The block's inner text, LF-normalized with the final terminator removed —
1579
+ * byte-identical to what the parsers have always received, which is what lets
1580
+ * `extractFrontmatter` sit on top of the locator with no behavior change.
1581
+ */
1582
+ declare function frontmatterInnerText(content: string, loc: FrontmatterLocation): string;
1583
+
1584
+ /** Core front matter extraction shared by the markdown, mdx, adoc, rst formats. */
1585
+ declare function extractFrontmatter(content: string, format: string): ExtractedMetadata;
1586
+
1587
+ /**
1588
+ * Merge `patch` into the document's leading metadata block and return the new
1589
+ * content. Pure: no IO, no mutation, and the input string itself is returned
1590
+ * when the patch is a no-op.
1591
+ */
1592
+ declare function applyFrontmatter(content: string, patch: MetadataPatch, options?: ApplyOptions): string;
1593
+
1594
+ /**
1595
+ * Write `contents` to `path`, replacing it atomically. Falls back to a direct
1596
+ * write (with a warning on stderr) if the rename keeps failing because the
1597
+ * target is locked — on Windows that is a real and recoverable situation, and
1598
+ * refusing to write at all would be worse than a non-atomic write.
1599
+ */
1600
+ declare function writeFileAtomic(path: string,
1601
+ /**
1602
+ * A `Uint8Array` writes byte-for-byte. `schemas vendor` needs that: the
1603
+ * integrity pin it records is taken over exactly what the server sent, and a
1604
+ * decode/re-encode round trip through a UTF-8 string would change the bytes
1605
+ * of a payload that is not valid UTF-8 — so the pin would be wrong the first
1606
+ * time anything checked it.
1607
+ */
1608
+ contents: string | Uint8Array): Promise<void>;
1609
+
1610
+ /**
1611
+ * Extractor registry. Maps file extensions to extractors and resolves an
1612
+ * extractor by name (for the `--as` override). Every registered extractor is
1613
+ * implemented today; the `implemented` filters below are what would keep a
1614
+ * declared-but-unwired format out of directory walks, so an unfinished format
1615
+ * can be registered without becoming "supported".
1616
+ */
1617
+
1618
+ /** Resolve an implemented extractor for a file extension (incl. dot). */
1619
+ declare function extractorForExtension(ext: string): MetadataExtractor | undefined;
1620
+ /** Extensions handled by implemented extractors (used for directory walks). */
1621
+ declare function supportedExtensions(): string[];
1622
+
1623
+ export { type ApplyOptions, type BaselineSummary, COMMON_FORMATS, type CheckConfig, type CommonFormat, type ConfigNotice, DEFAULT_SCHEMAS, DEFAULT_TTL_HOURS, DEFAULT_VENDOR_DIR, type DocmetaConfig, DocmetaError, type DocumentRefTrust, type ExtractOptions, type ExtractedMetadata, FILL_FORMATS, type FetchedSchema, type FieldError, type FillConfig, type FillFileResult, type FillOptions, type FillReportFormat, type FillReportOptions, type FillRun, type FillSummary, type FilledField, type FingerprintContext, type FrontmatterFlavor, type FrontmatterLocation, type GetFileResult, type GetOptions, type GetReportOptions, INTEGRITY_SHAPE, type JunitOptions, type LoadSchemaOptions, type LoadedConfig, type MetadataExtractor, type MetadataPatch, QUERY_FORMATS, type QueryChange, type QueryFormat, type QueryOptions, type QueryReportOptions, type QueryRun, REPORT_FORMATS, type ReadOptions, type ReportFormat, type ReportOptions, type RunConfig, type RunConfigOptions, type RunSummary, SCHEMA_CACHE_DIR, SCHEMA_CACHE_VERSION, type SarifOptions, SchemaCache, type SchemaCacheConfig, type SchemaCacheEntry, type SchemaEntry, type SchemaPin, type SchemaRefEntry, type SchemaTrustConfig, type SkipReason, type ValidateOptions, type ValidateRun, type ValidationResult, Validator, type VendorOptions, type VendorResult, applyFrontmatter, classifyRef, collectSchemaPins, extractFrontmatter, extractorForExtension, fetchSchemaBytes, frontmatterInnerText, getSchemasInfo, integrityOf, isCommonFormat, isFillFormat, isIntegrity, isQueryFormat, isReportFormat, listBuiltins, loadConfig, loadSchema, locateFrontmatter, parseConfig, rebaseConfigSchemaRefs, render, renderFill, renderFillGithub, renderGet, renderJunit, renderQuery, renderQueryCsv, renderSarif, resolveRunConfig, resolveSchemaSet, runFill, runGet, runQuery, runValidate, runVendorSchema, schemaCacheDir, schemaEntryRef, schemaLoadOptions, stringifyValue, supportedExtensions, vendorFileName, writeFileAtomic };