oui-spec 0.6.0 → 0.7.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.
Files changed (47) hide show
  1. package/README.md +28 -20
  2. package/dist/chunk-2CPOHQGI.cjs +463 -0
  3. package/dist/chunk-2CPOHQGI.cjs.map +1 -0
  4. package/dist/{chunk-VQETSIY5.js → chunk-4MEYE6XZ.js} +244 -37
  5. package/dist/chunk-4MEYE6XZ.js.map +1 -0
  6. package/dist/{chunk-AFNWLRKV.cjs → chunk-DOJXITEZ.cjs} +248 -41
  7. package/dist/chunk-DOJXITEZ.cjs.map +1 -0
  8. package/dist/{chunk-F3SKRAGU.cjs → chunk-FSGB5JNJ.cjs} +5 -3
  9. package/dist/chunk-FSGB5JNJ.cjs.map +1 -0
  10. package/dist/chunk-RZUYWZFK.js +431 -0
  11. package/dist/chunk-RZUYWZFK.js.map +1 -0
  12. package/dist/{chunk-NYCJZQSP.js → chunk-UOTAHGIV.js} +5 -3
  13. package/dist/chunk-UOTAHGIV.js.map +1 -0
  14. package/dist/core/index.cjs +6 -6
  15. package/dist/core/index.d.cts +5 -5
  16. package/dist/core/index.d.ts +5 -5
  17. package/dist/core/index.js +2 -2
  18. package/dist/index.cjs +108 -20
  19. package/dist/index.d.cts +4 -4
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +3 -3
  22. package/dist/react/index.cjs +6 -6
  23. package/dist/react/index.d.cts +7 -6
  24. package/dist/react/index.d.ts +7 -6
  25. package/dist/react/index.js +1 -1
  26. package/dist/spec/index.cjs +98 -10
  27. package/dist/spec/index.d.cts +76 -4
  28. package/dist/spec/index.d.ts +76 -4
  29. package/dist/spec/index.js +1 -1
  30. package/dist/{surface-runtime-D5nINY4b.d.ts → surface-runtime-BPEtT3LZ.d.ts} +30 -6
  31. package/dist/{surface-runtime-CSZ9UtBO.d.cts → surface-runtime-CexHqUn-.d.cts} +30 -6
  32. package/dist/transport/index.d.cts +3 -3
  33. package/dist/transport/index.d.ts +3 -3
  34. package/dist/{types-CmJb1BQ8.d.cts → types-CnlVRPFL.d.cts} +92 -2
  35. package/dist/{types-CmJb1BQ8.d.ts → types-CnlVRPFL.d.ts} +92 -2
  36. package/dist/{websocket-Ce3tDSsJ.d.ts → websocket-DKL9qoO-.d.ts} +1 -1
  37. package/dist/{websocket-Ds2Rh_jL.d.cts → websocket-HnzPlfk6.d.cts} +1 -1
  38. package/package.json +35 -41
  39. package/spec/OUI-SPEC-v0.1.md +116 -7
  40. package/dist/chunk-AFNWLRKV.cjs.map +0 -1
  41. package/dist/chunk-B2EFZMGY.js +0 -159
  42. package/dist/chunk-B2EFZMGY.js.map +0 -1
  43. package/dist/chunk-F3SKRAGU.cjs.map +0 -1
  44. package/dist/chunk-LDECTDPU.cjs +0 -169
  45. package/dist/chunk-LDECTDPU.cjs.map +0 -1
  46. package/dist/chunk-NYCJZQSP.js.map +0 -1
  47. package/dist/chunk-VQETSIY5.js.map +0 -1
package/README.md CHANGED
@@ -64,13 +64,25 @@ change that: navigating unmounts one page's surfaces and mounts another's. An
64
64
  agent that only knew the capability set from before the action would be acting
65
65
  on the page it just left.
66
66
 
