bareloop 0.8.0 → 0.9.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,720 @@
1
+ /** The frozen question set for a picked class. Throws on a locked or unknown
2
+ * one: reaching here with either means admission did not refuse, which is a
3
+ * bareloop bug, and failing loudly beats interviewing for a class we cannot run.
4
+ * @param {string} verdictType */
5
+ export function questionsFor(verdictType: string): any;
6
+ /** The question numbers whose answer must be present for that class's interview
7
+ * to be finished. @param {string} verdictType @returns {number[]} */
8
+ export function requiredAnswersFor(verdictType: string): number[];
9
+ /**
10
+ * The mechanical seam between the catalogue and the schema, read BOTH ways: a
11
+ * catalogue parameter with no schema would be silently undeclarable, and a schema
12
+ * entry the catalogue does not have is a second catalogue.
13
+ * @param {Record<string, any>} [catalogue]
14
+ * @returns {{ok: boolean, missing: string[], orphan: string[]}}
15
+ */
16
+ export function schemaCoverage(catalogue?: Record<string, any>): {
17
+ ok: boolean;
18
+ missing: string[];
19
+ orphan: string[];
20
+ };
21
+ /**
22
+ * THE DECLARATION SCHEMA — the tool's input schema, and therefore the whole
23
+ * shape a model can express.
24
+ *
25
+ * One `oneOf` branch per LIVE kind, each pinning its own `kind` as a const so a
26
+ * parameter set cannot drift onto the wrong kind. A LOCKED kind gets no branch at
27
+ * all: declaring one is inexpressible here rather than rejected afterwards (see
28
+ * the header for what that costs).
29
+ *
30
+ * It enforces STRUCTURE, not LAW. The stage-name slug rule, the one-population
31
+ * law, the listing rule, F49's regex reject and the D5 guard equality are M2's,
32
+ * and they arrive as validation reds through the revise loop — a schema that
33
+ * tried to restate them would be a second validator.
34
+ *
35
+ * THROWS on a catalogue it cannot cover: a malformed catalogue is a bareloop bug,
36
+ * and failing loudly beats emitting a schema that quietly cannot say something
37
+ * the validator will then demand.
38
+ * @param {Record<string, any>} [catalogue]
39
+ */
40
+ export function declarationSchema(catalogue?: Record<string, any>): {
41
+ type: string;
42
+ properties: {
43
+ stages: {
44
+ type: string;
45
+ minItems: number;
46
+ maxItems: number;
47
+ description: string;
48
+ items: {
49
+ oneOf: {
50
+ title: string;
51
+ description: any;
52
+ type: string;
53
+ properties: {
54
+ name: {
55
+ type: string;
56
+ description: string;
57
+ };
58
+ kind: {
59
+ const: string;
60
+ };
61
+ params: {
62
+ type: string;
63
+ properties: Record<string, any>;
64
+ required: any[];
65
+ additionalProperties: boolean;
66
+ };
67
+ };
68
+ required: string[];
69
+ additionalProperties: boolean;
70
+ }[];
71
+ };
72
+ };
73
+ notes: {
74
+ type: string;
75
+ items: {
76
+ type: string;
77
+ minLength: number;
78
+ };
79
+ description: string;
80
+ };
81
+ };
82
+ required: string[];
83
+ additionalProperties: boolean;
84
+ };
85
+ /**
86
+ * The output channel. It records and acknowledges; it takes no action, which is
87
+ * why handing it to a toolless authoring call does not reopen D3.
88
+ * @param {{calls: any[]}} box
89
+ * @param {{catalogue?: Record<string, any>}} [o]
90
+ */
91
+ export function declarationTool(box: {
92
+ calls: any[];
93
+ }, { catalogue }?: {
94
+ catalogue?: Record<string, any>;
95
+ }): {
96
+ name: string;
97
+ description: string;
98
+ parameters: {
99
+ type: string;
100
+ properties: {
101
+ stages: {
102
+ type: string;
103
+ minItems: number;
104
+ maxItems: number;
105
+ description: string;
106
+ items: {
107
+ oneOf: {
108
+ title: string;
109
+ description: any;
110
+ type: string;
111
+ properties: {
112
+ name: {
113
+ type: string;
114
+ description: string;
115
+ };
116
+ kind: {
117
+ const: string;
118
+ };
119
+ params: {
120
+ type: string;
121
+ properties: Record<string, any>;
122
+ required: any[];
123
+ additionalProperties: boolean;
124
+ };
125
+ };
126
+ required: string[];
127
+ additionalProperties: boolean;
128
+ }[];
129
+ };
130
+ };
131
+ notes: {
132
+ type: string;
133
+ items: {
134
+ type: string;
135
+ minLength: number;
136
+ };
137
+ description: string;
138
+ };
139
+ };
140
+ required: string[];
141
+ additionalProperties: boolean;
142
+ };
143
+ execute: (args: any) => Promise<string>;
144
+ };
145
+ /**
146
+ * The catalogue, as the authoring call sees it — rendered FROM the catalogue, so
147
+ * the prompt and the validator judge one set of facts. `shape` and `asserts` are
148
+ * M2's own strings.
149
+ * @param {Record<string, any>} [catalogue]
150
+ */
151
+ export function catalogueBlock(catalogue?: Record<string, any>): string;
152
+ /** The three laws. Stated to the author; enforced, where checkable, by M2. */
153
+ export function lawsBlock(): string;
154
+ /**
155
+ * The whole authoring prompt, as one string.
156
+ *
157
+ * Two people fed this brief and neither of them is the model: a person who is not
158
+ * a software engineer answered an interview, and a read-only survey produced the
159
+ * facts. The prompt says so, because round 1 measured what happens when a model
160
+ * treats a lay answer as a specification.
161
+ *
162
+ * `verdictType` is REQUIRED and has no default. It is the user's own answer and
163
+ * the one thing that tells the composer what DONE is allowed to mean here; a
164
+ * defaulted class would be the prompt answering a question the user was asked.
165
+ *
166
+ * @param {{answers: Record<string|number, string>, questions?: Record<string|number, string>,
167
+ * facts: any, listingBlock: string, lang: string, verdictType: string,
168
+ * guards: {name: string, kind: string, params: Record<string, any>, fill: string[]}[],
169
+ * ownedEnvNames?: string[], mode?: 'tool'|'text', catalogue?: Record<string, any>}} o
170
+ */
171
+ export function authorPrompt({ answers, questions, facts, listingBlock, lang, verdictType, guards, ownedEnvNames, mode, catalogue }: {
172
+ answers: Record<string | number, string>;
173
+ questions?: Record<string | number, string>;
174
+ facts: any;
175
+ listingBlock: string;
176
+ lang: string;
177
+ verdictType: string;
178
+ guards: {
179
+ name: string;
180
+ kind: string;
181
+ params: Record<string, any>;
182
+ fill: string[];
183
+ }[];
184
+ ownedEnvNames?: string[];
185
+ mode?: "tool" | "text";
186
+ catalogue?: Record<string, any>;
187
+ }): string;
188
+ /**
189
+ * The seed read, as the model sees it: mechanical labels, no editorial. Per-stage
190
+ * gap capped with the trim ANNOUNCED (F28 — a bound that eats the failure names
191
+ * deletes exactly the mechanical detail that converts).
192
+ *
193
+ * SCRUBBED at the emission boundary. What this block renders is raw subprocess
194
+ * output (gap lines, an instrument stop carrying a command's stderr) and it
195
+ * becomes the next USER TURN sent to the provider — the surface most likely to
196
+ * carry a real credential, crossing the network. It goes through the ONE shared
197
+ * redactor, the same one `askDeclaration` puts the model's own text through and
198
+ * the same one `declaredclose`/`authorjob` put these very fields through; never
199
+ * a second inventory. Applied to the whole rendered block rather than one field,
200
+ * so a line added here is scrubbed by construction.
201
+ * @param {any[]} rows M1 `StageResult[]`
202
+ * @param {{gapCap?: number}} [o]
203
+ */
204
+ export function renderSeedReadBlock(rows: any[], { gapCap }?: {
205
+ gapCap?: number;
206
+ }): string;
207
+ /**
208
+ * The measured block when the declaration never reached execution. Both cases are
209
+ * machine outputs of the pipeline, never editorial prose about the model's work.
210
+ *
211
+ * SCRUBBED at the emission boundary, for the SAME reason `renderSeedReadBlock`
212
+ * is and through the SAME one redactor. The channel here is different and just
213
+ * as real: a validation red QUOTES WHAT THE MODEL DECLARED, verbatim — the
214
+ * genre-env branch echoes the expected and the declared value, the deny floor
215
+ * echoes the whole `cmd`, the listing rule echoes the path — and this block
216
+ * becomes the next USER TURN sent to the provider. A declared value shaped like
217
+ * a credential crossed unmasked before this line existed. Applied to the whole
218
+ * rendered block rather than one field, so a red added to the validator is
219
+ * scrubbed by construction rather than by remembering.
220
+ * @param {{kind: 'validation'|'artifact', reds: (Red|string)[], cap?: number}} o
221
+ */
222
+ export function renderRejectBlock({ kind, reds, cap }: {
223
+ kind: "validation" | "artifact";
224
+ reds: (Red | string)[];
225
+ cap?: number;
226
+ }): string;
227
+ /** A revise turn is EXACTLY the measured block, a blank line, and the instruction. */
228
+ export function buildReviseTurn(measuredBlock: string): string;
229
+ /**
230
+ * The structural guarantee that no other prose can enter a revise turn. Without
231
+ * it "the feedback is measurement only" is a promise; with it, it is a fact that
232
+ * fails the build the day someone appends a helpful sentence.
233
+ * @param {string} turn @param {string} measuredBlock
234
+ */
235
+ export function assertReviseTurn(turn: string, measuredBlock: string): {
236
+ ok: boolean;
237
+ bytes: number;
238
+ };
239
+ /**
240
+ * Apply the genre's environment to a declaration, mechanically.
241
+ *
242
+ * Three rules, and each one is a finding:
243
+ * - it lands on every stage that SPAWNS something (env-capable by the
244
+ * catalogue) and nowhere else — a stage that runs no process has no
245
+ * environment to set;
246
+ * - a model-authored copy of a genre-owned name is DROPPED and ANNOUNCED. M2's
247
+ * validator already reds that, so this is defence in depth — but the failure
248
+ * direction matters: silently keeping the model's guess is how round 2's arm
249
+ * B graded an unedited checkout;
250
+ * - a genre variable this patient cannot supply is a RED, not an omission. It
251
+ * moves no seed number, so no seed-verdict read can ever see it missing, and
252
+ * the artefact it would be missing from is SIGNED.
253
+ *
254
+ * The input declaration is never mutated: the model's own copy has to stay what
255
+ * the model wrote, or the next turn's validator reds it for our injection.
256
+ * @param {any} declaration
257
+ * @param {string} lang
258
+ * @param {{sourcePrefixes?: string[], catalogue?: Record<string, any>}} [o]
259
+ * @returns {{declaration: any, applied: Record<string, string>, dropped: {stage: string, name: string}[],
260
+ * missing: string[], reds: Red[]}}
261
+ */
262
+ export function applyGenreEnv(declaration: any, lang: string, { sourcePrefixes, catalogue }?: {
263
+ sourcePrefixes?: string[];
264
+ catalogue?: Record<string, any>;
265
+ }): {
266
+ declaration: any;
267
+ applied: Record<string, string>;
268
+ dropped: {
269
+ stage: string;
270
+ name: string;
271
+ }[];
272
+ missing: string[];
273
+ reds: Red[];
274
+ };
275
+ /**
276
+ * The prefixes `genreEnv` JOINS into the genre's variable, resolved against the
277
+ * real tree. Two filters, and the second one was paid for on a live patient.
278
+ *
279
+ * EXISTENCE (unchanged): a prefix that names nothing at the seed would build a
280
+ * variable pointing at nothing, and the grounded validator refuses it anyway
281
+ * (`ungroundedGenreEnv` checks every ELEMENT against the seed listing).
282
+ *
283
+ * IDENTITY (new): existence alone reads a SYMLINK and the directory behind it as
284
+ * two prefixes. On aurora, 11 entries under `src` resolve into the per-package
285
+ * `packages/<pkg>/src` trees, so the joined `MYPYPATH` named one tree twice
286
+ * under two spellings and mypy died FATALLY — exit 2, "shadows library module",
287
+ * zero output — which the close reads as a broken instrument on a perfectly
288
+ * healthy patient. The realpath-deduped control produced the identical clean
289
+ * reading as the known-good invocation.
290
+ *
291
+ * WHICH SPELLING SURVIVES is not cosmetic. The REAL path wins, because that is
292
+ * the one the checker itself resolves to; the symlink spelling is kept only when
293
+ * the real one cannot be used. And a spelling is only ever emitted when it
294
+ * SELECTS from the seed listing, because the arbiter records this value in a
295
+ * SIGNED envelope and re-validates it GROUNDED — a value the grounded validator
296
+ * cannot select is one the arbiter must never build. So a link out of the
297
+ * repository, or into a path git does not track, keeps its declared spelling
298
+ * rather than becoming an absolute path nothing can ground.
299
+ *
300
+ * An unreadable candidate (a dangling link, a race) is NOT dropped: it passed the
301
+ * existence filter against the listing, and silently losing a real prefix is the
302
+ * Result-5 hazard in the other direction.
303
+ * @param {{workdir: string, sourcePaths: any, seedFiles: string[]}} o
304
+ * @returns {string[]}
305
+ */
306
+ export function resolveSourcePrefixes({ workdir, sourcePaths, seedFiles }: {
307
+ workdir: string;
308
+ sourcePaths: any;
309
+ seedFiles: string[];
310
+ }): string[];
311
+ /**
312
+ * F6's shape: an unpriced call or round makes the TOTAL unknown, and unknown is
313
+ * reported as null — never as the sum of the priced half wearing a complete coat.
314
+ * `knownUsd` carries the priced half explicitly so nothing is hidden either way.
315
+ *
316
+ * IT IS ALSO THE RUN'S AUDIT OF WHAT WAS SAID, not only of what was spent. Every
317
+ * `add` records the call's RAW output beside its price, through the one
318
+ * scrubbed-persist helper — one list of calls, read two ways. That pairing is
319
+ * structural rather than remembered: run mslhn707 metered a $0.053 scout call
320
+ * and kept not one byte of what it returned, so the malformation that killed the
321
+ * run could not be read afterwards. A cost entry with no raw beside it is that
322
+ * run again.
323
+ */
324
+ export function makeCostBook(): {
325
+ /** @param {string} label @param {any} r a bare-agent run result @param {number} [attempt] */
326
+ add(label: string, r: any, attempt?: number): {
327
+ label: string;
328
+ costUsd: number | null;
329
+ unpricedRounds: number;
330
+ } | undefined;
331
+ /** @param {{label: string, costUsd: number|null, unpricedRounds: number}[]} calls
332
+ * @param {ReturnType<typeof scrubRaw>[]} [callRaws] */
333
+ absorb(calls: {
334
+ label: string;
335
+ costUsd: number | null;
336
+ unpricedRounds: number;
337
+ }[], callRaws?: ReturnType<typeof scrubRaw>[]): void;
338
+ /** the persisted raws, in call order — the same order and the same labels as
339
+ * `report().calls`, because both are readings of one list */
340
+ raws(): {
341
+ label: string;
342
+ attempt: number;
343
+ bytes: number;
344
+ trimmed: boolean;
345
+ text: string;
346
+ cause: string | null;
347
+ reason: string | null;
348
+ }[];
349
+ report(): {
350
+ costUsd: number | null;
351
+ knownUsd: number;
352
+ spendComplete: boolean;
353
+ nullCostCalls: number;
354
+ unpricedRounds: number;
355
+ calls: {
356
+ label: string;
357
+ costUsd: number | null;
358
+ unpricedRounds: number;
359
+ }[];
360
+ };
361
+ };
362
+ /**
363
+ * The default model boundary: one bare-agent Loop per call, with the declaration
364
+ * tool wired to END the call the moment it is used. The tool is an OUTPUT
365
+ * CHANNEL, not a step in a conversation, so the round that would acknowledge its
366
+ * result has nothing left to say.
367
+ *
368
+ * MEASURED against the real Loop with a counting provider, both arms: stop-wired
369
+ * = 1 provider round, $0.001; unwired = 2 rounds, $0.002. So the wiring halves
370
+ * the round count of every authoring and revise call — that is the number, not
371
+ * an estimate, and it is why tool mode does not cost double what text mode did.
372
+ *
373
+ * `cacheMessages` (F18) and `maxTokens` (F30) are not optional on this stack.
374
+ * @param {any} provider @param {{system?: string, maxTokens?: number}} [o]
375
+ * @returns {(messages: any[], tools: any[], opts?: any) => Promise<any>}
376
+ */
377
+ export function makeLoopGenerate(provider: any, { system, maxTokens }?: {
378
+ system?: string;
379
+ maxTokens?: number;
380
+ }): (messages: any[], tools: any[], opts?: any) => Promise<any>;
381
+ /**
382
+ * THE AUTHORING FLOW.
383
+ *
384
+ * Everything cheap happens BEFORE any token is spent: an ABSENT survey, an
385
+ * unreadable listing, an unsupported genre and a genre variable that cannot be
386
+ * built are all $0 refusals, because a paid call that was always going to be
387
+ * thrown away is a paid call nobody needed.
388
+ *
389
+ * The return is deliberately complete rather than tidy:
390
+ * - `ok` is true iff a declaration passed validation and was measured;
391
+ * - `declaration` is the LAST ACCEPTED one, genre-env injected — the exact form
392
+ * that will run and that the signature will cover;
393
+ * - `reds` is what the LAST validated iteration said. `ok:true` with a non-empty
394
+ * `reds` means the final revision was rejected and the previous close stands:
395
+ * the rejection is reported, never hidden, and never silently shipped either;
396
+ * - `iterations` carries every intermediate declaration, validation, seed read
397
+ * and attempt count, because M4 emits them and a human signs against them;
398
+ * - `raws` carries what every model call actually SAID — the scout's attempts
399
+ * and the declaration's, scrubbed and bounded through the one persist
400
+ * helper, in the cost book's own order and under its own labels. It is
401
+ * present on EVERY path including the $0 preflight refusals, because the
402
+ * path that spends nothing more is exactly the one whose evidence used to
403
+ * vanish with the process.
404
+ *
405
+ * No spine emission here (M4 wires events).
406
+ *
407
+ * @param {{workdir: string, seedRef: string, lang: string, verdictType: string,
408
+ * answers: Record<string|number, string>, questions?: Record<string|number, string>,
409
+ * scout: {state: string, facts: any, reason?: string|null, calls?: any[], raws?: any[]},
410
+ * listing?: {stop: string|null, files: string[]|null, block: string|null, meta: any}|null,
411
+ * generate: Function, seedReadFn?: Function, closeCtx?: any,
412
+ * maxRevisions?: number, structureRetries?: number,
413
+ * structuredMode?: 'tool'|'text', catalogue?: Record<string, any>}} o
414
+ */
415
+ export function authorClose({ workdir, seedRef, lang, verdictType, answers, questions, scout, listing, generate, seedReadFn, closeCtx, maxRevisions, structureRetries, structuredMode, catalogue, }: {
416
+ workdir: string;
417
+ seedRef: string;
418
+ lang: string;
419
+ verdictType: string;
420
+ answers: Record<string | number, string>;
421
+ questions?: Record<string | number, string>;
422
+ scout: {
423
+ state: string;
424
+ facts: any;
425
+ reason?: string | null;
426
+ calls?: any[];
427
+ raws?: any[];
428
+ };
429
+ listing?: {
430
+ stop: string | null;
431
+ files: string[] | null;
432
+ block: string | null;
433
+ meta: any;
434
+ } | null;
435
+ generate: Function;
436
+ seedReadFn?: Function;
437
+ closeCtx?: any;
438
+ maxRevisions?: number;
439
+ structureRetries?: number;
440
+ structuredMode?: "tool" | "text";
441
+ catalogue?: Record<string, any>;
442
+ }): Promise<any>;
443
+ /** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
444
+ /** the output channel's name. It takes no action; it carries the answer. */
445
+ export const DECLARATION_TOOL_NAME: "declare_close";
446
+ /** what the tool returns. The loop stops on delivery, so the model never reads it. */
447
+ export const DECLARATION_ACK: "declaration received";
448
+ /** addendum 5: unlimited revising launders thrash as adaptation (v1.12's rule). */
449
+ export const MAX_REVISIONS: 2;
450
+ /** a malformed EMISSION is a transport fault, bounded on its own axis */
451
+ export const MAX_STRUCTURE_RETRIES: 2;
452
+ /** per-stage gap lines carried into a revise turn, trim announced (F28) */
453
+ export const REVISE_GAP_CAP: 15;
454
+ /** validator reds carried into a revise turn, trim announced (F28) */
455
+ export const REVISE_RED_CAP: 20;
456
+ /** F18 / F30 — caching on, and the 4096 provider default cannot hold a declaration */
457
+ export const AUTHOR_MAX_TOKENS: 32000;
458
+ /** the one slot the model fills on an injected guard */
459
+ export const FILL_MARKER: "<FILL IN>";
460
+ /**
461
+ * THE FROZEN REVISE INSTRUCTION — gate-2 round 3's own text, byte for byte
462
+ * (`scratch-gate2/author.mjs:63`, the turn that PASSED both arms). It is the only
463
+ * prose a revise turn may carry, this constant is its only source, and the suite
464
+ * asserts its bytes: an edit reds the suite and forces a decision rather than
465
+ * quietly changing what every future close is corrected against.
466
+ */
467
+ export const REVISE_INSTRUCTION: string;
468
+ /**
469
+ * The structure re-ask, per mode. DELIBERATELY NOT `REVISE_INSTRUCTION`: nothing
470
+ * has been measured, there is no declaration to judge, and reusing the revise
471
+ * text would tell a model to "judge its own declaration against them" when there
472
+ * is no them.
473
+ */
474
+ export const STRUCTURE_INSTRUCTION_TOOL: string;
475
+ export const STRUCTURE_INSTRUCTION_TEXT: string;
476
+ /**
477
+ * THE INTERVIEW, KEYED BY VERDICT CLASS (hamr's ruling, PRD v1.57 §2).
478
+ *
479
+ * One question set per GENRE has no terminating shape — genres are a fat long
480
+ * tail that cannot be enumerated, and TYPES was the first specimen rather than
481
+ * the pattern. One set per verdict CLASS has exactly three. Genre understanding
482
+ * does not disappear: it moves into the COMPOSITION over the kind catalogue
483
+ * (`CLASS_STATEMENTS` below, rendered into the authoring prompt), which is the
484
+ * layer already built to hold it — the authoring call composes owned kinds and
485
+ * cannot emit anything else (D2/D3), so a genre it has never seen is a
486
+ * composition problem, not a catalogue problem.
487
+ *
488
+ * The GREEN set is questions 1–6 of the frozen TYPES set (prereg §5) BYTE FOR
489
+ * BYTE. What is gone is the seventh slot — D13's genre CONFIRM ("this looks like
490
+ * a type-fixing job, correct?") — superseded in full: the interview never asks
491
+ * about a genre again. The refusal it carried did not disappear; it MOVED to the
492
+ * composer, on the same counted `request-red` path (see `authorCloseForJob`).
493
+ * The remaining six are already genre-neutral, which is why generalising them
494
+ * required deleting a slot rather than rewording one.
495
+ */
496
+ export const GREEN_QUESTIONS: Readonly<{
497
+ 1: "What do you want done?";
498
+ 2: "Which files or folders should change?";
499
+ 3: "Is there anything that must not change?";
500
+ 4: "How do you check today whether it's working?";
501
+ 5: "What would make you say this came back worse than before?";
502
+ 6: "Is there a code repo I can look at? Where?";
503
+ }>;
504
+ /**
505
+ * The three sets. `questions: null` on a locked class is ABSENT, never `{}`:
506
+ * an empty set would read as "this class needs no questions", which is a
507
+ * different and false statement (F59's distinction, at the interview layer).
508
+ * Nothing ever reads them — a locked class refuses at ADMISSION, before its
509
+ * questions run — and the two readers below throw rather than hand back nothing.
510
+ * @type {Record<string, {locked: boolean, questions: Record<string|number, string>|null, required: readonly number[]|null}>}
511
+ */
512
+ export const QUESTION_SETS: Record<string, {
513
+ locked: boolean;
514
+ questions: Record<string | number, string> | null;
515
+ required: readonly number[] | null;
516
+ }>;
517
+ /**
518
+ * WHERE GENRE UNDERSTANDING NOW LIVES: the plain statement the composer is fed —
519
+ * *the user has this problem and declared it green/deterministic*. It is the
520
+ * user's own answer travelling into the composition call, and the composer is
521
+ * what turns it into stages over owned kinds.
522
+ *
523
+ * A locked class states NOTHING rather than something bland: a sentence here
524
+ * would be a class this build can compose for, and it cannot.
525
+ * @type {Record<string, string|null>}
526
+ */
527
+ export const CLASS_STATEMENTS: Record<string, string | null>;
528
+ export const AUTHOR_SYSTEM: string;
529
+ /**
530
+ * ONE schema per PARAMETER NAME, composed into kinds by the catalogue's own
531
+ * `required`/`optional` lists. Keyed by name rather than by kind on purpose: the
532
+ * catalogue already decides which kind takes which parameter, and a per-kind
533
+ * table would be a second place for that fact to live.
534
+ *
535
+ * What is genuinely NEW here is only the JSON TYPE of each leaf — the catalogue
536
+ * states it as prose (`shape`) for the prompt, and nothing in the tree states it
537
+ * as a schema. Everything a schema could DRIFT on — which kinds exist, which are
538
+ * locked, which parameters each takes, which values an enum admits — is read
539
+ * from M2 and M1, and {@link schemaCoverage} makes the remaining seam mechanical:
540
+ * a catalogue that grows a parameter this table does not know about fails LOUDLY
541
+ * at schema-build time rather than silently omitting it from what the model can
542
+ * say.
543
+ */
544
+ export const PARAM_SCHEMAS: Readonly<{
545
+ cmd: {
546
+ type: string;
547
+ description: string;
548
+ };
549
+ args: {
550
+ type: string;
551
+ items: {
552
+ type: string;
553
+ };
554
+ };
555
+ expectExit: {
556
+ type: string;
557
+ };
558
+ timeoutMs: {
559
+ type: string;
560
+ minimum: number;
561
+ };
562
+ env: {
563
+ type: string;
564
+ additionalProperties: {
565
+ type: string;
566
+ };
567
+ };
568
+ parser: Readonly<{
569
+ description: string;
570
+ oneOf: ({
571
+ title: string;
572
+ type: string;
573
+ properties: {
574
+ terms: {
575
+ type: string;
576
+ minItems: number;
577
+ maxItems: number;
578
+ items: {
579
+ type: string;
580
+ properties: {
581
+ lineMatch: {
582
+ type: string;
583
+ description: string;
584
+ };
585
+ capture: {
586
+ type: string;
587
+ minimum: number;
588
+ description: string;
589
+ };
590
+ sign: {
591
+ enum: number[];
592
+ description: string;
593
+ };
594
+ aggregate: {
595
+ enum: string[];
596
+ description: string;
597
+ };
598
+ region: {
599
+ oneOf: ({
600
+ const: string;
601
+ type?: undefined;
602
+ properties?: undefined;
603
+ required?: undefined;
604
+ additionalProperties?: undefined;
605
+ } | {
606
+ type: string;
607
+ properties: {
608
+ anchor: {
609
+ type: string;
610
+ };
611
+ capture: {
612
+ type: string;
613
+ minimum: number;
614
+ description: string;
615
+ };
616
+ };
617
+ required: string[];
618
+ additionalProperties: boolean;
619
+ const?: undefined;
620
+ })[];
621
+ };
622
+ };
623
+ required: string[];
624
+ additionalProperties: boolean;
625
+ };
626
+ };
627
+ lineMatch?: undefined;
628
+ capture?: undefined;
629
+ };
630
+ required: string[];
631
+ additionalProperties: boolean;
632
+ description?: undefined;
633
+ } | {
634
+ title: string;
635
+ type: string;
636
+ description: string;
637
+ properties: {
638
+ lineMatch: {
639
+ type: string;
640
+ };
641
+ capture: {
642
+ type: string;
643
+ minimum: number;
644
+ };
645
+ terms?: undefined;
646
+ };
647
+ required: string[];
648
+ additionalProperties: boolean;
649
+ })[];
650
+ }>;
651
+ scope: Readonly<{
652
+ type: "object";
653
+ description: "which population this stage counts. A path prefix, read off the seed listing.";
654
+ properties: {
655
+ includePrefixes: {
656
+ type: string;
657
+ minItems: number;
658
+ items: {
659
+ type: string;
660
+ };
661
+ };
662
+ excludePrefixes: {
663
+ type: string;
664
+ minItems: number;
665
+ items: {
666
+ type: string;
667
+ };
668
+ };
669
+ };
670
+ additionalProperties: false;
671
+ }>;
672
+ direction: {
673
+ enum: string[];
674
+ };
675
+ baseline: {
676
+ enum: (string | number)[];
677
+ description: string;
678
+ };
679
+ patterns: {
680
+ type: string;
681
+ minItems: number;
682
+ items: {
683
+ type: string;
684
+ properties: {
685
+ id: {
686
+ type: string;
687
+ };
688
+ regex: {
689
+ type: string;
690
+ };
691
+ };
692
+ required: string[];
693
+ additionalProperties: boolean;
694
+ };
695
+ };
696
+ extensions: {
697
+ type: string;
698
+ minItems: number;
699
+ items: {
700
+ type: string;
701
+ };
702
+ };
703
+ allowPrefixes: {
704
+ type: string;
705
+ minItems: number;
706
+ items: {
707
+ type: string;
708
+ };
709
+ };
710
+ requireNonEmpty: {
711
+ const: boolean;
712
+ };
713
+ }>;
714
+ export type Red = {
715
+ code: string;
716
+ path: string;
717
+ detail: string;
718
+ [k: string]: any;
719
+ };
720
+ import { scrubRaw } from './text.js';