@abaigram/abai-stub 0.0.0-stage → 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 +22 -2
- package/dist/audit.d.ts +70 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +166 -0
- package/dist/audit.js.map +1 -0
- package/dist/cells/fit.d.ts +6 -0
- package/dist/cells/fit.d.ts.map +1 -0
- package/dist/cells/fit.js +44 -0
- package/dist/cells/fit.js.map +1 -0
- package/dist/content.d.ts +17 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +71 -0
- package/dist/content.js.map +1 -0
- package/dist/endpoint.d.ts +90 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/endpoint.js +789 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/entry.d.ts +36 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +409 -0
- package/dist/entry.js.map +1 -0
- package/dist/env.d.ts +38 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +69 -0
- package/dist/env.js.map +1 -0
- package/dist/harness-binding.d.ts +223 -0
- package/dist/harness-binding.d.ts.map +1 -0
- package/dist/harness-binding.js +589 -0
- package/dist/harness-binding.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +3 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +3 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/manifest.d.ts +172 -0
- package/dist/manifest/manifest.d.ts.map +1 -0
- package/dist/manifest/manifest.js +443 -0
- package/dist/manifest/manifest.js.map +1 -0
- package/dist/manifest/render.d.ts +6 -0
- package/dist/manifest/render.d.ts.map +1 -0
- package/dist/manifest/render.js +39 -0
- package/dist/manifest/render.js.map +1 -0
- package/dist/null-harness.d.ts +32 -0
- package/dist/null-harness.d.ts.map +1 -0
- package/dist/null-harness.js +162 -0
- package/dist/null-harness.js.map +1 -0
- package/dist/program.d.ts +250 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +877 -0
- package/dist/program.js.map +1 -0
- package/dist/region.d.ts +72 -0
- package/dist/region.d.ts.map +1 -0
- package/dist/region.js +92 -0
- package/dist/region.js.map +1 -0
- package/dist/registry.d.ts +57 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +101 -0
- package/dist/registry.js.map +1 -0
- package/dist/wire/descriptor.d.ts +38 -0
- package/dist/wire/descriptor.d.ts.map +1 -0
- package/dist/wire/descriptor.js +144 -0
- package/dist/wire/descriptor.js.map +1 -0
- package/dist/wire/framing.d.ts +11 -0
- package/dist/wire/framing.d.ts.map +1 -0
- package/dist/wire/framing.js +42 -0
- package/dist/wire/framing.js.map +1 -0
- package/dist/wire/index.d.ts +4 -0
- package/dist/wire/index.d.ts.map +1 -0
- package/dist/wire/index.js +4 -0
- package/dist/wire/index.js.map +1 -0
- package/dist/wire/protocol.d.ts +255 -0
- package/dist/wire/protocol.d.ts.map +1 -0
- package/dist/wire/protocol.js +15 -0
- package/dist/wire/protocol.js.map +1 -0
- package/package.json +36 -5
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
// The abaigrammar 0.1 manifest: types, validation and helpers (spec/abaigrammar.md sections 5 and 7).
|
|
2
|
+
//
|
|
3
|
+
// The manifest exists in two forms that must agree: in code (the program's
|
|
4
|
+
// declarations, the source of truth at runtime) and in the repo
|
|
5
|
+
// (abaigram.yaml, rendered by render.ts). The validator here checks either
|
|
6
|
+
// form, so `<entry> doctor` and the self-check test apply the same rules.
|
|
7
|
+
// Fields beyond the grammar (`deviations`, `writes`, `nullable`) are
|
|
8
|
+
// extensions a partial realization needs; the manifest's `deviations` list
|
|
9
|
+
// names them.
|
|
10
|
+
export const ABAIGRAMMAR_VERSION = "0.1";
|
|
11
|
+
export const MODES = ["turns", "thread", "sidecar"];
|
|
12
|
+
/** Default `max` sizes of the sized types (grammar section 5, common rules). */
|
|
13
|
+
export const DEFAULT_STRING_MAX = 256;
|
|
14
|
+
export const DEFAULT_SIZED_MAX = 1024;
|
|
15
|
+
/** Payload bytes an event slot holds; a larger declared payload must be `large`. */
|
|
16
|
+
export const EVENT_SLOT_BYTES = 4096;
|
|
17
|
+
/** Bytes counted for a scalar field. */
|
|
18
|
+
export const SCALAR_BYTES = 8;
|
|
19
|
+
/** Events the library (the stub) emits under the reserved `abai.` prefix. */
|
|
20
|
+
export const LIBRARY_EVENTS = [
|
|
21
|
+
"abai.events.dropped",
|
|
22
|
+
"abai.knob.reset",
|
|
23
|
+
"abai.lifecycle.exited",
|
|
24
|
+
"abai.pause.blocked",
|
|
25
|
+
"abai.io.stdout",
|
|
26
|
+
"abai.io.stderr",
|
|
27
|
+
"abai.audit.failed",
|
|
28
|
+
];
|
|
29
|
+
const NAME = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/;
|
|
30
|
+
const DURATION = /^[0-9]+(ms|s|m|h)$/;
|
|
31
|
+
const VALUE_TYPES = ["bool", "int", "float", "enum", "string", "object", "list"];
|
|
32
|
+
const SIZED_TYPES = ["string", "object", "list"];
|
|
33
|
+
const POLICIES = ["auto", "confirm", "forbid"];
|
|
34
|
+
/** A valid abai name: lowercase segments joined by dots, words joined by underscores. */
|
|
35
|
+
export function isValidName(name) {
|
|
36
|
+
return typeof name === "string" && NAME.test(name);
|
|
37
|
+
}
|
|
38
|
+
export function isDuration(value) {
|
|
39
|
+
return typeof value === "string" && DURATION.test(value);
|
|
40
|
+
}
|
|
41
|
+
/** A duration string in milliseconds. */
|
|
42
|
+
export function durationMs(value) {
|
|
43
|
+
const match = /^([0-9]+)(ms|s|m|h)$/.exec(value);
|
|
44
|
+
if (!match)
|
|
45
|
+
throw new Error(`not a duration: ${value}`);
|
|
46
|
+
const n = Number(match[1]);
|
|
47
|
+
switch (match[2]) {
|
|
48
|
+
case "ms":
|
|
49
|
+
return n;
|
|
50
|
+
case "s":
|
|
51
|
+
return n * 1000;
|
|
52
|
+
case "m":
|
|
53
|
+
return n * 60_000;
|
|
54
|
+
default:
|
|
55
|
+
return n * 3_600_000;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function isPositiveInt(value) {
|
|
62
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
63
|
+
}
|
|
64
|
+
/** Normalize a field schema to its object form. */
|
|
65
|
+
export function fieldOf(field) {
|
|
66
|
+
return typeof field === "string" ? { type: field } : field;
|
|
67
|
+
}
|
|
68
|
+
/** Bytes a field counts toward an event slot: scalars 8, sized fields their `max`. */
|
|
69
|
+
export function fieldBytes(field) {
|
|
70
|
+
const f = fieldOf(field);
|
|
71
|
+
if (f.type === "string")
|
|
72
|
+
return f.max ?? DEFAULT_STRING_MAX;
|
|
73
|
+
if (f.type === "object" || f.type === "list")
|
|
74
|
+
return f.max ?? DEFAULT_SIZED_MAX;
|
|
75
|
+
return SCALAR_BYTES;
|
|
76
|
+
}
|
|
77
|
+
/** Bytes a payload counts toward an event slot (grammar section 5.1). */
|
|
78
|
+
export function payloadBytes(schema) {
|
|
79
|
+
let total = 0;
|
|
80
|
+
for (const field of Object.values(schema))
|
|
81
|
+
total += fieldBytes(field);
|
|
82
|
+
return total;
|
|
83
|
+
}
|
|
84
|
+
/** Whether a value has a declared type. `int` accepts integers only; `float` any finite number. */
|
|
85
|
+
export function matchesType(value, field) {
|
|
86
|
+
const f = fieldOf(field);
|
|
87
|
+
if (value === null)
|
|
88
|
+
return f.nullable === true;
|
|
89
|
+
switch (f.type) {
|
|
90
|
+
case "bool":
|
|
91
|
+
return typeof value === "boolean";
|
|
92
|
+
case "int":
|
|
93
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
94
|
+
case "float":
|
|
95
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
96
|
+
case "enum":
|
|
97
|
+
return typeof value === "string" && (f.enum?.includes(value) ?? false);
|
|
98
|
+
case "string":
|
|
99
|
+
return typeof value === "string";
|
|
100
|
+
case "object":
|
|
101
|
+
if (!isRecord(value))
|
|
102
|
+
return false;
|
|
103
|
+
if (f.fields) {
|
|
104
|
+
for (const [key, sub] of Object.entries(f.fields)) {
|
|
105
|
+
if (!matchesType(value[key], sub))
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
case "list":
|
|
111
|
+
if (!Array.isArray(value))
|
|
112
|
+
return false;
|
|
113
|
+
if (f.items) {
|
|
114
|
+
const items = f.items;
|
|
115
|
+
return value.every((item) => matchesType(item, items));
|
|
116
|
+
}
|
|
117
|
+
return true;
|
|
118
|
+
default:
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Encoded size of a value in bytes, as the wire would carry it. */
|
|
123
|
+
export function encodedBytes(value) {
|
|
124
|
+
return Buffer.byteLength(typeof value === "string" ? value : JSON.stringify(value), "utf8");
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Cut a string to at most `maxBytes` of UTF-8 without splitting a code
|
|
128
|
+
* point: one encode, a cut, a step back over continuation bytes, one decode.
|
|
129
|
+
*/
|
|
130
|
+
export function cutUtf8(value, maxBytes) {
|
|
131
|
+
const bytes = Buffer.from(value, "utf8");
|
|
132
|
+
if (bytes.length <= maxBytes)
|
|
133
|
+
return value;
|
|
134
|
+
let end = Math.max(0, maxBytes);
|
|
135
|
+
while (end > 0 && (bytes[end] & 0xc0) === 0x80)
|
|
136
|
+
end -= 1;
|
|
137
|
+
return bytes.toString("utf8", 0, end);
|
|
138
|
+
}
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Validation
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
class Violations {
|
|
143
|
+
list = [];
|
|
144
|
+
add(where, what) {
|
|
145
|
+
this.list.push(`${where}: ${what}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function validateSchema(v, where, schema) {
|
|
149
|
+
if (!isRecord(schema)) {
|
|
150
|
+
v.add(where, "must be an object of fields");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
154
|
+
const at = `${where}.${key}`;
|
|
155
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
156
|
+
v.add(at, "field names are identifiers");
|
|
157
|
+
if (typeof field === "string") {
|
|
158
|
+
if (!VALUE_TYPES.includes(field))
|
|
159
|
+
v.add(at, `unknown type ${JSON.stringify(field)}`);
|
|
160
|
+
else if (field === "enum")
|
|
161
|
+
v.add(at, "an enum field needs its values (use the object form)");
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (!isRecord(field) || typeof field.type !== "string" || !VALUE_TYPES.includes(field.type)) {
|
|
165
|
+
v.add(at, "must be a type name or an object with a valid type");
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (field.max !== undefined) {
|
|
169
|
+
if (!isPositiveInt(field.max))
|
|
170
|
+
v.add(at, "max must be a positive integer");
|
|
171
|
+
if (!SIZED_TYPES.includes(field.type))
|
|
172
|
+
v.add(at, "max applies to sized types only");
|
|
173
|
+
}
|
|
174
|
+
if (field.type === "enum") {
|
|
175
|
+
if (!Array.isArray(field.enum) || field.enum.length === 0 || !field.enum.every((e) => typeof e === "string")) {
|
|
176
|
+
v.add(at, "enum fields need a non-empty list of string values");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else if (field.enum !== undefined)
|
|
180
|
+
v.add(at, "enum values belong to enum fields only");
|
|
181
|
+
if (field.fields !== undefined) {
|
|
182
|
+
if (field.type !== "object")
|
|
183
|
+
v.add(at, "fields belong to object fields only");
|
|
184
|
+
else
|
|
185
|
+
validateSchema(v, at, field.fields);
|
|
186
|
+
}
|
|
187
|
+
if (field.items !== undefined) {
|
|
188
|
+
if (field.type !== "list")
|
|
189
|
+
v.add(at, "items belong to list fields only");
|
|
190
|
+
else
|
|
191
|
+
validateSchema(v, at, { item: field.items });
|
|
192
|
+
}
|
|
193
|
+
if (field.nullable !== undefined && typeof field.nullable !== "boolean")
|
|
194
|
+
v.add(at, "nullable must be a boolean");
|
|
195
|
+
if (field.doc !== undefined && typeof field.doc !== "string")
|
|
196
|
+
v.add(at, "doc must be a string");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function validateNamed(v, where, items, seen) {
|
|
200
|
+
if (!Array.isArray(items)) {
|
|
201
|
+
v.add(where, "must be a list");
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
const valid = [];
|
|
205
|
+
items.forEach((item, index) => {
|
|
206
|
+
const at = `${where}[${index}]`;
|
|
207
|
+
if (!isRecord(item)) {
|
|
208
|
+
v.add(at, "must be an object");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (!isValidName(item.name)) {
|
|
212
|
+
v.add(at, `invalid name ${JSON.stringify(item.name)}`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (seen.has(item.name))
|
|
216
|
+
v.add(`${where}.${item.name}`, "duplicate name");
|
|
217
|
+
seen.add(item.name);
|
|
218
|
+
if (item.name.startsWith("abai.") && !(where === "events" && LIBRARY_EVENTS.includes(item.name))) {
|
|
219
|
+
v.add(`${where}.${item.name}`, "the abai. prefix is reserved for the library");
|
|
220
|
+
}
|
|
221
|
+
if (typeof item.doc !== "string" || item.doc.trim() === "")
|
|
222
|
+
v.add(`${where}.${item.name}`, "doc is required");
|
|
223
|
+
valid.push(item);
|
|
224
|
+
});
|
|
225
|
+
return valid;
|
|
226
|
+
}
|
|
227
|
+
function validateCell(v, cell) {
|
|
228
|
+
const at = `cells.${cell.name}`;
|
|
229
|
+
const type = cell.type;
|
|
230
|
+
if (typeof type !== "string" || !VALUE_TYPES.includes(type)) {
|
|
231
|
+
v.add(at, `unknown type ${JSON.stringify(type)}`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (cell.access !== "read" && cell.access !== "readwrite")
|
|
235
|
+
v.add(at, "access must be read or readwrite");
|
|
236
|
+
if (cell.max !== undefined) {
|
|
237
|
+
if (!isPositiveInt(cell.max))
|
|
238
|
+
v.add(at, "max must be a positive integer");
|
|
239
|
+
if (!SIZED_TYPES.includes(type))
|
|
240
|
+
v.add(at, "max applies to sized types only");
|
|
241
|
+
}
|
|
242
|
+
if (type === "enum") {
|
|
243
|
+
if (!Array.isArray(cell.enum) || cell.enum.length === 0 || !cell.enum.every((e) => typeof e === "string")) {
|
|
244
|
+
v.add(at, "enum cells need a non-empty list of string values");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
else if (cell.enum !== undefined)
|
|
248
|
+
v.add(at, "enum values belong to enum cells only");
|
|
249
|
+
if (cell.range !== undefined) {
|
|
250
|
+
const range = cell.range;
|
|
251
|
+
if (!Array.isArray(range) ||
|
|
252
|
+
range.length !== 2 ||
|
|
253
|
+
typeof range[0] !== "number" ||
|
|
254
|
+
typeof range[1] !== "number" ||
|
|
255
|
+
range[0] > range[1]) {
|
|
256
|
+
v.add(at, "range must be [min, max]");
|
|
257
|
+
}
|
|
258
|
+
if (type !== "int" && type !== "float")
|
|
259
|
+
v.add(at, "range applies to int and float cells only");
|
|
260
|
+
}
|
|
261
|
+
if (cell.cadence !== undefined && !isPositiveInt(cell.cadence))
|
|
262
|
+
v.add(at, "cadence must be a positive integer");
|
|
263
|
+
if (cell.fields !== undefined) {
|
|
264
|
+
if (type !== "object")
|
|
265
|
+
v.add(at, "fields belong to object cells only");
|
|
266
|
+
else
|
|
267
|
+
validateSchema(v, at, cell.fields);
|
|
268
|
+
}
|
|
269
|
+
if (cell.items !== undefined) {
|
|
270
|
+
if (type !== "list")
|
|
271
|
+
v.add(at, "items belong to list cells only");
|
|
272
|
+
else
|
|
273
|
+
validateSchema(v, at, { item: cell.items });
|
|
274
|
+
}
|
|
275
|
+
if (cell.nullable !== undefined && typeof cell.nullable !== "boolean")
|
|
276
|
+
v.add(at, "nullable must be a boolean");
|
|
277
|
+
if (cell.access === "readwrite") {
|
|
278
|
+
if (cell.default === undefined)
|
|
279
|
+
v.add(at, "a readwrite cell needs a default");
|
|
280
|
+
else if (!matchesType(cell.default, cell))
|
|
281
|
+
v.add(at, "default is not of the cell's type");
|
|
282
|
+
if (cell.policy !== undefined && cell.policy !== "auto" && cell.policy !== "confirm") {
|
|
283
|
+
v.add(at, "a knob's policy is auto or confirm");
|
|
284
|
+
}
|
|
285
|
+
if (cell.timeout !== undefined) {
|
|
286
|
+
if (!isDuration(cell.timeout))
|
|
287
|
+
v.add(at, "timeout must be a duration such as 30s");
|
|
288
|
+
if (!SIZED_TYPES.includes(type))
|
|
289
|
+
v.add(at, "a delivery timeout applies to sized knobs only");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
if (cell.policy !== undefined)
|
|
294
|
+
v.add(at, "policy applies to readwrite cells only");
|
|
295
|
+
if (cell.timeout !== undefined)
|
|
296
|
+
v.add(at, "timeout applies to readwrite cells only");
|
|
297
|
+
if (cell.default !== undefined)
|
|
298
|
+
v.add(at, "default applies to readwrite cells only");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function validateEvent(v, event) {
|
|
302
|
+
const at = `events.${event.name}`;
|
|
303
|
+
validateSchema(v, `${at}.payload`, event.payload);
|
|
304
|
+
if (event.wakes !== undefined && (typeof event.wakes !== "string" || event.wakes.trim() === "")) {
|
|
305
|
+
v.add(at, "wakes must be always, never or a condition");
|
|
306
|
+
}
|
|
307
|
+
if (event.large !== undefined && typeof event.large !== "boolean")
|
|
308
|
+
v.add(at, "large must be a boolean");
|
|
309
|
+
if (isRecord(event.payload)) {
|
|
310
|
+
const bytes = payloadBytes(event.payload);
|
|
311
|
+
if (bytes > EVENT_SLOT_BYTES && event.large !== true) {
|
|
312
|
+
v.add(at, `payload counts ${bytes} bytes, over ${EVENT_SLOT_BYTES}: declare large: true`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function validateCapability(v, cap, knobs) {
|
|
317
|
+
const at = `capabilities.${cap.name}`;
|
|
318
|
+
validateSchema(v, `${at}.params`, cap.params);
|
|
319
|
+
validateSchema(v, `${at}.result`, cap.result);
|
|
320
|
+
if (cap.effect !== "read" && cap.effect !== "mutate")
|
|
321
|
+
v.add(at, "effect must be read or mutate");
|
|
322
|
+
if (cap.dispatch !== "immediate" && cap.dispatch !== "safepoint")
|
|
323
|
+
v.add(at, "dispatch must be declared");
|
|
324
|
+
if (typeof cap.policy !== "string" || !POLICIES.includes(cap.policy))
|
|
325
|
+
v.add(at, "policy must be declared");
|
|
326
|
+
if (cap.timeout !== undefined && !isDuration(cap.timeout))
|
|
327
|
+
v.add(at, "timeout must be a duration such as 30s");
|
|
328
|
+
if (cap.example !== undefined) {
|
|
329
|
+
if (!isRecord(cap.example))
|
|
330
|
+
v.add(at, "example must be an object of parameters");
|
|
331
|
+
else if (isRecord(cap.params)) {
|
|
332
|
+
for (const key of Object.keys(cap.example)) {
|
|
333
|
+
if (!(key in cap.params))
|
|
334
|
+
v.add(at, `example has an undeclared parameter ${key}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (cap.writes !== undefined) {
|
|
339
|
+
if (!isValidName(cap.writes))
|
|
340
|
+
v.add(at, "writes must name a cell");
|
|
341
|
+
else if (!knobs.has(cap.writes))
|
|
342
|
+
v.add(at, `writes names ${cap.writes}, which is not a readwrite cell`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function validateDecision(v, decision) {
|
|
346
|
+
const at = `decisions.${decision.name}`;
|
|
347
|
+
validateSchema(v, `${at}.context`, decision.context);
|
|
348
|
+
const hasOptions = decision.options !== undefined;
|
|
349
|
+
const hasAnswer = decision.answer !== undefined;
|
|
350
|
+
if (hasOptions === hasAnswer)
|
|
351
|
+
v.add(at, "declare either options or answer");
|
|
352
|
+
if (hasOptions) {
|
|
353
|
+
const options = decision.options;
|
|
354
|
+
if (!Array.isArray(options) || options.length === 0 || !options.every((o) => typeof o === "string")) {
|
|
355
|
+
v.add(at, "options must be a non-empty list of strings");
|
|
356
|
+
}
|
|
357
|
+
else if (decision.default !== "abort" && !options.includes(decision.default)) {
|
|
358
|
+
v.add(at, "default must be one of the options or abort");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (hasAnswer)
|
|
362
|
+
validateSchema(v, `${at}.answer`, decision.answer);
|
|
363
|
+
if (decision.default === undefined)
|
|
364
|
+
v.add(at, "default is required");
|
|
365
|
+
if (!isDuration(decision.timeout))
|
|
366
|
+
v.add(at, "timeout is required (a duration such as 30s)");
|
|
367
|
+
if (typeof decision.policy !== "string" || !POLICIES.includes(decision.policy))
|
|
368
|
+
v.add(at, "policy must be declared");
|
|
369
|
+
}
|
|
370
|
+
function validateTurn(v, turn) {
|
|
371
|
+
if (!isDuration(turn.timeout))
|
|
372
|
+
v.add(`turns.${turn.name}`, "timeout is required (a duration such as 30s)");
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Validate a manifest in either form. Returns the violations, each
|
|
376
|
+
* `<where>: <what>`; an empty list means the manifest validates.
|
|
377
|
+
*/
|
|
378
|
+
export function validateManifest(value) {
|
|
379
|
+
const v = new Violations();
|
|
380
|
+
if (!isRecord(value))
|
|
381
|
+
return ["manifest: must be an object"];
|
|
382
|
+
if (value.abaigrammar !== ABAIGRAMMAR_VERSION) {
|
|
383
|
+
v.add("abaigrammar", `must be ${JSON.stringify(ABAIGRAMMAR_VERSION)}`);
|
|
384
|
+
}
|
|
385
|
+
if (typeof value.name !== "string" || value.name.trim() === "")
|
|
386
|
+
v.add("name", "is required");
|
|
387
|
+
if (typeof value.entry !== "string" || value.entry.trim() === "")
|
|
388
|
+
v.add("entry", "is required");
|
|
389
|
+
const modes = value.modes;
|
|
390
|
+
if (!Array.isArray(modes) || modes.length === 0)
|
|
391
|
+
v.add("modes", "must list at least one mode");
|
|
392
|
+
else {
|
|
393
|
+
modes.forEach((mode, index) => {
|
|
394
|
+
if (!MODES.includes(mode))
|
|
395
|
+
v.add(`modes[${index}]`, `unknown mode ${JSON.stringify(mode)}`);
|
|
396
|
+
});
|
|
397
|
+
if (new Set(modes).size !== modes.length)
|
|
398
|
+
v.add("modes", "must not repeat a mode");
|
|
399
|
+
}
|
|
400
|
+
if (!isRecord(value.content) || typeof value.content.identity !== "string" || value.content.identity === "") {
|
|
401
|
+
v.add("content.identity", "is required");
|
|
402
|
+
}
|
|
403
|
+
if (!isRecord(value.audit) || typeof value.audit.path !== "string" || value.audit.path === "") {
|
|
404
|
+
v.add("audit.path", "is required");
|
|
405
|
+
}
|
|
406
|
+
if (value.lifecycle !== undefined) {
|
|
407
|
+
const lifecycle = value.lifecycle;
|
|
408
|
+
if (!isRecord(lifecycle) || !["cooperative", "os", "none"].includes(lifecycle.pause)) {
|
|
409
|
+
v.add("lifecycle.pause", "must be cooperative, os or none");
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (value.deviations !== undefined) {
|
|
413
|
+
const deviations = value.deviations;
|
|
414
|
+
if (!Array.isArray(deviations) || !deviations.every((d) => typeof d === "string" && d.trim() !== "")) {
|
|
415
|
+
v.add("deviations", "must be a list of non-empty strings");
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (value.check !== undefined && (!isRecord(value.check) || typeof value.check.run !== "string")) {
|
|
419
|
+
v.add("check.run", "is required when check is declared");
|
|
420
|
+
}
|
|
421
|
+
const cells = validateNamed(v, "cells", value.cells, new Set());
|
|
422
|
+
for (const cell of cells)
|
|
423
|
+
validateCell(v, cell);
|
|
424
|
+
const knobs = new Set(cells.filter((cell) => cell.access === "readwrite").map((cell) => cell.name));
|
|
425
|
+
for (const event of validateNamed(v, "events", value.events, new Set()))
|
|
426
|
+
validateEvent(v, event);
|
|
427
|
+
for (const cap of validateNamed(v, "capabilities", value.capabilities, new Set())) {
|
|
428
|
+
validateCapability(v, cap, knobs);
|
|
429
|
+
}
|
|
430
|
+
for (const decision of validateNamed(v, "decisions", value.decisions, new Set()))
|
|
431
|
+
validateDecision(v, decision);
|
|
432
|
+
for (const turn of validateNamed(v, "turns", value.turns, new Set()))
|
|
433
|
+
validateTurn(v, turn);
|
|
434
|
+
return v.list;
|
|
435
|
+
}
|
|
436
|
+
/** Narrow an unknown value to a Manifest; throws with the violations otherwise. */
|
|
437
|
+
export function assertManifest(value) {
|
|
438
|
+
const violations = validateManifest(value);
|
|
439
|
+
if (violations.length > 0)
|
|
440
|
+
throw new Error(`manifest does not validate:\n${violations.join("\n")}`);
|
|
441
|
+
return value;
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/manifest/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["// The abaigrammar 0.1 manifest: types, validation and helpers (spec/abaigrammar.md sections 5 and 7).\n//\n// The manifest exists in two forms that must agree: in code (the program's\n// declarations, the source of truth at runtime) and in the repo\n// (abaigram.yaml, rendered by render.ts). The validator here checks either\n// form, so `<entry> doctor` and the self-check test apply the same rules.\n// Fields beyond the grammar (`deviations`, `writes`, `nullable`) are\n// extensions a partial realization needs; the manifest's `deviations` list\n// names them.\n\nexport const ABAIGRAMMAR_VERSION = \"0.1\";\n\nexport type ScalarType = \"bool\" | \"int\" | \"float\" | \"enum\";\nexport type SizedType = \"string\" | \"object\" | \"list\";\nexport type ValueType = ScalarType | SizedType;\n\nexport type Mode = \"turns\" | \"thread\" | \"sidecar\";\nexport const MODES: readonly Mode[] = [\"turns\", \"thread\", \"sidecar\"];\n\nexport type Access = \"read\" | \"readwrite\";\nexport type Effect = \"read\" | \"mutate\";\nexport type Dispatch = \"immediate\" | \"safepoint\";\nexport type Policy = \"auto\" | \"confirm\" | \"forbid\";\nexport type Wakes = \"always\" | \"never\" | string;\n\n/** Default `max` sizes of the sized types (grammar section 5, common rules). */\nexport const DEFAULT_STRING_MAX = 256;\nexport const DEFAULT_SIZED_MAX = 1024;\n/** Payload bytes an event slot holds; a larger declared payload must be `large`. */\nexport const EVENT_SLOT_BYTES = 4096;\n/** Bytes counted for a scalar field. */\nexport const SCALAR_BYTES = 8;\n\n/**\n * A schema field: a bare type name when the defaults suffice, or an object\n * with `type` and `max` (and, beyond the grammar, `enum` values, an object's\n * `fields`, a list's `items`, `nullable` and a `doc`).\n */\nexport type FieldSchema =\n\t| ValueType\n\t| {\n\t\t\ttype: ValueType;\n\t\t\tmax?: number;\n\t\t\tenum?: string[];\n\t\t\tfields?: Schema;\n\t\t\titems?: FieldSchema;\n\t\t\tnullable?: boolean;\n\t\t\tdoc?: string;\n\t };\n\nexport type Schema = Record<string, FieldSchema>;\n\nexport interface CellDecl {\n\tname: string;\n\ttype: ValueType;\n\taccess: Access;\n\tdoc: string;\n\t/** Sized types only. */\n\tmax?: number;\n\t/** `enum` cells. */\n\tenum?: string[];\n\t/** `int` and `float` cells. */\n\trange?: [number, number];\n\t/** Required for `readwrite`. */\n\tdefault?: unknown;\n\t/** Hint in milliseconds. */\n\tcadence?: number;\n\t/** `readwrite` only; knobs are never `forbid`. */\n\tpolicy?: \"auto\" | \"confirm\";\n\t/** Sized knobs only: delivery timeout. */\n\ttimeout?: string;\n\t/** `object` cells: the fields. */\n\tfields?: Schema;\n\t/** `list` cells: the item schema. */\n\titems?: FieldSchema;\n\t/** Extension: the value may be null. */\n\tnullable?: boolean;\n}\n\nexport interface EventDecl {\n\tname: string;\n\tdoc: string;\n\tpayload: Schema;\n\twakes?: Wakes;\n\tlarge?: boolean;\n}\n\nexport interface CapabilityDecl {\n\tname: string;\n\tdoc: string;\n\tparams: Schema;\n\tresult: Schema;\n\teffect: Effect;\n\tdispatch: Dispatch;\n\ttimeout?: string;\n\tpolicy: Policy;\n\texample?: Record<string, unknown>;\n\t/** Extension: the knob this capability sets; such calls are audited as knob writes. */\n\twrites?: string;\n}\n\nexport interface DecisionDecl {\n\tname: string;\n\tdoc: string;\n\tcontext: Schema;\n\t/** Either `options` (an enum of choices) or `answer` (a schema). */\n\toptions?: string[];\n\tanswer?: Schema;\n\tdefault: unknown;\n\ttimeout: string;\n\tpolicy: Policy;\n}\n\nexport interface TurnDecl {\n\tname: string;\n\tdoc: string;\n\ttimeout: string;\n}\n\nexport interface Manifest {\n\tabaigrammar: string;\n\tname: string;\n\tentry: string;\n\tmodes: Mode[];\n\tharness?: { path: string | null };\n\tmodel?: Record<string, unknown>;\n\tcheck?: { run: string; overhead?: string };\n\tcontent: { identity: string; install?: string; use?: string; turns?: string };\n\taudit: { path: string };\n\tlifecycle?: {\n\t\tpause: \"cooperative\" | \"os\" | \"none\";\n\t\tstop?: { graceful: string; handler: string };\n\t\tpolicy?: Partial<Record<\"pause\" | \"resume\" | \"stop\" | \"restart\", Policy>>;\n\t};\n\tattention?: { budget?: { wakes_per_minute?: number; tokens_per_hour?: number } };\n\tpolicy?: { confirm_timeout?: string };\n\t/** Where this instantiation departs from the grammar, one sentence each (section 7); a program may add its own. */\n\tdeviations?: string[];\n\tcells: CellDecl[];\n\tevents: EventDecl[];\n\tcapabilities: CapabilityDecl[];\n\tdecisions: DecisionDecl[];\n\tturns: TurnDecl[];\n}\n\n/** Events the library (the stub) emits under the reserved `abai.` prefix. */\nexport const LIBRARY_EVENTS: readonly string[] = [\n\t\"abai.events.dropped\",\n\t\"abai.knob.reset\",\n\t\"abai.lifecycle.exited\",\n\t\"abai.pause.blocked\",\n\t\"abai.io.stdout\",\n\t\"abai.io.stderr\",\n\t\"abai.audit.failed\",\n];\n\nconst NAME = /^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$/;\nconst DURATION = /^[0-9]+(ms|s|m|h)$/;\nconst VALUE_TYPES: readonly string[] = [\"bool\", \"int\", \"float\", \"enum\", \"string\", \"object\", \"list\"];\nconst SIZED_TYPES: readonly string[] = [\"string\", \"object\", \"list\"];\nconst POLICIES: readonly string[] = [\"auto\", \"confirm\", \"forbid\"];\n\n/** A valid abai name: lowercase segments joined by dots, words joined by underscores. */\nexport function isValidName(name: unknown): name is string {\n\treturn typeof name === \"string\" && NAME.test(name);\n}\n\nexport function isDuration(value: unknown): value is string {\n\treturn typeof value === \"string\" && DURATION.test(value);\n}\n\n/** A duration string in milliseconds. */\nexport function durationMs(value: string): number {\n\tconst match = /^([0-9]+)(ms|s|m|h)$/.exec(value);\n\tif (!match) throw new Error(`not a duration: ${value}`);\n\tconst n = Number(match[1]);\n\tswitch (match[2]) {\n\t\tcase \"ms\":\n\t\t\treturn n;\n\t\tcase \"s\":\n\t\t\treturn n * 1000;\n\t\tcase \"m\":\n\t\t\treturn n * 60_000;\n\t\tdefault:\n\t\t\treturn n * 3_600_000;\n\t}\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isPositiveInt(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isInteger(value) && value > 0;\n}\n\n/** Normalize a field schema to its object form. */\nexport function fieldOf(field: FieldSchema): Exclude<FieldSchema, string> {\n\treturn typeof field === \"string\" ? { type: field } : field;\n}\n\n/** Bytes a field counts toward an event slot: scalars 8, sized fields their `max`. */\nexport function fieldBytes(field: FieldSchema): number {\n\tconst f = fieldOf(field);\n\tif (f.type === \"string\") return f.max ?? DEFAULT_STRING_MAX;\n\tif (f.type === \"object\" || f.type === \"list\") return f.max ?? DEFAULT_SIZED_MAX;\n\treturn SCALAR_BYTES;\n}\n\n/** Bytes a payload counts toward an event slot (grammar section 5.1). */\nexport function payloadBytes(schema: Schema): number {\n\tlet total = 0;\n\tfor (const field of Object.values(schema)) total += fieldBytes(field);\n\treturn total;\n}\n\n/** Whether a value has a declared type. `int` accepts integers only; `float` any finite number. */\nexport function matchesType(value: unknown, field: FieldSchema): boolean {\n\tconst f = fieldOf(field);\n\tif (value === null) return f.nullable === true;\n\tswitch (f.type) {\n\t\tcase \"bool\":\n\t\t\treturn typeof value === \"boolean\";\n\t\tcase \"int\":\n\t\t\treturn typeof value === \"number\" && Number.isInteger(value);\n\t\tcase \"float\":\n\t\t\treturn typeof value === \"number\" && Number.isFinite(value);\n\t\tcase \"enum\":\n\t\t\treturn typeof value === \"string\" && (f.enum?.includes(value) ?? false);\n\t\tcase \"string\":\n\t\t\treturn typeof value === \"string\";\n\t\tcase \"object\":\n\t\t\tif (!isRecord(value)) return false;\n\t\t\tif (f.fields) {\n\t\t\t\tfor (const [key, sub] of Object.entries(f.fields)) {\n\t\t\t\t\tif (!matchesType(value[key], sub)) return false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\tcase \"list\":\n\t\t\tif (!Array.isArray(value)) return false;\n\t\t\tif (f.items) {\n\t\t\t\tconst items = f.items;\n\t\t\t\treturn value.every((item) => matchesType(item, items));\n\t\t\t}\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\n/** Encoded size of a value in bytes, as the wire would carry it. */\nexport function encodedBytes(value: unknown): number {\n\treturn Buffer.byteLength(typeof value === \"string\" ? value : JSON.stringify(value), \"utf8\");\n}\n\n/**\n * Cut a string to at most `maxBytes` of UTF-8 without splitting a code\n * point: one encode, a cut, a step back over continuation bytes, one decode.\n */\nexport function cutUtf8(value: string, maxBytes: number): string {\n\tconst bytes = Buffer.from(value, \"utf8\");\n\tif (bytes.length <= maxBytes) return value;\n\tlet end = Math.max(0, maxBytes);\n\twhile (end > 0 && (bytes[end] & 0xc0) === 0x80) end -= 1;\n\treturn bytes.toString(\"utf8\", 0, end);\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nclass Violations {\n\treadonly list: string[] = [];\n\tadd(where: string, what: string): void {\n\t\tthis.list.push(`${where}: ${what}`);\n\t}\n}\n\nfunction validateSchema(v: Violations, where: string, schema: unknown): void {\n\tif (!isRecord(schema)) {\n\t\tv.add(where, \"must be an object of fields\");\n\t\treturn;\n\t}\n\tfor (const [key, field] of Object.entries(schema)) {\n\t\tconst at = `${where}.${key}`;\n\t\tif (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) v.add(at, \"field names are identifiers\");\n\t\tif (typeof field === \"string\") {\n\t\t\tif (!VALUE_TYPES.includes(field)) v.add(at, `unknown type ${JSON.stringify(field)}`);\n\t\t\telse if (field === \"enum\") v.add(at, \"an enum field needs its values (use the object form)\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isRecord(field) || typeof field.type !== \"string\" || !VALUE_TYPES.includes(field.type)) {\n\t\t\tv.add(at, \"must be a type name or an object with a valid type\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (field.max !== undefined) {\n\t\t\tif (!isPositiveInt(field.max)) v.add(at, \"max must be a positive integer\");\n\t\t\tif (!SIZED_TYPES.includes(field.type)) v.add(at, \"max applies to sized types only\");\n\t\t}\n\t\tif (field.type === \"enum\") {\n\t\t\tif (!Array.isArray(field.enum) || field.enum.length === 0 || !field.enum.every((e) => typeof e === \"string\")) {\n\t\t\t\tv.add(at, \"enum fields need a non-empty list of string values\");\n\t\t\t}\n\t\t} else if (field.enum !== undefined) v.add(at, \"enum values belong to enum fields only\");\n\t\tif (field.fields !== undefined) {\n\t\t\tif (field.type !== \"object\") v.add(at, \"fields belong to object fields only\");\n\t\t\telse validateSchema(v, at, field.fields);\n\t\t}\n\t\tif (field.items !== undefined) {\n\t\t\tif (field.type !== \"list\") v.add(at, \"items belong to list fields only\");\n\t\t\telse validateSchema(v, at, { item: field.items });\n\t\t}\n\t\tif (field.nullable !== undefined && typeof field.nullable !== \"boolean\") v.add(at, \"nullable must be a boolean\");\n\t\tif (field.doc !== undefined && typeof field.doc !== \"string\") v.add(at, \"doc must be a string\");\n\t}\n}\n\nfunction validateNamed(v: Violations, where: string, items: unknown, seen: Set<string>): Record<string, unknown>[] {\n\tif (!Array.isArray(items)) {\n\t\tv.add(where, \"must be a list\");\n\t\treturn [];\n\t}\n\tconst valid: Record<string, unknown>[] = [];\n\titems.forEach((item, index) => {\n\t\tconst at = `${where}[${index}]`;\n\t\tif (!isRecord(item)) {\n\t\t\tv.add(at, \"must be an object\");\n\t\t\treturn;\n\t\t}\n\t\tif (!isValidName(item.name)) {\n\t\t\tv.add(at, `invalid name ${JSON.stringify(item.name)}`);\n\t\t\treturn;\n\t\t}\n\t\tif (seen.has(item.name)) v.add(`${where}.${item.name}`, \"duplicate name\");\n\t\tseen.add(item.name);\n\t\tif (item.name.startsWith(\"abai.\") && !(where === \"events\" && LIBRARY_EVENTS.includes(item.name))) {\n\t\t\tv.add(`${where}.${item.name}`, \"the abai. prefix is reserved for the library\");\n\t\t}\n\t\tif (typeof item.doc !== \"string\" || item.doc.trim() === \"\") v.add(`${where}.${item.name}`, \"doc is required\");\n\t\tvalid.push(item);\n\t});\n\treturn valid;\n}\n\nfunction validateCell(v: Violations, cell: Record<string, unknown>): void {\n\tconst at = `cells.${cell.name}`;\n\tconst type = cell.type;\n\tif (typeof type !== \"string\" || !VALUE_TYPES.includes(type)) {\n\t\tv.add(at, `unknown type ${JSON.stringify(type)}`);\n\t\treturn;\n\t}\n\tif (cell.access !== \"read\" && cell.access !== \"readwrite\") v.add(at, \"access must be read or readwrite\");\n\tif (cell.max !== undefined) {\n\t\tif (!isPositiveInt(cell.max)) v.add(at, \"max must be a positive integer\");\n\t\tif (!SIZED_TYPES.includes(type)) v.add(at, \"max applies to sized types only\");\n\t}\n\tif (type === \"enum\") {\n\t\tif (!Array.isArray(cell.enum) || cell.enum.length === 0 || !cell.enum.every((e) => typeof e === \"string\")) {\n\t\t\tv.add(at, \"enum cells need a non-empty list of string values\");\n\t\t}\n\t} else if (cell.enum !== undefined) v.add(at, \"enum values belong to enum cells only\");\n\tif (cell.range !== undefined) {\n\t\tconst range = cell.range;\n\t\tif (\n\t\t\t!Array.isArray(range) ||\n\t\t\trange.length !== 2 ||\n\t\t\ttypeof range[0] !== \"number\" ||\n\t\t\ttypeof range[1] !== \"number\" ||\n\t\t\trange[0] > range[1]\n\t\t) {\n\t\t\tv.add(at, \"range must be [min, max]\");\n\t\t}\n\t\tif (type !== \"int\" && type !== \"float\") v.add(at, \"range applies to int and float cells only\");\n\t}\n\tif (cell.cadence !== undefined && !isPositiveInt(cell.cadence)) v.add(at, \"cadence must be a positive integer\");\n\tif (cell.fields !== undefined) {\n\t\tif (type !== \"object\") v.add(at, \"fields belong to object cells only\");\n\t\telse validateSchema(v, at, cell.fields);\n\t}\n\tif (cell.items !== undefined) {\n\t\tif (type !== \"list\") v.add(at, \"items belong to list cells only\");\n\t\telse validateSchema(v, at, { item: cell.items });\n\t}\n\tif (cell.nullable !== undefined && typeof cell.nullable !== \"boolean\") v.add(at, \"nullable must be a boolean\");\n\tif (cell.access === \"readwrite\") {\n\t\tif (cell.default === undefined) v.add(at, \"a readwrite cell needs a default\");\n\t\telse if (!matchesType(cell.default, cell as unknown as FieldSchema))\n\t\t\tv.add(at, \"default is not of the cell's type\");\n\t\tif (cell.policy !== undefined && cell.policy !== \"auto\" && cell.policy !== \"confirm\") {\n\t\t\tv.add(at, \"a knob's policy is auto or confirm\");\n\t\t}\n\t\tif (cell.timeout !== undefined) {\n\t\t\tif (!isDuration(cell.timeout)) v.add(at, \"timeout must be a duration such as 30s\");\n\t\t\tif (!SIZED_TYPES.includes(type)) v.add(at, \"a delivery timeout applies to sized knobs only\");\n\t\t}\n\t} else {\n\t\tif (cell.policy !== undefined) v.add(at, \"policy applies to readwrite cells only\");\n\t\tif (cell.timeout !== undefined) v.add(at, \"timeout applies to readwrite cells only\");\n\t\tif (cell.default !== undefined) v.add(at, \"default applies to readwrite cells only\");\n\t}\n}\n\nfunction validateEvent(v: Violations, event: Record<string, unknown>): void {\n\tconst at = `events.${event.name}`;\n\tvalidateSchema(v, `${at}.payload`, event.payload);\n\tif (event.wakes !== undefined && (typeof event.wakes !== \"string\" || event.wakes.trim() === \"\")) {\n\t\tv.add(at, \"wakes must be always, never or a condition\");\n\t}\n\tif (event.large !== undefined && typeof event.large !== \"boolean\") v.add(at, \"large must be a boolean\");\n\tif (isRecord(event.payload)) {\n\t\tconst bytes = payloadBytes(event.payload as Schema);\n\t\tif (bytes > EVENT_SLOT_BYTES && event.large !== true) {\n\t\t\tv.add(at, `payload counts ${bytes} bytes, over ${EVENT_SLOT_BYTES}: declare large: true`);\n\t\t}\n\t}\n}\n\nfunction validateCapability(v: Violations, cap: Record<string, unknown>, knobs: ReadonlySet<string>): void {\n\tconst at = `capabilities.${cap.name}`;\n\tvalidateSchema(v, `${at}.params`, cap.params);\n\tvalidateSchema(v, `${at}.result`, cap.result);\n\tif (cap.effect !== \"read\" && cap.effect !== \"mutate\") v.add(at, \"effect must be read or mutate\");\n\tif (cap.dispatch !== \"immediate\" && cap.dispatch !== \"safepoint\") v.add(at, \"dispatch must be declared\");\n\tif (typeof cap.policy !== \"string\" || !POLICIES.includes(cap.policy)) v.add(at, \"policy must be declared\");\n\tif (cap.timeout !== undefined && !isDuration(cap.timeout)) v.add(at, \"timeout must be a duration such as 30s\");\n\tif (cap.example !== undefined) {\n\t\tif (!isRecord(cap.example)) v.add(at, \"example must be an object of parameters\");\n\t\telse if (isRecord(cap.params)) {\n\t\t\tfor (const key of Object.keys(cap.example)) {\n\t\t\t\tif (!(key in cap.params)) v.add(at, `example has an undeclared parameter ${key}`);\n\t\t\t}\n\t\t}\n\t}\n\tif (cap.writes !== undefined) {\n\t\tif (!isValidName(cap.writes)) v.add(at, \"writes must name a cell\");\n\t\telse if (!knobs.has(cap.writes)) v.add(at, `writes names ${cap.writes}, which is not a readwrite cell`);\n\t}\n}\n\nfunction validateDecision(v: Violations, decision: Record<string, unknown>): void {\n\tconst at = `decisions.${decision.name}`;\n\tvalidateSchema(v, `${at}.context`, decision.context);\n\tconst hasOptions = decision.options !== undefined;\n\tconst hasAnswer = decision.answer !== undefined;\n\tif (hasOptions === hasAnswer) v.add(at, \"declare either options or answer\");\n\tif (hasOptions) {\n\t\tconst options = decision.options;\n\t\tif (!Array.isArray(options) || options.length === 0 || !options.every((o) => typeof o === \"string\")) {\n\t\t\tv.add(at, \"options must be a non-empty list of strings\");\n\t\t} else if (decision.default !== \"abort\" && !options.includes(decision.default as string)) {\n\t\t\tv.add(at, \"default must be one of the options or abort\");\n\t\t}\n\t}\n\tif (hasAnswer) validateSchema(v, `${at}.answer`, decision.answer);\n\tif (decision.default === undefined) v.add(at, \"default is required\");\n\tif (!isDuration(decision.timeout)) v.add(at, \"timeout is required (a duration such as 30s)\");\n\tif (typeof decision.policy !== \"string\" || !POLICIES.includes(decision.policy)) v.add(at, \"policy must be declared\");\n}\n\nfunction validateTurn(v: Violations, turn: Record<string, unknown>): void {\n\tif (!isDuration(turn.timeout)) v.add(`turns.${turn.name}`, \"timeout is required (a duration such as 30s)\");\n}\n\n/**\n * Validate a manifest in either form. Returns the violations, each\n * `<where>: <what>`; an empty list means the manifest validates.\n */\nexport function validateManifest(value: unknown): string[] {\n\tconst v = new Violations();\n\tif (!isRecord(value)) return [\"manifest: must be an object\"];\n\tif (value.abaigrammar !== ABAIGRAMMAR_VERSION) {\n\t\tv.add(\"abaigrammar\", `must be ${JSON.stringify(ABAIGRAMMAR_VERSION)}`);\n\t}\n\tif (typeof value.name !== \"string\" || value.name.trim() === \"\") v.add(\"name\", \"is required\");\n\tif (typeof value.entry !== \"string\" || value.entry.trim() === \"\") v.add(\"entry\", \"is required\");\n\tconst modes = value.modes;\n\tif (!Array.isArray(modes) || modes.length === 0) v.add(\"modes\", \"must list at least one mode\");\n\telse {\n\t\tmodes.forEach((mode, index) => {\n\t\t\tif (!(MODES as readonly unknown[]).includes(mode))\n\t\t\t\tv.add(`modes[${index}]`, `unknown mode ${JSON.stringify(mode)}`);\n\t\t});\n\t\tif (new Set(modes).size !== modes.length) v.add(\"modes\", \"must not repeat a mode\");\n\t}\n\tif (!isRecord(value.content) || typeof value.content.identity !== \"string\" || value.content.identity === \"\") {\n\t\tv.add(\"content.identity\", \"is required\");\n\t}\n\tif (!isRecord(value.audit) || typeof value.audit.path !== \"string\" || value.audit.path === \"\") {\n\t\tv.add(\"audit.path\", \"is required\");\n\t}\n\tif (value.lifecycle !== undefined) {\n\t\tconst lifecycle = value.lifecycle;\n\t\tif (!isRecord(lifecycle) || ![\"cooperative\", \"os\", \"none\"].includes(lifecycle.pause as string)) {\n\t\t\tv.add(\"lifecycle.pause\", \"must be cooperative, os or none\");\n\t\t}\n\t}\n\tif (value.deviations !== undefined) {\n\t\tconst deviations = value.deviations;\n\t\tif (!Array.isArray(deviations) || !deviations.every((d) => typeof d === \"string\" && d.trim() !== \"\")) {\n\t\t\tv.add(\"deviations\", \"must be a list of non-empty strings\");\n\t\t}\n\t}\n\tif (value.check !== undefined && (!isRecord(value.check) || typeof value.check.run !== \"string\")) {\n\t\tv.add(\"check.run\", \"is required when check is declared\");\n\t}\n\n\tconst cells = validateNamed(v, \"cells\", value.cells, new Set());\n\tfor (const cell of cells) validateCell(v, cell);\n\tconst knobs = new Set(cells.filter((cell) => cell.access === \"readwrite\").map((cell) => cell.name as string));\n\tfor (const event of validateNamed(v, \"events\", value.events, new Set())) validateEvent(v, event);\n\tfor (const cap of validateNamed(v, \"capabilities\", value.capabilities, new Set())) {\n\t\tvalidateCapability(v, cap, knobs);\n\t}\n\tfor (const decision of validateNamed(v, \"decisions\", value.decisions, new Set())) validateDecision(v, decision);\n\tfor (const turn of validateNamed(v, \"turns\", value.turns, new Set())) validateTurn(v, turn);\n\treturn v.list;\n}\n\n/** Narrow an unknown value to a Manifest; throws with the violations otherwise. */\nexport function assertManifest(value: unknown): Manifest {\n\tconst violations = validateManifest(value);\n\tif (violations.length > 0) throw new Error(`manifest does not validate:\\n${violations.join(\"\\n\")}`);\n\treturn value as Manifest;\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Manifest } from "./manifest.ts";
|
|
2
|
+
/** Render the manifest as YAML text with exactly one trailing newline. */
|
|
3
|
+
export declare function renderManifestYaml(manifest: Manifest): string;
|
|
4
|
+
/** Parse YAML text into a plain value; the caller validates it. */
|
|
5
|
+
export declare function parseManifestYaml(text: string): unknown;
|
|
6
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/manifest/render.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAgB9C,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAY7D;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD","sourcesContent":["// Rendering the manifest as abaigram.yaml and reading it back.\n//\n// The rendering must be byte-stable across machines and Node versions, since\n// `<entry> doctor` and the self-check test compare the checked-in file with\n// the rendered manifest: keys keep their insertion order, lines are never\n// folded, the header carries no version or date, and strings a YAML 1.1\n// reader would take for booleans are quoted.\nimport { Document, parse, Scalar, visit } from \"yaml\";\nimport type { Manifest } from \"./manifest.ts\";\n\n/** The comment above the rendered manifest, computed from its name, grammar version and entry. */\nfunction header(manifest: Manifest): string {\n\tconst entry = manifest.entry;\n\treturn [\n\t\t` abaigram.yaml: the manifest of ${manifest.name} as an abaigram (abaigrammar ${manifest.abaigrammar}).`,\n\t\t` Generated by \\`${entry} manifest\\` from the program's declarations in code.`,\n\t\t` Do not edit by hand: \\`${entry} doctor\\` and the test suite check that this file`,\n\t\t` agrees with the code. Regenerate with \\`${entry} manifest > abaigram.yaml\\`.`,\n\t].join(\"\\n\");\n}\n\n/** Strings YAML 1.2 renders bare but a YAML 1.1 reader (PyYAML, go-yaml v2) takes for booleans. */\nconst YAML_1_1_BOOLEANS = /^(?:y|yes|n|no|on|off)$/i;\n\n/** Render the manifest as YAML text with exactly one trailing newline. */\nexport function renderManifestYaml(manifest: Manifest): string {\n\tconst doc = new Document(manifest);\n\tdoc.commentBefore = header(manifest);\n\tvisit(doc, {\n\t\tScalar(_key, node) {\n\t\t\tif (typeof node.value === \"string\" && YAML_1_1_BOOLEANS.test(node.value)) {\n\t\t\t\tnode.type = Scalar.QUOTE_DOUBLE;\n\t\t\t}\n\t\t},\n\t});\n\tconst text = doc.toString({ lineWidth: 0 });\n\treturn `${text.replace(/\\n+$/, \"\")}\\n`;\n}\n\n/** Parse YAML text into a plain value; the caller validates it. */\nexport function parseManifestYaml(text: string): unknown {\n\treturn parse(text);\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Rendering the manifest as abaigram.yaml and reading it back.
|
|
2
|
+
//
|
|
3
|
+
// The rendering must be byte-stable across machines and Node versions, since
|
|
4
|
+
// `<entry> doctor` and the self-check test compare the checked-in file with
|
|
5
|
+
// the rendered manifest: keys keep their insertion order, lines are never
|
|
6
|
+
// folded, the header carries no version or date, and strings a YAML 1.1
|
|
7
|
+
// reader would take for booleans are quoted.
|
|
8
|
+
import { Document, parse, Scalar, visit } from "yaml";
|
|
9
|
+
/** The comment above the rendered manifest, computed from its name, grammar version and entry. */
|
|
10
|
+
function header(manifest) {
|
|
11
|
+
const entry = manifest.entry;
|
|
12
|
+
return [
|
|
13
|
+
` abaigram.yaml: the manifest of ${manifest.name} as an abaigram (abaigrammar ${manifest.abaigrammar}).`,
|
|
14
|
+
` Generated by \`${entry} manifest\` from the program's declarations in code.`,
|
|
15
|
+
` Do not edit by hand: \`${entry} doctor\` and the test suite check that this file`,
|
|
16
|
+
` agrees with the code. Regenerate with \`${entry} manifest > abaigram.yaml\`.`,
|
|
17
|
+
].join("\n");
|
|
18
|
+
}
|
|
19
|
+
/** Strings YAML 1.2 renders bare but a YAML 1.1 reader (PyYAML, go-yaml v2) takes for booleans. */
|
|
20
|
+
const YAML_1_1_BOOLEANS = /^(?:y|yes|n|no|on|off)$/i;
|
|
21
|
+
/** Render the manifest as YAML text with exactly one trailing newline. */
|
|
22
|
+
export function renderManifestYaml(manifest) {
|
|
23
|
+
const doc = new Document(manifest);
|
|
24
|
+
doc.commentBefore = header(manifest);
|
|
25
|
+
visit(doc, {
|
|
26
|
+
Scalar(_key, node) {
|
|
27
|
+
if (typeof node.value === "string" && YAML_1_1_BOOLEANS.test(node.value)) {
|
|
28
|
+
node.type = Scalar.QUOTE_DOUBLE;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
const text = doc.toString({ lineWidth: 0 });
|
|
33
|
+
return `${text.replace(/\n+$/, "")}\n`;
|
|
34
|
+
}
|
|
35
|
+
/** Parse YAML text into a plain value; the caller validates it. */
|
|
36
|
+
export function parseManifestYaml(text) {
|
|
37
|
+
return parse(text);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/manifest/render.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,6CAA6C;AAC7C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAGtD,kGAAkG;AAClG,SAAS,MAAM,CAAC,QAAkB,EAAU;IAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC7B,OAAO;QACN,mCAAmC,QAAQ,CAAC,IAAI,gCAAgC,QAAQ,CAAC,WAAW,IAAI;QACxG,mBAAmB,KAAK,sDAAsD;QAC9E,2BAA2B,KAAK,mDAAmD;QACnF,4CAA4C,KAAK,8BAA8B;KAC/E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACb;AAED,mGAAmG;AACnG,MAAM,iBAAiB,GAAG,0BAA0B,CAAC;AAErD,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,QAAkB,EAAU;IAC9D,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,KAAK,CAAC,GAAG,EAAE;QACV,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE;YAClB,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1E,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC;YACjC,CAAC;QAAA,CACD;KACD,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC;AAAA,CACvC;AAED,mEAAmE;AACnE,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAW;IACxD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;AAAA,CACnB","sourcesContent":["// Rendering the manifest as abaigram.yaml and reading it back.\n//\n// The rendering must be byte-stable across machines and Node versions, since\n// `<entry> doctor` and the self-check test compare the checked-in file with\n// the rendered manifest: keys keep their insertion order, lines are never\n// folded, the header carries no version or date, and strings a YAML 1.1\n// reader would take for booleans are quoted.\nimport { Document, parse, Scalar, visit } from \"yaml\";\nimport type { Manifest } from \"./manifest.ts\";\n\n/** The comment above the rendered manifest, computed from its name, grammar version and entry. */\nfunction header(manifest: Manifest): string {\n\tconst entry = manifest.entry;\n\treturn [\n\t\t` abaigram.yaml: the manifest of ${manifest.name} as an abaigram (abaigrammar ${manifest.abaigrammar}).`,\n\t\t` Generated by \\`${entry} manifest\\` from the program's declarations in code.`,\n\t\t` Do not edit by hand: \\`${entry} doctor\\` and the test suite check that this file`,\n\t\t` agrees with the code. Regenerate with \\`${entry} manifest > abaigram.yaml\\`.`,\n\t].join(\"\\n\");\n}\n\n/** Strings YAML 1.2 renders bare but a YAML 1.1 reader (PyYAML, go-yaml v2) takes for booleans. */\nconst YAML_1_1_BOOLEANS = /^(?:y|yes|n|no|on|off)$/i;\n\n/** Render the manifest as YAML text with exactly one trailing newline. */\nexport function renderManifestYaml(manifest: Manifest): string {\n\tconst doc = new Document(manifest);\n\tdoc.commentBefore = header(manifest);\n\tvisit(doc, {\n\t\tScalar(_key, node) {\n\t\t\tif (typeof node.value === \"string\" && YAML_1_1_BOOLEANS.test(node.value)) {\n\t\t\t\tnode.type = Scalar.QUOTE_DOUBLE;\n\t\t\t}\n\t\t},\n\t});\n\tconst text = doc.toString({ lineWidth: 0 });\n\treturn `${text.replace(/\\n+$/, \"\")}\\n`;\n}\n\n/** Parse YAML text into a plain value; the caller validates it. */\nexport function parseManifestYaml(text: string): unknown {\n\treturn parse(text);\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HarnessBinding } from "./harness-binding.ts";
|
|
2
|
+
export type NullForm = "null" | "exercise";
|
|
3
|
+
export interface NullHarnessReport {
|
|
4
|
+
form: NullForm;
|
|
5
|
+
events: number;
|
|
6
|
+
dropped: number;
|
|
7
|
+
decisions: number;
|
|
8
|
+
turns: number;
|
|
9
|
+
touchpoints: number;
|
|
10
|
+
/** Cells the program wrote while the harness was attached: a cell whose version moved, a knob's beyond the harness's own write. */
|
|
11
|
+
cellsWritten: string[];
|
|
12
|
+
/** The program's own events emitted while attached, by name, each once; the library's `abai.*` are not the program's. */
|
|
13
|
+
eventsEmitted: string[];
|
|
14
|
+
/** The active form only. */
|
|
15
|
+
knobsWritten: string[];
|
|
16
|
+
capabilitiesCalled: string[];
|
|
17
|
+
/** Declarations the run did not exercise, with the reason. */
|
|
18
|
+
unexercised: Array<{
|
|
19
|
+
kind: "capability" | "decision" | "turn" | "knob";
|
|
20
|
+
name: string;
|
|
21
|
+
why: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
export interface NullHarness {
|
|
25
|
+
readonly form: NullForm;
|
|
26
|
+
report(): NullHarnessReport;
|
|
27
|
+
/** The active form's exercise, once it has run (resolves at once for the passive form). */
|
|
28
|
+
readonly exercised: Promise<void>;
|
|
29
|
+
detach(reason: string): void;
|
|
30
|
+
}
|
|
31
|
+
export declare function attachNullHarness(binding: HarnessBinding, form: NullForm): NullHarness;
|
|
32
|
+
//# sourceMappingURL=null-harness.d.ts.map
|