67
- Surfaces are heavy (every action's schema), so a result repeats them only when
68
- the agent runtime does not hold them: the runtime sends the `surfacesHash` it
69
- holds as the request's `knownSurfaces`, and the result carries `surfaces` only
70
- when the client's hash differs. A result the receiver refuses (too large,
71
- invalid) is acknowledged as refused, and the client sends it again trimmed,
72
- with `delivery` saying what was left out and why: the agent always learns the
73
- action's outcome. A request is acknowledged on receipt when the sender asks,
67
+ Action definitions are heavy (every action's schema: several hundred KB on a
68
+ studio page), so a client does not send them. It sends an **index**: one entry
69
+ per action, with its title, the first sentence of its description, its effect
70
+ and a one-line summary of what it takes. An agent runtime fetches the
71
+ definition it needs with the runtime's own `oui.describe`, and reads state that
72
+ did not fit with `oui.read`. This is the index form: pass `form: "index"` to
73
+ `createSurfaceRuntime` once the agent runtime reads it. Until 1.0 the default is
74
+ `"full"`, which sends every definition as earlier versions did.
75
+
76
+ A result repeats the index only when the agent runtime does not hold it: the
77
+ runtime sends the `surfacesHash` it holds as the request's `knownSurfaces`, and
78
+ the result carries `index` only when the client's hash differs.
79
+
80
+ What a client sends is fitted to a byte budget before it is sent (480 KB for a
81
+ result, 256 KB for a snapshot): long lists are cut first, then long texts, and
82
+ `fit` says where, so the rest can be read. A result the receiver still refuses
83
+ is acknowledged as refused, and the client sends it again trimmed a step at a
84
+ time (the index, then the observations, then the data), with `delivery` saying
85
+ what was left out and why: the agent always learns the action's outcome. A request is acknowledged on receipt when the sender asks,
74
86
  and a repeat of a request whose answer is on its way gets no second copy.
75
87
 
76
88
  An async action (`async: true`) is acknowledged at once with `interim: true`,
@@ -173,7 +185,7 @@ function CounterPage() {
173
185
  }
174
186
  ```
175
187
 
176
- `runtime.snapshot()` returns `{ surfaces, observations, surfacesHash }` for
188
+ `runtime.snapshot()` returns `{ surfaces, observations, surfacesHash }` (or `index` in place of `surfaces`, in index form) for
177
189
  everything mounted. An agent runtime that keeps no registry of its own can take it with
178
190
  each request (for example, with each chat turn); set `announce: false` and the
179
191
  runtime sends nothing but results over the socket.
@@ -256,7 +268,7 @@ sequenceDiagram
256
268
  WS->>Browser: oui:dispatch
257
269
  Note over Browser: Handler runs once (de-duplicated by requestId)
258
270
  Note over Browser: Waits until the UI settles
259
- Browser->>WS: oui:action:result { requestId, success, data, observations, surfacesHash, surfaces if changed }
271
+ Browser->>WS: oui:action:result { requestId, success, data, observations, surfacesHash, surfaces or index if changed }
260
272
  WS->>Agent: result for requestId
261
273
  ```
262
274
 
@@ -736,6 +748,7 @@ They even share JSON Schema for parameter validation — a deliberate design cho
736
748
  - [x] `createSurfaceRuntime()` — client-side record of mounted surfaces; every request answered with a result and the snapshot after it
737
749
  - [x] Approvals — `transaction` and destructive actions run only on a grant from the user's own confirmation, bound to the exact params (0.5.0)
738
750
  - [x] Results carry surfaces only when they changed (`knownSurfaces` / `surfacesHash`), and a refused result is sent again trimmed, saying why (0.6.0)
751
+ - [x] The index form: a client sends an index of its actions, definitions are fetched with `oui.describe`, state is read with `oui.read`, and every frame is fitted to a byte budget (0.7.0)
739
752
  - [ ] `oui-spec/devtools` — Surface inspector / debugger
740
753
  - [ ] `oui-spec/vue` — Vue bindings
741
754
  - [ ] `oui-spec/validator` — Runtime schema validation
@@ -747,20 +760,15 @@ They even share JSON Schema for parameter validation — a deliberate design cho
747
760
 
748
761
  Contributions welcome. Please read the spec at [`spec/OUI-SPEC-v0.1.md`](./spec/OUI-SPEC-v0.1.md) before proposing changes to ensure alignment with the design principles.
749
762
 
