@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.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/checks.d.ts +733 -0
- package/dist/checks.js +1867 -0
- package/dist/index.d.ts +589 -0
- package/dist/index.js +231 -0
- package/dist/stores.d.ts +188 -0
- package/dist/stores.js +287 -0
- package/dist/types-cYfcp6_8.d.ts +282 -0
- package/package.json +70 -0
package/dist/checks.d.ts
ADDED
|
@@ -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 };
|