@bendyline/gezel-sdk 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,733 @@
1
+ import { G as GateScriptResult } from './types-cYfcp6_8.js';
2
+
3
+ /**
4
+ * ─ Shared deliverable checks ─────────────────────────────────────────
5
+ *
6
+ * Pure, dependency-free predicates over file content and file listings.
7
+ * The ONE source of truth consumed by three surfaces that must agree:
8
+ *
9
+ * 1. the gate engine's declarative checks (service/tasks/gate-eval.ts)
10
+ * 2. the standard gate-script library (packages/script-stdlib, via the
11
+ * bundled `@bendyline/gezel-sdk/checks` re-export)
12
+ * 3. the eval harness's success sniffs (evals/src)
13
+ *
14
+ * Keep this directory zod-free and Node-API-free: it is bundled into the
15
+ * sandbox SDK (`noExternal`), and its failure prose is shown verbatim to
16
+ * users and models.
17
+ */
18
+ /** Read-only view of a workspace the file checks evaluate against. */
19
+ interface WorkspaceLike {
20
+ /** File content (relative path), or null if absent. */
21
+ read(file: string): Promise<string | null>;
22
+ /** Relative paths of all files (for count/scan checks). */
23
+ list(): Promise<string[]>;
24
+ /**
25
+ * Raw bytes (relative path), or null if absent. OPTIONAL: only the
26
+ * surfaces that can serve bytes implement it, and only the checks that
27
+ * genuinely need bytes (image-signature validation) call it. Text
28
+ * checks must keep using `read` — decoding binary through `read`
29
+ * is lossy, which is precisely why an extension-only image count was
30
+ * gameable with text stubs. A check that requires bytes must degrade
31
+ * explicitly when this is absent rather than silently passing.
32
+ */
33
+ readBytes?(file: string): Promise<Uint8Array | null>;
34
+ }
35
+ interface CheckResult {
36
+ ok: boolean;
37
+ /**
38
+ * One human-readable line. On failure: the concrete gap to fix (this
39
+ * exact prose lands in gate-rejection messages). On success: a brief
40
+ * diagnostic ("index.html is 4312 bytes").
41
+ */
42
+ detail: string;
43
+ }
44
+
45
+ /**
46
+ * HTML deliverable checks: truncation detection, inline-script
47
+ * extraction, V8 syntax validation, and the two content sniffs the
48
+ * craftbook runtime uses (`html-complete`, `html-game`).
49
+ *
50
+ * Ported from evals/src/html-validation.ts and the service's
51
+ * chat/step-sniff.ts so all three consumers share one implementation —
52
+ * including the wild-caught failure modes documented inline.
53
+ */
54
+ /**
55
+ * Minimum inline JS bytes for an "interactive game" page to count as
56
+ * non-skeleton. matrix calibration: a tight tic-tac-toe game
57
+ * (state, win-detect, click handler, reset) fits cleanly in ~2.5 KB; 4 KB
58
+ * rejected real working games; 2 KB rejects skeletons while letting
59
+ * tight implementations through.
60
+ */
61
+ declare const MIN_INLINE_JS_BYTES = 2048;
62
+ /**
63
+ * Count `<script>` openers vs `</script>` closers. When closers <
64
+ * openers the document was truncated mid-script and inline-JS
65
+ * extraction silently dropped a real body.
66
+ */
67
+ declare function detectUnclosedScript(html: string): {
68
+ opens: number;
69
+ closes: number;
70
+ unclosed: boolean;
71
+ };
72
+ interface InlineScript {
73
+ /** The raw inline JS body (between `<script>` open and close). */
74
+ body: string;
75
+ /** Attribute string after the `<script` tag name (e.g. `type="module"`). */
76
+ attrs: string;
77
+ }
78
+ /**
79
+ * Every inline `<script>` body in document order. External scripts
80
+ * (`src=`) and non-JS types (JSON-LD etc.) are skipped.
81
+ */
82
+ declare function extractInlineScripts(html: string): InlineScript[];
83
+ interface ScriptValidation {
84
+ /** Sum of `body.length` across all inline non-empty scripts. */
85
+ totalBytes: number;
86
+ /** True iff every script body parses without SyntaxError. */
87
+ allParse: boolean;
88
+ /** Per-script parse status. */
89
+ perScript: Array<{
90
+ bytes: number;
91
+ parses: boolean;
92
+ error?: string;
93
+ }>;
94
+ /** First parse error encountered, for the failure line. */
95
+ firstError?: string;
96
+ }
97
+ /**
98
+ * Try-parse each script body via `new Function(body)` — V8's parser.
99
+ * `type="module"` scripts skip the parse (top-level `import` fails under
100
+ * the function-body parser) but still count toward size; a genuinely
101
+ * broken module fails at the runtime-render layer instead.
102
+ */
103
+ declare function validateScriptSyntax(scripts: ReadonlyArray<InlineScript>): ScriptValidation;
104
+ /**
105
+ * Conservative sniff for TypeScript-only constructs inside a script that
106
+ * already FAILED to parse as JavaScript. Only patterns that are never
107
+ * valid JS: postfix non-null assertions, `as` casts before a delimiter,
108
+ * parameter/property type annotations with a following identifier-ish
109
+ * type, and `interface`/`enum` declarations. Returns a short description
110
+ * of the first construct found (with an excerpt), or null.
111
+ */
112
+ declare function detectTypeScriptOnlySyntax(body: string): string | null;
113
+ /** Total trimmed bytes of inline `<script>` bodies. */
114
+ declare function inlineJsBytes(html: string): number;
115
+ /**
116
+ * Generic "this HTML file isn't truncated": balanced `<script>` tags
117
+ * (the truncation failure mode is an open `<script>` with no closer)
118
+ * AND a closing `</body>` or `</html>`.
119
+ */
120
+ declare function htmlCompleteSniff(html: string): boolean;
121
+ /**
122
+ * "Plausibly a real browser game": a game *surface*, at least one CLOSED
123
+ * script, and non-trivial inline JS (default floor 400 bytes —
124
+ * `advanceWhen.minBytes` guards total size separately).
125
+ *
126
+ * A "surface" is a canvas/SVG render target OR a real animation/tick loop
127
+ * (`requestAnimationFrame`, `setInterval`/`setTimeout`, or a conventional
128
+ * frame function). The loop branch matters: plenty of legitimate games —
129
+ * board games, multi-screen arcade games, anything that animates by
130
+ * mutating the DOM each frame — never touch `<canvas>`. Requiring a
131
+ * canvas held 2 of 3 genuinely-passing DOM arcade games at the build gate
132
+ * gate-liveness run, while the eval grader (which
133
+ * treats render-surface as one optional signal of six) passed all three.
134
+ * The gate must agree with the grader on what "is a game" means — canvas
135
+ * is one way to be a game, not the definition. The closed-script +
136
+ * substantial-JS floors still exclude static pages and truncated stubs.
137
+ */
138
+ declare function htmlGameSniff(html: string, minJsBytes?: number): boolean;
139
+
140
+ /**
141
+ * File-fact checks: sizes, counts, CSS volume, content patterns. Ported
142
+ * verbatim from service/src/tasks/gate-eval.ts so the failure prose
143
+ * users see is byte-identical wherever a check runs.
144
+ */
145
+ declare function fileMinBytes(ws: WorkspaceLike, file: string, bytes: number, trim?: boolean): Promise<CheckResult>;
146
+ declare function fileMinLines(ws: WorkspaceLike, file: string, minLines: number): Promise<CheckResult>;
147
+ declare function totalMinBytes(ws: WorkspaceLike, files: string[], bytes: number): Promise<CheckResult>;
148
+ declare function fileCountByExt(ws: WorkspaceLike, ext: string[], min: number, dir?: string, opts?: {
149
+ verifyImageBytes?: boolean;
150
+ }): Promise<CheckResult & {
151
+ matched: string[];
152
+ }>;
153
+ /**
154
+ * `<style>` blocks + inline `style=""` attributes + linked local
155
+ * stylesheets in `file` total ≥ `bytes`. Style attributes count because a
156
+ * fully-inline-styled page is real CSS work — ignoring them false-failed
157
+ * valid pages that never opened a `<style>` block.
158
+ */
159
+ declare function cssMinBytes(ws: WorkspaceLike, bytes: number, file?: string): Promise<CheckResult>;
160
+ declare function containsPattern(ws: WorkspaceLike, file: string, pattern: string, flags?: string, label?: string): Promise<CheckResult>;
161
+ declare function notContainsPattern(ws: WorkspaceLike, file: string, pattern: string, flags?: string, label?: string): Promise<CheckResult>;
162
+ /**
163
+ * Grep-returns-results across the workspace: at least `minMatches` files
164
+ * (optionally under `dir`, optionally filtered to `ext`) whose content
165
+ * matches `pattern`.
166
+ */
167
+ declare function grepMatches(ws: WorkspaceLike, pattern: string, opts?: {
168
+ dir?: string;
169
+ ext?: string[];
170
+ flags?: string;
171
+ minMatches?: number;
172
+ }): Promise<CheckResult & {
173
+ matched: string[];
174
+ }>;
175
+
176
+ /**
177
+ * Reference-resolution checks: do the things a document points at
178
+ * actually exist? Ported from the petShop eval sniff
179
+ * (evals/src/success-check.ts) — its "working image link" rule caught
180
+ * the most common broken-deliverable mode: assets generated but linked
181
+ * from the wrong path.
182
+ */
183
+ declare const IMG_EXT: RegExp;
184
+ /**
185
+ * Resolve a relative path against a base file's directory using POSIX
186
+ * semantics (`..` walks up, `.` is no-op, leading `/` is project root).
187
+ * Returns null for external/anchor/data refs or paths escaping the root.
188
+ */
189
+ declare function resolveRelative(basePath: string, srcRaw: string): string | null;
190
+ /** Every `<img src="…">` value in document order. */
191
+ declare function findImageRefs(html: string): string[];
192
+ interface ImageRefsReport {
193
+ ok: boolean;
194
+ detail: string;
195
+ /** Refs that point at image files which do NOT exist in the project. */
196
+ broken: string[];
197
+ /** Count of refs that resolve to real files. */
198
+ working: number;
199
+ /** Total image-shaped refs found. */
200
+ total: number;
201
+ }
202
+ /**
203
+ * Check that `<img>` refs in `html` resolve to real files.
204
+ * `requireAll: false` (default) = at least one working image ref;
205
+ * `true` = every image-shaped ref must resolve.
206
+ */
207
+ declare function imageRefsResolve(html: string, htmlPath: string, projectFiles: readonly string[], requireAll?: boolean): ImageRefsReport;
208
+
209
+ /**
210
+ * Static-scan an ESM/JS/TS file for two high-confidence import errors that
211
+ * break the module at LOAD time (so nothing runs) yet slip past the
212
+ * inline-`<script>` JS-parse gate — which skips `type="module"` and never
213
+ * sees a standalone `.mjs`/`.ts`:
214
+ *
215
+ * 1. A named import pulled from the WRONG `node:` builtin (the canonical
216
+ * case: `import { dirname } from 'node:url'` — `dirname` is `node:path`).
217
+ * Throws `SyntaxError: … does not provide an export named …`.
218
+ * 2. `require(...)` inside a `.mjs` file — `require` is not defined in ESM
219
+ * and throws at runtime. (Restricted to `.mjs`, where ESM is
220
+ * unambiguous; a bare `.js`/`.ts` may legitimately be CommonJS.)
221
+ *
222
+ * Returns the FIRST issue with a prescriptive fix (the "name one gap"
223
+ * discipline). A file with no `node:` named imports — and no require() in a
224
+ * `.mjs` — passes; there is nothing this check can be confident about.
225
+ */
226
+ declare function esmImports(content: string, file?: string): CheckResult;
227
+ /**
228
+ * Standalone-file parse floor for `.js`/`.mjs` sources, without the
229
+ * TypeScript compiler (usable from the sandboxed stdlib). Import/export
230
+ * statements are textually stripped (top-level module syntax can't be
231
+ * function-parsed), then the remainder must parse via `new Function` —
232
+ * catching the dominant truncation / unbalanced-brace failure class the
233
+ * way `validateScriptSyntax` does for inline HTML scripts. TypeScript
234
+ * sources need the service-side `sourceParses` gate check instead.
235
+ */
236
+ declare function standaloneJsParses(content: string, file?: string): CheckResult;
237
+
238
+ /**
239
+ * Text/structure checks: distinct-match counting, ordered Markdown
240
+ * sections, JSON validity. Ported from evals/src/success-check.ts
241
+ * (incident-postmortem's citation + section rules).
242
+ */
243
+
244
+ type JsonScalar = string | number | boolean | null;
245
+ interface JsonPathEqualsResult extends CheckResult {
246
+ actual?: unknown;
247
+ }
248
+ /**
249
+ * Count DISTINCT regex matches in `text` (distinct by capture group 1
250
+ * when present, else by the whole match, case-insensitive). A file cited
251
+ * six times counts once.
252
+ */
253
+ declare function countDistinctMatches(text: string, pattern: RegExp): number;
254
+ /**
255
+ * Verify `text` contains each header in `headers` IN ORDER (later
256
+ * headers must appear AFTER earlier ones). Headers match `^#+\s+<h>$`
257
+ * (case-insensitive, multi-line) — `#`/`##`/`###` all qualify.
258
+ */
259
+ declare function requireOrderedSections(text: string, headers: readonly string[]): {
260
+ ok: true;
261
+ } | {
262
+ ok: false;
263
+ missing: string;
264
+ foundIndex: number;
265
+ };
266
+ declare function jsonValid(content: string): {
267
+ ok: boolean;
268
+ error?: string;
269
+ };
270
+ declare function jsonPathEquals(ws: WorkspaceLike, file: string, path: string, expected: JsonScalar, label?: string): Promise<JsonPathEqualsResult>;
271
+
272
+ /**
273
+ * Grounding + citation checks — the anti-fabrication vocabulary.
274
+ *
275
+ * Ported from the eval graders (evals/src/scenarios/decoy-research.ts) so
276
+ * the gate that fires in production is byte-identical to the one the eval
277
+ * suite proved out:
278
+ *
279
+ * - `valueGrounding` generalizes decoy-research's `checkBriefing`:
280
+ * required facts must be present, forbidden (decoy) values must be
281
+ * absent anywhere — even to contrast them.
282
+ * - `citationsResolve` is the squisq lesson as a mechanical gate: every
283
+ * source a deliverable cites must resolve to a real file (no
284
+ * fabricated paths). URLs can't be fetched offline, so they fail
285
+ * open unless an explicit corpus allowlist is supplied.
286
+ */
287
+ /**
288
+ * Collapse digit-grouping separators so "$4,217,300", "4 217 300", and
289
+ * "4217300" all compare equal. Only separators between a digit and a
290
+ * 3-digit group are touched, so list punctuation ("1, 2, 3") and prose
291
+ * spacing survive. (Ported verbatim from decoy-research.)
292
+ */
293
+ declare function normalizeDigitGroups(text: string): string;
294
+ /** A single grounded fact: at least one `required` form must appear and no
295
+ * `forbidden` (decoy) form may. Values are regex sources, matched
296
+ * case-insensitively against the (optionally digit-normalized) text. */
297
+ interface GroundingFact {
298
+ /** Stable id, surfaced in the failure message. */
299
+ id: string;
300
+ /** Short human label ("Q3 revenue"); falls back to `id`. */
301
+ label?: string;
302
+ /** Value(s) that MUST appear — the fact passes when ANY one matches. */
303
+ required: string[];
304
+ /** Value(s) that must NOT appear anywhere (the decoy twins). */
305
+ forbidden?: string[];
306
+ }
307
+ interface GroundingResult extends CheckResult {
308
+ /** Ids of facts that passed. */
309
+ signals: string[];
310
+ /** Forbidden (decoy) values that were detected, for logs/facts.json. */
311
+ decoysDetected: string[];
312
+ }
313
+ /**
314
+ * Behavioral fact-check over a deliverable's text: for each fact an
315
+ * authorized value must be present and every forbidden twin absent.
316
+ * Pure (string in, verdict out) so it drives gate scripts and the eval
317
+ * grader from one codebase. Reports the FIRST failing fact concretely
318
+ * (Law 3: name the gap, not the rule).
319
+ */
320
+ declare function valueGrounding(text: string, facts: readonly GroundingFact[], opts?: {
321
+ normalizeDigits?: boolean;
322
+ }): GroundingResult;
323
+ interface CitationsResult extends CheckResult {
324
+ /** Cited paths that resolved to a real workspace file. */
325
+ resolved: string[];
326
+ /** Cited paths/URLs that did NOT resolve. */
327
+ unresolved: string[];
328
+ /** Cited URLs (not checked offline unless a corpus allowlist is given). */
329
+ urls: string[];
330
+ }
331
+ /**
332
+ * Every source `file` cites must exist. File-path citations are resolved
333
+ * against the workspace listing (tolerant of leading `./`, `/`, and
334
+ * `workspace/`, case-insensitive). URLs cannot be fetched offline, so
335
+ * they pass unless `corpus` is supplied, in which case every cited path
336
+ * AND URL must be a member of the allowlist. The anti-fabrication gate.
337
+ */
338
+ declare function citationsResolve(ws: WorkspaceLike, file: string, opts?: {
339
+ pattern?: string;
340
+ flags?: string;
341
+ minCitations?: number;
342
+ corpus?: string[];
343
+ }): Promise<CitationsResult>;
344
+ /** Spec for {@link valuesSubsetOf}. */
345
+ interface ValuesSubsetSpec {
346
+ /**
347
+ * Regex source with ONE capture group; every match's group 1 in the
348
+ * output and in each source is a "value". Matched with `g` plus any
349
+ * extra `flags`.
350
+ */
351
+ pattern: string;
352
+ flags?: string;
353
+ /**
354
+ * Presence floor: the output must contain at least this many values
355
+ * (default 0 — a subset check alone passes an output with no values;
356
+ * pair with a shape check, or set a floor here, when values are
357
+ * mandatory).
358
+ */
359
+ minMatches?: number;
360
+ }
361
+ interface ValuesSubsetResult extends CheckResult {
362
+ /** Distinct values found in the output. */
363
+ checked: number;
364
+ /** Output values that appear in NO source (dedup, output order). */
365
+ invented: string[];
366
+ }
367
+ /**
368
+ * Value-conservation check for transform/ETL deliverables: every value the
369
+ * output carries (per `pattern`) must appear verbatim in at least one
370
+ * source text. Catches the classic integrity failure where a model
371
+ * regenerates identifiers instead of preserving them — renumbered record
372
+ * ids, invented ticket refs, made-up SKUs — which survives every
373
+ * shape/schema check because the output LOOKS right. Wild-caught
374
+ * core sweep: 7 of 8 local models failed precision ETL solely
375
+ * by renumbering source ids. Pure (strings in, verdict out) so it drives
376
+ * gate checks, gate scripts, and eval graders from one codebase.
377
+ */
378
+ declare function valuesSubsetOf(outputText: string, sourceTexts: readonly string[], spec: ValuesSubsetSpec): ValuesSubsetResult;
379
+
380
+ interface SecurityReportOptions {
381
+ /** Path to the machine-readable findings JSON. */
382
+ findings?: string;
383
+ /** Section headings the report must contain. */
384
+ requiredSections?: string[];
385
+ /** Minimum systemic themes required once findings ≥ themeThreshold. */
386
+ minThemes?: number;
387
+ /** Findings count at/above which systemic-theme synthesis is required. */
388
+ themeThreshold?: number;
389
+ }
390
+ interface SecurityReportResult extends CheckResult {
391
+ findingCount: number;
392
+ /** Cited files that don't exist in the workspace, for logs/facts. */
393
+ fabricated: string[];
394
+ }
395
+ declare function securityReport(ws: WorkspaceLike, reportFile: string, opts?: SecurityReportOptions): Promise<SecurityReportResult>;
396
+
397
+ /** ISO yyyy-mm-dd AND a real calendar date (ported from data-wrangle). */
398
+ declare function isRealIsoDate(value: string): boolean;
399
+ /**
400
+ * Built-in cell/field types, or any other string is treated as a regex
401
+ * source the value must match. Returns `detail` describing the mismatch.
402
+ */
403
+ type CellType = 'string' | 'nonempty' | 'number' | 'integer' | 'boolean' | 'date' | 'iso-date' | 'email' | (string & {});
404
+ interface ParsedTable {
405
+ headers: string[];
406
+ rows: string[][];
407
+ }
408
+ /** Parse the first GitHub-flavored Markdown table (header row, a `|---|`
409
+ * delimiter row, then contiguous body rows). Returns null if none. */
410
+ declare function parseMarkdownTable(text: string): ParsedTable | null;
411
+ interface TableShapeSpec {
412
+ /** Header names that must be present (case-insensitive). */
413
+ requiredColumns?: string[];
414
+ /** Minimum body-row count. */
415
+ minRows?: number;
416
+ /** Per-column value type (built-in CellType or a regex source). */
417
+ columnTypes?: Record<string, CellType>;
418
+ }
419
+ interface TableShapeResult extends CheckResult {
420
+ headers: string[];
421
+ rowCount: number;
422
+ }
423
+ /** Validate the first Markdown table in `text`: required header set, row
424
+ * floor, and per-column value types. */
425
+ declare function tableShape(text: string, spec: TableShapeSpec): TableShapeResult;
426
+ /**
427
+ * Minimal RFC-4180-ish CSV parser: quoted fields, embedded commas,
428
+ * escaped double-quotes (""), CRLF, and a leading UTF-8 BOM. Returns a
429
+ * grid of trimmed-on-cell cells (callers trim further as needed).
430
+ */
431
+ declare function parseCsv(text: string): string[][];
432
+ /**
433
+ * Cheap, dependency-free sniff: does `text` look like a produced DATA
434
+ * deliverable — a non-empty JSON array of records, a comma-delimited
435
+ * table with a header + at least one data row, or a Markdown table —
436
+ * rather than an empty file or the transform *script* that would
437
+ * produce it? This is the data-class analogue of `htmlCompleteSniff`:
438
+ * it answers "is this plausibly the real output", not "is every value
439
+ * correct" (that's {@link recordSchema}'s job, used when a field schema
440
+ * is known). The shared-column-shape requirement on the delimited path
441
+ * keeps a source file accidentally read as CSV (ragged, mostly
442
+ * single-column lines) from passing as data.
443
+ */
444
+ declare function dataTableSniff(text: string): boolean;
445
+ interface CsvShapeSpec {
446
+ /** Header names that must be present exactly. */
447
+ requiredColumns?: string[];
448
+ /** Complete header row, in order. When set, no extra/missing columns are allowed. */
449
+ exactColumns?: string[];
450
+ /** Minimum data-row count, excluding the header row. */
451
+ minRows?: number;
452
+ /** Reject rows whose cell count differs from the header. Defaults to true. */
453
+ consistentColumns?: boolean;
454
+ /** Per-column allowed values. Empty cells are ignored here; use exactColumns/requiredColumns for shape. */
455
+ allowedValues?: Record<string, string[]>;
456
+ }
457
+ interface CsvShapeResult extends CheckResult {
458
+ headers: string[];
459
+ rowCount: number;
460
+ }
461
+ /** Validate CSV file shape: header, row count, ragged rows, and optional picklist values. */
462
+ declare function csvShape(text: string | null, spec: CsvShapeSpec): CsvShapeResult;
463
+ interface RecordFieldSpec {
464
+ name: string;
465
+ /** Value type; omit (or 'string') for any non-empty string. */
466
+ type?: CellType;
467
+ /** Defaults to true. */
468
+ required?: boolean;
469
+ }
470
+ interface RecordSchemaSpec {
471
+ fields: RecordFieldSpec[];
472
+ /** Reject rows carrying fields not in `fields`. Defaults to false. */
473
+ allowExtraFields?: boolean;
474
+ minRows?: number;
475
+ /** Field whose values must be unique across all rows. */
476
+ uniqueBy?: string;
477
+ /** 'json' | 'csv' | 'auto' (default 'auto' — sniff by first char). */
478
+ format?: 'json' | 'csv' | 'auto';
479
+ }
480
+ interface RecordSchemaResult extends CheckResult {
481
+ rowCount: number;
482
+ }
483
+ /**
484
+ * Validate a JSON array (or CSV) of records against a declared schema.
485
+ * Checks run in a fixed order and STOP at the first failure, naming
486
+ * exactly one gap with the offending value (the data-wrangle discipline).
487
+ * `null` text means the deliverable doesn't exist yet.
488
+ */
489
+ declare function recordSchema(text: string | null, spec: RecordSchemaSpec): RecordSchemaResult;
490
+
491
+ interface WordBandResult extends CheckResult {
492
+ words: number;
493
+ }
494
+ /** Word count within `[min, max]` (either bound optional). */
495
+ declare function wordBand(text: string, opts?: {
496
+ min?: number;
497
+ max?: number;
498
+ stripMarkdown?: boolean;
499
+ }): WordBandResult;
500
+ interface ReadingLevelResult extends CheckResult {
501
+ /** Flesch-Kincaid grade level. */
502
+ grade: number;
503
+ /** Flesch reading-ease (higher = easier). */
504
+ ease: number;
505
+ words: number;
506
+ sentences: number;
507
+ }
508
+ /**
509
+ * Flesch-Kincaid grade level and Flesch reading-ease, banded by any of
510
+ * `minGrade`/`maxGrade`/`minEase`/`maxEase`. Reports the first band the
511
+ * text falls outside of.
512
+ */
513
+ declare function readingLevel(text: string, opts?: {
514
+ minGrade?: number;
515
+ maxGrade?: number;
516
+ minEase?: number;
517
+ maxEase?: number;
518
+ stripMarkdown?: boolean;
519
+ }): ReadingLevelResult;
520
+ /** A canonical term plus the spellings/numberings that should NOT appear. */
521
+ interface EntitySpec {
522
+ canonical: string;
523
+ /** Forbidden variants (drifted spellings, wrong numbers). */
524
+ variants: string[];
525
+ }
526
+ interface EntitiesResult extends CheckResult {
527
+ violations: Array<{
528
+ canonical: string;
529
+ variant: string;
530
+ }>;
531
+ }
532
+ interface UnsupportedClaimPattern {
533
+ /** Regex for a high-risk claim phrase whose wording must be source-grounded. */
534
+ pattern: string;
535
+ /** Repair guidance shown when this pattern matches unsupported prose. */
536
+ label?: string;
537
+ }
538
+ interface UnsupportedClaimViolation {
539
+ pattern: string;
540
+ label?: string;
541
+ match: string;
542
+ }
543
+ interface UnsupportedClaimsResult extends CheckResult {
544
+ violations: UnsupportedClaimViolation[];
545
+ missingSources: string[];
546
+ }
547
+ /**
548
+ * Fail if any declared `variant` of an entity appears in `text` — i.e.
549
+ * the document drifted from the canonical spelling/number somewhere.
550
+ * Case-sensitive (so "ACME" vs "Acme" is caught). Reports the first
551
+ * inconsistency.
552
+ */
553
+ declare function namedEntitiesConsistent(text: string, entities: readonly EntitySpec[]): EntitiesResult;
554
+ /**
555
+ * Fail when high-risk claim wording appears in `file` but the exact
556
+ * matched phrase is absent from the declared source files. This is a
557
+ * deterministic middle ground for factual comms gates: it catches common
558
+ * overclaim/tone drift while still allowing loaded phrases that the source
559
+ * brief explicitly authorized.
560
+ */
561
+ declare function unsupportedClaims(ws: WorkspaceLike, file: string, sourceFiles: readonly string[], patterns: readonly UnsupportedClaimPattern[], opts?: {
562
+ flags?: string;
563
+ maxViolations?: number;
564
+ }): Promise<UnsupportedClaimsResult>;
565
+
566
+ /**
567
+ * Plain-language hints derived from runtime/test output. Failure lines
568
+ * from assertion harnesses name the mismatch but not the mistake; small
569
+ * models keep patching the wrong thing until a hint names it. Generalized
570
+ * from the eval harness's perf-budget `wrapperReturnHint` (0/3 → 3/3 once
571
+ * the wrapper misread was named).
572
+ */
573
+ /**
574
+ * Detect the "returned a wrapper object where an array was expected"
575
+ * shape in assertion output lines (`… expected [...], got {...}`) and
576
+ * name it. Returns null when no line matches — a bare array with wrong
577
+ * contents is a genuinely different mistake and gets no hint.
578
+ */
579
+ declare function wrapperReturnHint(outputLines: readonly string[]): string | null;
580
+
581
+ interface MarkdownHeadingsMatchResult extends CheckResult {
582
+ outlineHeadings: string[];
583
+ documentHeadings: string[];
584
+ mismatchIndex?: number;
585
+ }
586
+ /**
587
+ * Compare a Markdown deck's H1 boundaries with a locked outline whose slides
588
+ * are authored as `## Slide N — Title` (also accepts `## N. Title`).
589
+ */
590
+ declare function markdownHeadingsMatch(ws: WorkspaceLike, file: string, outlineFile: string): Promise<MarkdownHeadingsMatchResult>;
591
+
592
+ /**
593
+ * Human-line explainers for the step sniffs. A gate verdict that says
594
+ * "index.html failed the html-game check" restates the rule; one that
595
+ * says "no render surface and no frame loop — add the game loop" names
596
+ * the model's actual gap (Law 3 of the task-completion strategy: the
597
+ * verdict must quote the failing observation, not the rule). Composed
598
+ * from the same primitives the sniffs themselves use, so the diagnosis
599
+ * can never disagree with the verdict.
600
+ */
601
+ type ExplainableSniff = 'html-complete' | 'html-game' | 'nonempty' | 'json-valid' | 'data-table';
602
+ /**
603
+ * One imperative line explaining why `content` fails the named sniff.
604
+ * Callers only invoke this AFTER the sniff returned false; for content
605
+ * that actually passes, a generic line is returned rather than lying
606
+ * about a defect.
607
+ */
608
+ declare function explainSniff(name: ExplainableSniff, content: string): string;
609
+
610
+ /**
611
+ * Pure helpers for the LLM-judge gate check (`kind: 'judge'`) —
612
+ * prompt building, verdict parsing, and the verbatim-evidence wall.
613
+ * No LLM calls, no filesystem: the service's gate evaluator supplies
614
+ * the artifact text and the one-shot executor.
615
+ *
616
+ * The evidence wall is the growth-proposals pattern (packages/service/
617
+ * src/growth/proposals.ts): a quote survives only when it matches the
618
+ * artifact exactly or as a ≥24-char normalized substring — a judge
619
+ * that fabricates its evidence loses the verdict.
620
+ */
621
+ declare const MIN_JUDGE_EVIDENCE_SUBSTRING = 24;
622
+ interface JudgeVerdict {
623
+ verdict: 'pass' | 'fail';
624
+ reasons: string[];
625
+ evidence: string[];
626
+ confidence?: 'low' | 'medium' | 'high';
627
+ }
628
+ declare function buildJudgePrompt(opts: {
629
+ rubric: string;
630
+ file: string;
631
+ artifactText: string;
632
+ sources?: Array<{
633
+ path: string;
634
+ text: string;
635
+ }>;
636
+ requireEvidence?: boolean;
637
+ }): string;
638
+ /**
639
+ * Extract and validate a JudgeVerdict from a raw model reply. Accepts
640
+ * a ```json fenced block, a bare JSON object, or JSON embedded in
641
+ * surrounding prose (first `{` to last `}`) — the keurmeester parse
642
+ * ladder. Throws when nothing validates.
643
+ */
644
+ declare function parseJudgeVerdict(raw: string): JudgeVerdict;
645
+ /**
646
+ * The verbatim wall: keep only the quotes that actually appear in the
647
+ * artifact (whitespace-normalized exact match, or a substring of the
648
+ * artifact at ≥ MIN_JUDGE_EVIDENCE_SUBSTRING chars).
649
+ */
650
+ declare function validateJudgeEvidence(verdict: JudgeVerdict, artifactText: string): {
651
+ kept: string[];
652
+ dropped: number;
653
+ };
654
+
655
+ /**
656
+ * Structural plan validation (`kind: 'planStructure'`) — the Planner
657
+ * role's mechanical floor. Validates the FIRST Markdown table in the
658
+ * text against the plan contract: `ID | Task | Owner | Depends on |
659
+ * Done when` (+ optional `Estimate`), owners on-roster, dependencies
660
+ * that resolve, contain no cycles, and (by default) point only at
661
+ * EARLIER rows, and done-states long enough to be checkable.
662
+ *
663
+ * Law-3 details: every failure names the offending row and cell
664
+ * verbatim so the rejection is the fix instruction.
665
+ */
666
+ interface PlanStructureSpec {
667
+ minRows?: number;
668
+ /** When given, every Owner must be one of these names (case-insensitive). */
669
+ ownerRoster?: readonly string[];
670
+ /** Rows may only depend on earlier rows (default true). */
671
+ requireEarlierOnly?: boolean;
672
+ /** Minimum Done-when cell length (default 12 chars). */
673
+ doneWhenMinChars?: number;
674
+ }
675
+ interface PlanRow {
676
+ id: string;
677
+ task: string;
678
+ owner: string;
679
+ dependsOn: string[];
680
+ doneWhen: string;
681
+ estimate?: string;
682
+ }
683
+ interface PlanStructureResult {
684
+ ok: boolean;
685
+ /** First failure, row+cell named (empty when ok). */
686
+ detail: string;
687
+ rows: PlanRow[];
688
+ unknownDeps: string[];
689
+ cycleIds: string[];
690
+ missingOwners: string[];
691
+ weakDoneStates: string[];
692
+ }
693
+ declare function planStructure(text: string, spec?: PlanStructureSpec): PlanStructureResult;
694
+
695
+ /**
696
+ * `@bendyline/gezel-sdk/checks` — the shared deliverable-check predicates,
697
+ * re-exported for use INSIDE sandboxed scripts.
698
+ *
699
+ * Source of truth is `@bendyline/gezel/checks` (packages/core/src/checks).
700
+ * This entry is built with `noExternal` so the bundle is self-contained:
701
+ * the script runner vendors the SDK dist into each sandbox scratch dir,
702
+ * and sandboxed scripts can only import from this package. The stdlib
703
+ * gate scripts import their checks from here — a lint test enforces it —
704
+ * which is what keeps gate verdicts identical to the gate engine's
705
+ * declarative checks and the eval harness's sniffs.
706
+ */
707
+
708
+ /**
709
+ * Convenience for gate scripts: stamp a GateResult-shaped output from a
710
+ * pass/fail + the failure lines the checks produced.
711
+ *
712
+ * const r = await fileMinBytes(ws, input.file, input.minBytes);
713
+ * gezel.output(gateResult(r.ok, r.detail));
714
+ */
715
+ declare function gateResult(ok: boolean, detail: string): GateScriptResult;
716
+
717
+ /**
718
+ * Adapt the `gezel` object to the `WorkspaceLike` interface every file
719
+ * check takes. Structural parameter (not an import of the gezel
720
+ * singleton) — this entry is bundled standalone, and importing the main
721
+ * entry's module state from here would duplicate the stdin init.
722
+ *
723
+ * const ws = workspaceFromGezel(gezel);
724
+ * const r = await fileMinBytes(ws, input.file, input.minBytes);
725
+ */
726
+ declare function workspaceFromGezel(g: {
727
+ fs: {
728
+ read(path: string): Promise<string>;
729
+ listAll(): Promise<string[]>;
730
+ };
731
+ }): WorkspaceLike;
732
+
733
+ export { type CellType, type CheckResult, type CitationsResult, type CsvShapeResult, type CsvShapeSpec, type EntitiesResult, type EntitySpec, type ExplainableSniff, GateScriptResult, type GroundingFact, type GroundingResult, IMG_EXT, type ImageRefsReport, type InlineScript, type JsonPathEqualsResult, type JsonScalar, type JudgeVerdict, MIN_INLINE_JS_BYTES, MIN_JUDGE_EVIDENCE_SUBSTRING, type MarkdownHeadingsMatchResult, type ParsedTable, type PlanRow, type PlanStructureResult, type PlanStructureSpec, type ReadingLevelResult, type RecordFieldSpec, type RecordSchemaResult, type RecordSchemaSpec, type ScriptValidation, type SecurityReportOptions, type SecurityReportResult, type TableShapeResult, type TableShapeSpec, type UnsupportedClaimPattern, type UnsupportedClaimViolation, type UnsupportedClaimsResult, type ValuesSubsetResult, type ValuesSubsetSpec, type WordBandResult, type WorkspaceLike, buildJudgePrompt, citationsResolve, containsPattern, countDistinctMatches, cssMinBytes, csvShape, dataTableSniff, detectTypeScriptOnlySyntax, detectUnclosedScript, esmImports, explainSniff, extractInlineScripts, fileCountByExt, fileMinBytes, fileMinLines, findImageRefs, gateResult, grepMatches, htmlCompleteSniff, htmlGameSniff, imageRefsResolve, inlineJsBytes, isRealIsoDate, jsonPathEquals, jsonValid, markdownHeadingsMatch, namedEntitiesConsistent, normalizeDigitGroups, notContainsPattern, parseCsv, parseJudgeVerdict, parseMarkdownTable, planStructure, readingLevel, recordSchema, requireOrderedSections, resolveRelative, securityReport, standaloneJsParses, tableShape, totalMinBytes, unsupportedClaims, validateJudgeEvidence, validateScriptSyntax, valueGrounding, valuesSubsetOf, wordBand, workspaceFromGezel, wrapperReturnHint };