763
+ `oui-spec` lives in the [OUI monorepo](https://github.com/wesreid/oui) beside the `@ouispec/*` packages. See its [CONTRIBUTING.md](https://github.com/wesreid/oui/blob/main/CONTRIBUTING.md):
764
+
750
765
  ```bash
751
- # Clone and install
752
766
  git clone https://github.com/wesreid/oui.git
753
767
  cd oui
754
- npm install
755
-
756
- # Build
757
- npm run build
758
-
759
- # Run tests
760
- npm test
761
-
762
- # Typecheck
763
- npm run typecheck
768
+ pnpm install
769
+ pnpm --filter oui-spec build
770
+ pnpm --filter oui-spec test
771
+ pnpm --filter oui-spec typecheck
764
772
  ```
765
773
 
766
774
  ---
@@ -0,0 +1,463 @@
1
+ 'use strict';
2
+
3
+ // src/spec/types.ts
4
+ var OUI_PROTOCOL_EVENTS = {
5
+ SURFACE_REGISTER: "surface:register",
6
+ SURFACE_DEREGISTER: "surface:deregister",
7
+ ACTION_REQUEST: "action:request",
8
+ ACTION_RESULT: "action:result",
9
+ OBSERVATION_UPDATE: "observation:update"
10
+ };
11
+
12
+ // src/spec/approval.ts
13
+ var OUI_EFFECT_KINDS = [
14
+ "view",
15
+ "selection",
16
+ "navigate",
17
+ "open",
18
+ "edit",
19
+ "file",
20
+ "mutate",
21
+ "job",
22
+ "transaction"
23
+ ];
24
+ var OUI_EFFECT_ACCESS = {
25
+ view: "read",
26
+ selection: "read",
27
+ navigate: "read",
28
+ open: "read",
29
+ edit: "write",
30
+ file: "write",
31
+ mutate: "write",
32
+ job: "write",
33
+ transaction: "write"
34
+ };
35
+ function effectAccess(effect) {
36
+ return effect === void 0 ? "write" : OUI_EFFECT_ACCESS[effect];
37
+ }
38
+ function requiresApproval(effect, destructive) {
39
+ if (effect === "transaction") return true;
40
+ return !!destructive && effectAccess(effect) === "write";
41
+ }
42
+ var ARGS_HASH_PATTERN = /^[0-9a-f]{64}$/;
43
+ function canonicalJson(value) {
44
+ return serialize(value, "$");
45
+ }
46
+ async function argsHash(params) {
47
+ const canonical = canonicalJson(params);
48
+ const subtle = await webCrypto();
49
+ const digest = await subtle.digest(
50
+ "SHA-256",
51
+ new TextEncoder().encode(canonical)
52
+ );
53
+ let hex = "";
54
+ for (const byte of new Uint8Array(digest))
55
+ hex += byte.toString(16).padStart(2, "0");
56
+ return hex;
57
+ }
58
+ async function webCrypto() {
59
+ const global = globalThis.crypto?.subtle;
60
+ if (global) return global;
61
+ const nodeCrypto = "node:crypto";
62
+ try {
63
+ const mod = await import(
64
+ /* @vite-ignore */
65
+ nodeCrypto
66
+ );
67
+ if (mod.webcrypto?.subtle) return mod.webcrypto.subtle;
68
+ } catch {
69
+ }
70
+ throw new Error(
71
+ "[OUI] argsHash needs WebCrypto (crypto.subtle), which this runtime does not provide"
72
+ );
73
+ }
74
+ function refuse(path, what) {
75
+ throw new TypeError(`[OUI] ${path} is not I-JSON: ${what}`);
76
+ }
77
+ function serialize(value, path) {
78
+ switch (typeof value) {
79
+ case "string":
80
+ return quote(value, path);
81
+ case "number":
82
+ if (!Number.isFinite(value)) refuse(path, String(value));
83
+ return JSON.stringify(value);
84
+ case "boolean":
85
+ return value ? "true" : "false";
86
+ case "object": {
87
+ if (value === null) return "null";
88
+ if (Array.isArray(value)) {
89
+ return `[${value.map((item, i) => serialize(item, `${path}[${i}]`)).join(",")}]`;
90
+ }
91
+ const proto = Object.getPrototypeOf(value);
92
+ if (proto !== Object.prototype && proto !== null) {
93
+ refuse(path, `a ${proto?.constructor?.name ?? "non-plain"} object`);
94
+ }
95
+ const record = value;
96
+ const keys = Object.keys(record).filter((k) => record[k] !== void 0).sort();
97
+ return `{${keys.map(
98
+ (k) => `${quote(k, `${path} key`)}:${serialize(record[k], `${path}.${k}`)}`
99
+ ).join(",")}}`;
100
+ }
101
+ default:
102
+ return refuse(path, typeof value);
103
+ }
104
+ }
105
+ function quote(text, path) {
106
+ for (let i = 0; i < text.length; i++) {
107
+ const unit = text.charCodeAt(i);
108
+ if (unit >= 55296 && unit <= 56319) {
109
+ const next = text.charCodeAt(i + 1);
110
+ if (next >= 56320 && next <= 57343) {
111
+ i++;
112
+ continue;
113
+ }
114
+ refuse(path, `a lone surrogate at ${i}`);
115
+ }
116
+ if (unit >= 56320 && unit <= 57343)
117
+ refuse(path, `a lone surrogate at ${i}`);
118
+ }
119
+ return JSON.stringify(text);
120
+ }
121
+
122
+ // src/spec/surfaces-hash.ts
123
+ var PREFIX = "fnv1a64:";
124
+ function surfacesHash(surfaces) {
125
+ return PREFIX + fnv1a64(sortedJson(surfaces));
126
+ }
127
+ function sortedJson(value) {
128
+ return JSON.stringify(sortKeys(value)) ?? "null";
129
+ }
130
+ function sortKeys(value) {
131
+ if (Array.isArray(value)) return value.map(sortKeys);
132
+ if (value && typeof value === "object") {
133
+ const out = {};
134
+ for (const key of Object.keys(value).sort()) {
135
+ const member = value[key];
136
+ if (member !== void 0) out[key] = sortKeys(member);
137
+ }
138
+ return out;
139
+ }
140
+ return value;
141
+ }
142
+ function fnv1a64(text) {
143
+ let hi = 3421674724;
144
+ let lo = 2216829733;
145
+ for (let i = 0; i < text.length; i++) {
146
+ lo = (lo ^ text.charCodeAt(i)) >>> 0;
147
+ const loProduct = lo * 435;
148
+ const carry = Math.floor(loProduct / 4294967296);
149
+ const newLo = loProduct >>> 0;
150
+ hi = Math.imul(hi, 435) + Math.imul(lo, 256) + carry >>> 0;
151
+ lo = newLo;
152
+ }
153
+ return hex32(hi) + hex32(lo);
154
+ }
155
+ function hex32(n) {
156
+ return (n >>> 0).toString(16).padStart(8, "0");
157
+ }
158
+
159
+ // src/spec/index-form.ts
160
+ var INDEX_DESCRIPTION_CHARS = 160;
161
+ var INDEX_INPUT_CHARS = 120;
162
+ var INDEX_INPUT_PROPERTIES = 6;
163
+ var INDEX_ENUM_VALUES = 4;
164
+ var OUI_RUNTIME_SURFACE = "oui";
165
+ var OUI_DESCRIBE_ACTION = "describe";
166
+ var OUI_READ_ACTION = "read";
167
+ function utf8Length(text) {
168
+ let bytes = 0;
169
+ for (let i = 0; i < text.length; i++) {
170
+ const code = text.charCodeAt(i);
171
+ if (code < 128) bytes += 1;
172
+ else if (code < 2048) bytes += 2;
173
+ else if (code >= 55296 && code <= 56319) {
174
+ bytes += 4;
175
+ i++;
176
+ } else bytes += 3;
177
+ }
178
+ return bytes;
179
+ }
180
+ function jsonBytes(value) {
181
+ const json = JSON.stringify(value);
182
+ return json === void 0 ? 0 : utf8Length(json);
183
+ }
184
+ function clip(text, max) {
185
+ return text.length <= max ? text : `${text.slice(0, max - 1).trimEnd()}\u2026`;
186
+ }
187
+ function firstSentence(text) {
188
+ const line = text.replace(/\s+/g, " ").trim();
189
+ const end = line.search(/[.!?](?= [A-Z0-9"'([])/);
190
+ return clip(
191
+ end >= 0 ? line.slice(0, end + 1) : line,
192
+ INDEX_DESCRIPTION_CHARS
193
+ );
194
+ }
195
+ function typeOf(schema) {
196
+ const t = schema.type;
197
+ return Array.isArray(t) ? t.join("|") : t ?? "";
198
+ }
199
+ function unitOf(schema) {
200
+ const unit = schema["x-unit"];
201
+ return typeof unit === "string" && unit ? ` ${unit}` : "";
202
+ }
203
+ function unionOf(schema) {
204
+ const members = schema.oneOf ?? schema.anyOf;
205
+ return members && members.length > 0 ? members : null;
206
+ }
207
+ function discriminatorOf(members) {
208
+ const first = members[0]?.properties;
209
+ if (!first) return null;
210
+ for (const name of Object.keys(first)) {
211
+ const constants = members.map((m) => constantOf(m.properties?.[name]));
212
+ if (constants.every((c) => c !== void 0) && new Set(constants).size === members.length)
213
+ return name;
214
+ }
215
+ return null;
216
+ }
217
+ function constantOf(schema) {
218
+ if (!schema) return void 0;
219
+ if (typeof schema.const === "string" || typeof schema.const === "number" || typeof schema.const === "boolean") {
220
+ return schema.const;
221
+ }
222
+ return schema.enum?.length === 1 ? schema.enum[0] : void 0;
223
+ }
224
+ function valueSummary(schema) {
225
+ const constant = constantOf(schema);
226
+ if (constant !== void 0 && !schema.enum) return JSON.stringify(constant);
227
+ if (schema.enum) {
228
+ const shown = schema.enum.slice(0, INDEX_ENUM_VALUES).map(String).join("|");
229
+ return schema.enum.length > INDEX_ENUM_VALUES ? `${shown}|\u2026(${schema.enum.length})` : shown;
230
+ }
231
+ const union = unionOf(schema);
232
+ if (union) return `one of ${union.length}`;
233
+ const type = typeOf(schema);
234
+ if (type === "number" || type === "integer") {
235
+ const { minimum: min, maximum: max } = schema;
236
+ const range = min !== void 0 && max !== void 0 ? ` ${min}\u2013${max}` : min !== void 0 ? ` \u2265${min}` : max !== void 0 ? ` \u2264${max}` : "";
237
+ return `${type}${range}${unitOf(schema)}`;
238
+ }
239
+ if (type === "string")
240
+ return schema.format ? `string(${schema.format})` : "string";
241
+ if (type === "array")
242
+ return schema.items ? `list of ${valueSummary(schema.items)}` : "list";
243
+ if (type === "object") {
244
+ const n = Object.keys(schema.properties ?? {}).length;
245
+ return n > 0 ? `object(${n})` : "object";
246
+ }
247
+ return type || "any";
248
+ }
249
+ function summarizeInput(schema) {
250
+ if (!schema) return "none";
251
+ const union = unionOf(schema);
252
+ if (union) {
253
+ const by = discriminatorOf(union);
254
+ return clip(
255
+ `one of ${union.length} shapes${by ? ` by ${by}` : ""}`,
256
+ INDEX_INPUT_CHARS
257
+ );
258
+ }
259
+ const properties = schema.properties ?? {};
260
+ const names = Object.keys(properties);
261
+ if (names.length === 0)
262
+ return typeOf(schema) && typeOf(schema) !== "object" ? valueSummary(schema) : "none";
263
+ const required = new Set(schema.required ?? []);
264
+ const ordered = [
265
+ ...names.filter((n) => required.has(n)),
266
+ ...names.filter((n) => !required.has(n))
267
+ ];
268
+ const shown = ordered.slice(0, INDEX_INPUT_PROPERTIES);
269
+ const more = ordered.length - shown.length;
270
+ const parts = shown.map(
271
+ (n) => `${n}${required.has(n) ? "" : "?"}: ${valueSummary(properties[n])}`
272
+ );
273
+ if (more > 0) parts.push(`+${more} more`);
274
+ return clip(parts.join(", "), INDEX_INPUT_CHARS);
275
+ }
276
+ function definitionHash(action) {
277
+ return fnv1a64(sortedJson(action));
278
+ }
279
+ function indexEntry(action) {
280
+ return {
281
+ id: action.id,
282
+ ...action.title ? { title: action.title } : {},
283
+ description: firstSentence(action.description),
284
+ ...action.effect !== void 0 ? { effect: action.effect } : {},
285
+ ...action.confirm ? { confirm: true } : {},
286
+ ...action.async ? { async: true } : {},
287
+ ...action.estimatedDuration ? { estimatedDuration: action.estimatedDuration } : {},
288
+ ...action.polling?.maxDurationMs !== void 0 ? { maxDurationMs: action.polling.maxDurationMs } : {},
289
+ input: summarizeInput(action.input),
290
+ definitionHash: definitionHash(action),
291
+ definitionBytes: jsonBytes(action)
292
+ };
293
+ }
294
+ function surfaceIndex(surface) {
295
+ return {
296
+ id: surface.id,
297
+ name: surface.name,
298
+ description: surface.description,
299
+ ...surface.version !== void 0 ? { version: surface.version } : {},
300
+ ...surface.observations ? { observations: surface.observations } : {},
301
+ index: surface.actions.map(indexEntry)
302
+ };
303
+ }
304
+
305
+ // src/spec/fit.ts
306
+ var FIT_LIST_STEPS = [200, 50, 20, 5, 0];
307
+ var FIT_TEXT_CHARS = 2e3;
308
+ function pointerStep(pointer, key) {
309
+ return `${pointer}/${String(key).replace(/~/g, "~0").replace(/\//g, "~1")}`;
310
+ }
311
+ function pointerSteps(pointer) {
312
+ if (pointer === "") return [];
313
+ if (!pointer.startsWith("/"))
314
+ throw new Error(
315
+ `"${pointer}" is not a JSON Pointer: it must be "" or start with "/"`
316
+ );
317
+ return pointer.slice(1).split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
318
+ }
319
+ function atPointer(value, pointer) {
320
+ let at = value;
321
+ for (const step of pointerSteps(pointer)) {
322
+ if (Array.isArray(at)) {
323
+ at = /^(0|[1-9]\d*)$/.test(step) ? at[Number(step)] : void 0;
324
+ } else if (at && typeof at === "object") {
325
+ at = Object.prototype.hasOwnProperty.call(at, step) ? at[step] : void 0;
326
+ } else return void 0;
327
+ if (at === void 0) return void 0;
328
+ }
329
+ return at;
330
+ }
331
+ function slots(observations, want) {
332
+ const found = [];
333
+ const walk = (holder, key, surface, observation, path) => {
334
+ const value = holder[key];
335
+ if (Array.isArray(value)) {
336
+ if (want === "list")
337
+ found.push({ holder, key, surface, observation, path });
338
+ value.forEach(
339
+ (_, i) => walk(value, i, surface, observation, pointerStep(path, i))
340
+ );
341
+ } else if (value && typeof value === "object") {
342
+ for (const k of Object.keys(value))
343
+ walk(
344
+ value,
345
+ k,
346
+ surface,
347
+ observation,
348
+ pointerStep(path, k)
349
+ );
350
+ } else if (typeof value === "string" && want === "text") {
351
+ found.push({ holder, key, surface, observation, path });
352
+ }
353
+ };
354
+ for (const surface of Object.keys(observations)) {
355
+ for (const observation of Object.keys(observations[surface])) {
356
+ walk(observations[surface], observation, surface, observation, "");
357
+ }
358
+ }
359
+ return found;
360
+ }
361
+ function fitObservations(observations, budget) {
362
+ if (jsonBytes(observations) <= budget) return { observations, cuts: [] };
363
+ const fitted = JSON.parse(
364
+ JSON.stringify(observations)
365
+ );
366
+ const cuts = /* @__PURE__ */ new Map();
367
+ const note = (slot, kind, total, kept) => {
368
+ const id = `${slot.surface}\0${slot.observation}\0${slot.path}`;
369
+ const prior = cuts.get(id);
370
+ cuts.set(id, {
371
+ surface: slot.surface,
372
+ observation: slot.observation,
373
+ path: slot.path,
374
+ kind,
375
+ total: prior ? prior.total : total,
376
+ kept
377
+ });
378
+ };
379
+ const fits = () => jsonBytes(fitted) <= budget;
380
+ for (const rows of FIT_LIST_STEPS) {
381
+ for (const slot of slots(fitted, "list")) {
382
+ const list = slot.holder[slot.key];
383
+ if (list.length <= rows) continue;
384
+ note(slot, "list", list.length, rows);
385
+ list.length = rows;
386
+ }
387
+ for (const [id, cut] of cuts) {
388
+ if (cut.kind === "list" && atPointer(fitted[cut.surface]?.[cut.observation], cut.path) === void 0)
389
+ cuts.delete(id);
390
+ }
391
+ if (fits()) return { observations: fitted, cuts: [...cuts.values()] };
392
+ }
393
+ for (const slot of slots(fitted, "text")) {
394
+ const text = slot.holder[slot.key];
395
+ if (text.length <= FIT_TEXT_CHARS) continue;
396
+ note(slot, "text", text.length, FIT_TEXT_CHARS);
397
+ slot.holder[slot.key] = text.slice(
398
+ 0,
399
+ FIT_TEXT_CHARS
400
+ );
401
+ }
402
+ if (fits()) return { observations: fitted, cuts: [...cuts.values()] };
403
+ const values = Object.keys(fitted).flatMap(
404
+ (surface) => Object.keys(fitted[surface]).map((observation) => ({
405
+ surface,
406
+ observation,
407
+ bytes: jsonBytes(fitted[surface][observation])
408
+ }))
409
+ ).sort(
410
+ (a, b) => b.bytes - a.bytes || a.surface.localeCompare(b.surface) || a.observation.localeCompare(b.observation)
411
+ );
412
+ for (const { surface, observation, bytes } of values) {
413
+ if (fits()) break;
414
+ for (const [id, cut] of cuts) {
415
+ if (cut.surface === surface && cut.observation === observation)
416
+ cuts.delete(id);
417
+ }
418
+ fitted[surface][observation] = null;
419
+ cuts.set(`${surface}\0${observation}\0`, {
420
+ surface,
421
+ observation,
422
+ path: "",
423
+ kind: "value",
424
+ total: bytes,
425
+ kept: 0
426
+ });
427
+ }
428
+ return { observations: fitted, cuts: [...cuts.values()] };
429
+ }
430
+
431
+ exports.ARGS_HASH_PATTERN = ARGS_HASH_PATTERN;
432
+ exports.FIT_LIST_STEPS = FIT_LIST_STEPS;
433
+ exports.FIT_TEXT_CHARS = FIT_TEXT_CHARS;
434
+ exports.INDEX_DESCRIPTION_CHARS = INDEX_DESCRIPTION_CHARS;
435
+ exports.INDEX_INPUT_CHARS = INDEX_INPUT_CHARS;
436
+ exports.INDEX_INPUT_PROPERTIES = INDEX_INPUT_PROPERTIES;
437
+ exports.OUI_DESCRIBE_ACTION = OUI_DESCRIBE_ACTION;
438
+ exports.OUI_EFFECT_ACCESS = OUI_EFFECT_ACCESS;
439
+ exports.OUI_EFFECT_KINDS = OUI_EFFECT_KINDS;
440
+ exports.OUI_PROTOCOL_EVENTS = OUI_PROTOCOL_EVENTS;
441
+ exports.OUI_READ_ACTION = OUI_READ_ACTION;
442
+ exports.OUI_RUNTIME_SURFACE = OUI_RUNTIME_SURFACE;
443
+ exports.argsHash = argsHash;
444
+ exports.atPointer = atPointer;
445
+ exports.canonicalJson = canonicalJson;
446
+ exports.constantOf = constantOf;
447
+ exports.definitionHash = definitionHash;
448
+ exports.discriminatorOf = discriminatorOf;
449
+ exports.effectAccess = effectAccess;
450
+ exports.firstSentence = firstSentence;
451
+ exports.fitObservations = fitObservations;
452
+ exports.indexEntry = indexEntry;
453
+ exports.jsonBytes = jsonBytes;
454
+ exports.pointerStep = pointerStep;
455
+ exports.pointerSteps = pointerSteps;
456
+ exports.requiresApproval = requiresApproval;
457
+ exports.sortedJson = sortedJson;
458
+ exports.summarizeInput = summarizeInput;
459
+ exports.surfaceIndex = surfaceIndex;
460
+ exports.surfacesHash = surfacesHash;
461
+ exports.utf8Length = utf8Length;
462
+ //# sourceMappingURL=chunk-2CPOHQGI.cjs.map
463
+ //# sourceMappingURL=chunk-2CPOHQGI.cjs.map