@ai-matrx/content-ir 0.8.0 → 0.10.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 (45) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +24 -5
  3. package/dist/convert.cjs +1680 -0
  4. package/dist/convert.cjs.map +1 -0
  5. package/dist/convert.d.cts +230 -0
  6. package/dist/convert.d.ts +230 -0
  7. package/dist/convert.js +1666 -0
  8. package/dist/convert.js.map +1 -0
  9. package/dist/core.cjs +2493 -0
  10. package/dist/core.cjs.map +1 -0
  11. package/dist/core.d.cts +370 -0
  12. package/dist/core.d.ts +370 -0
  13. package/dist/core.js +2452 -0
  14. package/dist/core.js.map +1 -0
  15. package/dist/index.cjs +11 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +9 -2030
  18. package/dist/index.d.ts +9 -2030
  19. package/dist/index.js +11 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/ir-tree-DbLVxbf1.d.cts +441 -0
  22. package/dist/ir-tree-Dsc_66ek.d.ts +441 -0
  23. package/dist/ir-types-95bA2cXH.d.cts +119 -0
  24. package/dist/ir-types-95bA2cXH.d.ts +119 -0
  25. package/dist/kind-schema.types-CwncWj9U.d.cts +139 -0
  26. package/dist/kind-schema.types-CwncWj9U.d.ts +139 -0
  27. package/dist/registry.cjs +468 -0
  28. package/dist/registry.cjs.map +1 -0
  29. package/dist/registry.d.cts +357 -0
  30. package/dist/registry.d.ts +357 -0
  31. package/dist/registry.js +456 -0
  32. package/dist/registry.js.map +1 -0
  33. package/dist/session.cjs +2052 -0
  34. package/dist/session.cjs.map +1 -0
  35. package/dist/session.d.cts +75 -0
  36. package/dist/session.d.ts +75 -0
  37. package/dist/session.js +2047 -0
  38. package/dist/session.js.map +1 -0
  39. package/dist/wire.cjs +310 -0
  40. package/dist/wire.cjs.map +1 -0
  41. package/dist/wire.d.cts +326 -0
  42. package/dist/wire.d.ts +326 -0
  43. package/dist/wire.js +291 -0
  44. package/dist/wire.js.map +1 -0
  45. package/package.json +73 -1
@@ -0,0 +1,1680 @@
1
+ 'use strict';
2
+
3
+ // core/kind-schema.types.ts
4
+ var KIND_KEY = "__kind";
5
+ function scalarArrayItemType(type) {
6
+ if (type === "number[]") return "number";
7
+ if (type === "boolean[]") return "boolean";
8
+ return "string";
9
+ }
10
+
11
+ // utils/text-case-converter.ts
12
+ var DEFAULT_WORD_REPLACEMENTS = {
13
+ // Acronyms & initialisms
14
+ "api": "API",
15
+ "apis": "APIs",
16
+ "ui": "UI",
17
+ "ux": "UX",
18
+ "id": "ID",
19
+ "ids": "IDs",
20
+ "qr": "QR",
21
+ "ssr": "SSR",
22
+ "csr": "CSR",
23
+ "ssg": "SSG",
24
+ "isr": "ISR",
25
+ "spa": "SPA",
26
+ "pwa": "PWA",
27
+ "sdk": "SDK",
28
+ "sdks": "SDKs",
29
+ "cli": "CLI",
30
+ "tty": "TTY",
31
+ "repl": "REPL",
32
+ "ci": "CI",
33
+ "cd": "CD",
34
+ "cpu": "CPU",
35
+ "cpus": "CPUs",
36
+ "gpu": "GPU",
37
+ "gpus": "GPUs",
38
+ "ram": "RAM",
39
+ "rom": "ROM",
40
+ "ssd": "SSD",
41
+ "ssds": "SSDs",
42
+ "hdd": "HDD",
43
+ "hdds": "HDDs",
44
+ "kpi": "KPI",
45
+ "kpis": "KPIs",
46
+ "sla": "SLA",
47
+ "slas": "SLAs",
48
+ "slo": "SLO",
49
+ "slos": "SLOs",
50
+ "sli": "SLI",
51
+ "slis": "SLIs",
52
+ "dom": "DOM",
53
+ // Web, formats, protocols
54
+ "url": "URL",
55
+ "urls": "URLs",
56
+ "uri": "URI",
57
+ "uris": "URIs",
58
+ "http": "HTTP",
59
+ "https": "HTTPS",
60
+ "html": "HTML",
61
+ "css": "CSS",
62
+ "json": "JSON",
63
+ "yaml": "YAML",
64
+ "yml": "YML",
65
+ "toml": "TOML",
66
+ "csv": "CSV",
67
+ "pdf": "PDF",
68
+ "tsv": "TSV",
69
+ "jpg": "JPG",
70
+ "jpeg": "JPEG",
71
+ "png": "PNG",
72
+ "gif": "GIF",
73
+ "webp": "WebP",
74
+ "heic": "HEIC",
75
+ "heif": "HEIF",
76
+ "bmp": "BMP",
77
+ "tiff": "TIFF",
78
+ "ico": "ICO",
79
+ "xml": "XML",
80
+ "sql": "SQL",
81
+ "db": "DB",
82
+ "dbs": "DBs",
83
+ "nosql": "NoSQL",
84
+ "graphql": "GraphQL",
85
+ "grpc": "gRPC",
86
+ "rest": "REST",
87
+ "restful": "RESTful",
88
+ "websocket": "WebSocket",
89
+ "websockets": "WebSockets",
90
+ "webrtc": "WebRTC",
91
+ // Networking
92
+ "ip": "IP",
93
+ "ipv4": "IPv4",
94
+ "ipv6": "IPv6",
95
+ "dns": "DNS",
96
+ "dhcp": "DHCP",
97
+ "nat": "NAT",
98
+ "tcp": "TCP",
99
+ "udp": "UDP",
100
+ "icmp": "ICMP",
101
+ "ttl": "TTL",
102
+ "lan": "LAN",
103
+ "wan": "WAN",
104
+ "vlan": "VLAN",
105
+ "cdn": "CDN",
106
+ "ftp": "FTP",
107
+ "ssh": "SSH",
108
+ "tls": "TLS",
109
+ "ssl": "SSL",
110
+ // Security & crypto
111
+ "jwt": "JWT",
112
+ "jws": "JWS",
113
+ "jwe": "JWE",
114
+ "hmac": "HMAC",
115
+ "rsa": "RSA",
116
+ "ecdsa": "ECDSA",
117
+ "aes": "AES",
118
+ "pbkdf2": "PBKDF2",
119
+ "argon2": "Argon2",
120
+ "scrypt": "scrypt",
121
+ "totp": "TOTP",
122
+ "hotp": "HOTP",
123
+ "mfa": "MFA",
124
+ "2fa": "2FA",
125
+ "csrf": "CSRF",
126
+ "xss": "XSS",
127
+ "ssrf": "SSRF",
128
+ "rce": "RCE",
129
+ "dos": "DoS",
130
+ "ddos": "DDoS",
131
+ "mitm": "MITM",
132
+ "csp": "CSP",
133
+ "cors": "CORS",
134
+ "pii": "PII",
135
+ "phi": "PHI",
136
+ "gdpr": "GDPR",
137
+ "ccpa": "CCPA",
138
+ "hipaa": "HIPAA",
139
+ "rfc": "RFC",
140
+ // Platforms, langs, tools (single-token)
141
+ "javascript": "JavaScript",
142
+ "typescript": "TypeScript",
143
+ "jsx": "JSX",
144
+ "tsx": "TSX",
145
+ "node": "Node",
146
+ // (used when tokenized alone)
147
+ "deno": "Deno",
148
+ "bun": "Bun",
149
+ "react": "React",
150
+ "nextjs": "Next.js",
151
+ // if your tokenizer drops dots, keep this
152
+ "nodejs": "Node.js",
153
+ "postgresql": "PostgreSQL",
154
+ "postgres": "Postgres",
155
+ "mysql": "MySQL",
156
+ "sqlite": "SQLite",
157
+ "redis": "Redis",
158
+ "supabase": "Supabase",
159
+ "docker": "Docker",
160
+ "kubernetes": "Kubernetes",
161
+ "k8s": "Kubernetes",
162
+ "helm": "Helm",
163
+ "npm": "npm",
164
+ "pnpm": "pnpm",
165
+ "yarn": "Yarn",
166
+ "eslint": "ESLint",
167
+ "prettier": "Prettier",
168
+ "vite": "Vite",
169
+ "webpack": "Webpack",
170
+ "babel": "Babel",
171
+ // OS & vendors
172
+ "macos": "macOS",
173
+ "ios": "iOS",
174
+ "ipados": "iPadOS",
175
+ "watchos": "watchOS",
176
+ "tvos": "tvOS",
177
+ "windows": "Windows",
178
+ "linux": "Linux",
179
+ "ubuntu": "Ubuntu",
180
+ "github": "GitHub",
181
+ "gitlab": "GitLab",
182
+ "bitbucket": "Bitbucket",
183
+ // Data & analytics
184
+ "etl": "ETL",
185
+ "elt": "ELT",
186
+ "olap": "OLAP",
187
+ "oltp": "OLTP",
188
+ "bi": "BI",
189
+ // Time & locales
190
+ "utc": "UTC",
191
+ "gmt": "GMT",
192
+ "pst": "PST",
193
+ "pdt": "PDT",
194
+ "pt": "PT",
195
+ // Common “small words” to keep lowercase (unless first/last word)
196
+ "or": "or",
197
+ "and": "and",
198
+ "the": "the",
199
+ "of": "of",
200
+ "in": "in",
201
+ "to": "to",
202
+ "with": "with",
203
+ "as": "as",
204
+ "by": "by",
205
+ "for": "for",
206
+ "on": "on",
207
+ "at": "at",
208
+ "up": "up",
209
+ "a": "a",
210
+ "an": "an",
211
+ "is": "is",
212
+ "are": "are",
213
+ "was": "was",
214
+ "were": "were",
215
+ "be": "be",
216
+ "but": "but",
217
+ "nor": "nor",
218
+ "so": "so",
219
+ "yet": "yet",
220
+ "per": "per",
221
+ "via": "via",
222
+ // Latin abbreviations (tokenized as words in some pipelines)
223
+ "eg": "e.g.",
224
+ "ie": "i.e.",
225
+ "etc": "etc.",
226
+ "aka": "aka",
227
+ "vs": "vs.",
228
+ "v": "v.",
229
+ // Client abbreviations
230
+ "CIC": "CIC",
231
+ "AGR": "AGR",
232
+ "AGER": "AGER",
233
+ "DD": "DD",
234
+ "TS": "TS",
235
+ "TM": "TM",
236
+ "arman": "Arman"
237
+ };
238
+ var DEFAULT_OPTIONS = {
239
+ textCase: "title",
240
+ wordReplacements: DEFAULT_WORD_REPLACEMENTS,
241
+ trim: true
242
+ };
243
+ function formatText(text, options = {}) {
244
+ const opts = { ...DEFAULT_OPTIONS, ...options };
245
+ if (!text) return "";
246
+ let normalized = text.replace(/_/g, " ").replace(/-/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\s+/g, " ");
247
+ if (opts.trim) {
248
+ normalized = normalized.trim();
249
+ }
250
+ let caseTransformed = normalized;
251
+ switch (opts.textCase) {
252
+ case "title":
253
+ caseTransformed = normalized.replace(
254
+ /\w\S*/g,
255
+ (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
256
+ );
257
+ break;
258
+ case "sentence":
259
+ if (normalized.length > 0) {
260
+ caseTransformed = normalized.charAt(0).toUpperCase() + normalized.slice(1).toLowerCase();
261
+ }
262
+ break;
263
+ case "lower":
264
+ caseTransformed = normalized.toLowerCase();
265
+ break;
266
+ case "upper":
267
+ caseTransformed = normalized.toUpperCase();
268
+ break;
269
+ }
270
+ let result = caseTransformed;
271
+ if (opts.wordReplacements) {
272
+ Object.entries(opts.wordReplacements).forEach(([key, value]) => {
273
+ const regex = new RegExp(`\\b${key}\\b`, "gi");
274
+ result = result.replace(regex, value);
275
+ });
276
+ }
277
+ return result;
278
+ }
279
+
280
+ // core/schema-structure.ts
281
+ function formatBlockLabel(key) {
282
+ return formatText(key, { textCase: "title" });
283
+ }
284
+
285
+ // convert/openai-schema-converter.ts
286
+ function requiredNullableFlags(required, nullable) {
287
+ return {
288
+ ...required ? { required: true } : {},
289
+ ...nullable ? { nullable: true } : {}
290
+ };
291
+ }
292
+ var METADATA_KEYS = /* @__PURE__ */ new Set([
293
+ "description",
294
+ "title",
295
+ "default",
296
+ "examples",
297
+ "format",
298
+ "minimum",
299
+ "maximum",
300
+ "multipleOf",
301
+ "exclusiveMinimum",
302
+ "exclusiveMaximum",
303
+ "minLength",
304
+ "maxLength",
305
+ "minItems",
306
+ "maxItems",
307
+ "pattern",
308
+ "const",
309
+ "$schema",
310
+ "$id",
311
+ "deprecated",
312
+ "readOnly",
313
+ "writeOnly"
314
+ ]);
315
+ function isRecord(value) {
316
+ return typeof value === "object" && value !== null && !Array.isArray(value);
317
+ }
318
+ function deepClone(value) {
319
+ return JSON.parse(JSON.stringify(value));
320
+ }
321
+ function fieldSchemaSummary(field) {
322
+ if (field.type === "enum") {
323
+ return `enum(${field.values.join("|")}${field.open ? "|+any" : ""})${field.required ? "*" : ""}`;
324
+ }
325
+ if (field.type === "array") {
326
+ return `array<${field.itemKinds.join("|")}>${field.required ? "*" : ""}`;
327
+ }
328
+ if (field.type === "inline_object") {
329
+ return `inline{${Object.keys(field.fields).join(",")}}${field.required ? "*" : ""}`;
330
+ }
331
+ if (field.type === "object") {
332
+ return `object:${field.kind}${field.required ? "*" : ""}`;
333
+ }
334
+ if (field.type === "union") {
335
+ const members = [...field.scalars, ...field.kinds ?? []];
336
+ return `union(${members.join("|")})${field.required ? "*" : ""}`;
337
+ }
338
+ if (field.type === "record") {
339
+ return `record(${field.values})${field.required ? "*" : ""}`;
340
+ }
341
+ return `${field.type}${field.required ? "*" : ""}${field.nullable ? "?" : ""}`;
342
+ }
343
+ function resolvePrimaryType(node) {
344
+ const raw = node.type;
345
+ if (typeof raw === "string") {
346
+ const t = raw === "integer" ? "number" : raw;
347
+ return { type: t, nullable: false, members: [t] };
348
+ }
349
+ if (Array.isArray(raw)) {
350
+ const types = raw.filter((t) => typeof t === "string");
351
+ const nullable = types.includes("null");
352
+ const members = [
353
+ ...new Set(
354
+ types.filter((t) => t !== "null").map((t) => t === "integer" ? "number" : t)
355
+ )
356
+ ];
357
+ const primary = members[0] ?? (nullable && types.length === 1 ? "null" : null);
358
+ return { type: primary ?? null, nullable, members };
359
+ }
360
+ if (node.enum) return { type: "string", nullable: false, members: ["string"] };
361
+ if (node.properties)
362
+ return { type: "object", nullable: false, members: ["object"] };
363
+ if (node.items)
364
+ return { type: "array", nullable: false, members: ["array"] };
365
+ return { type: null, nullable: false, members: [] };
366
+ }
367
+ function carriedMetadataKeys(field) {
368
+ if (field === null) return /* @__PURE__ */ new Set();
369
+ const carried = /* @__PURE__ */ new Set(["description", "default"]);
370
+ if (field.type === "number") {
371
+ carried.add("minimum");
372
+ carried.add("maximum");
373
+ carried.add("multipleOf");
374
+ }
375
+ return carried;
376
+ }
377
+ function collectDropped(node, path, carriedField = null) {
378
+ const carried = carriedMetadataKeys(carriedField);
379
+ const dropped = {};
380
+ for (const [key, value] of Object.entries(node)) {
381
+ if (METADATA_KEYS.has(key) && !carried.has(key)) {
382
+ dropped[key] = value;
383
+ }
384
+ }
385
+ if (Object.keys(dropped).length > 0) {
386
+ return [{ path, dropped }];
387
+ }
388
+ return [];
389
+ }
390
+ function attachNodeMetadata(node, field) {
391
+ let out = field;
392
+ if (typeof node.description === "string" && out.description === void 0) {
393
+ out = { ...out, description: node.description };
394
+ }
395
+ if (node.default !== void 0 && out.default === void 0) {
396
+ out = { ...out, default: node.default };
397
+ }
398
+ if (out.type === "number") {
399
+ const bounds = {};
400
+ if (typeof node.minimum === "number" && out.min === void 0) {
401
+ bounds.min = node.minimum;
402
+ }
403
+ if (typeof node.maximum === "number" && out.max === void 0) {
404
+ bounds.max = node.maximum;
405
+ }
406
+ if (typeof node.multipleOf === "number" && out.step === void 0) {
407
+ bounds.step = node.multipleOf;
408
+ }
409
+ if (Object.keys(bounds).length > 0) out = { ...out, ...bounds };
410
+ }
411
+ return out;
412
+ }
413
+ function synthesizeItemKindSlug(schemaName, fieldName) {
414
+ const base = fieldName.endsWith("ies") ? `${fieldName.slice(0, -3)}y` : fieldName.endsWith("s") ? fieldName.slice(0, -1) : fieldName;
415
+ return `${schemaName}_${base}`;
416
+ }
417
+ function makeKindJsonSchemaProperty(kindSlug, strict) {
418
+ const base = {
419
+ type: "string",
420
+ description: "Block discriminator for render pipeline."
421
+ };
422
+ if (strict) {
423
+ return { ...base, const: kindSlug };
424
+ }
425
+ return { ...base, enum: [kindSlug] };
426
+ }
427
+ function injectKindIntoObjectSchema(objectSchema, kindSlug, strict) {
428
+ const clone = deepClone(objectSchema);
429
+ const properties = isRecord(clone.properties) ? { ...clone.properties } : {};
430
+ properties[KIND_KEY] = makeKindJsonSchemaProperty(kindSlug, strict);
431
+ const required = Array.isArray(clone.required) ? clone.required.filter((k) => typeof k === "string") : [];
432
+ const nextRequired = required.includes(KIND_KEY) ? required : [KIND_KEY, ...required];
433
+ return {
434
+ ...clone,
435
+ properties,
436
+ required: nextRequired,
437
+ ...strict ? { additionalProperties: false } : {}
438
+ };
439
+ }
440
+ function injectKindsIntoRootSchema(rootSchema, rootKindSlug, arrayBindings, strict) {
441
+ let updated = injectKindIntoObjectSchema(rootSchema, rootKindSlug, strict);
442
+ if (!isRecord(updated.properties)) {
443
+ return updated;
444
+ }
445
+ const properties = { ...updated.properties };
446
+ for (const binding of arrayBindings) {
447
+ const fieldNode = properties[binding.arrayField];
448
+ if (!isRecord(fieldNode)) continue;
449
+ const items = fieldNode.items;
450
+ const itemNode = Array.isArray(items) ? items[0] : items;
451
+ if (!isRecord(itemNode)) continue;
452
+ const updatedItem = injectKindIntoObjectSchema(
453
+ itemNode,
454
+ binding.itemKindSlug,
455
+ strict
456
+ );
457
+ properties[binding.arrayField] = {
458
+ ...fieldNode,
459
+ items: updatedItem
460
+ };
461
+ }
462
+ return { ...updated, properties };
463
+ }
464
+ function buildAgentSchemaWithRenderBlockSupport(input, rootKindSlug, arrayBindings, strict) {
465
+ if (!isRecord(input)) return null;
466
+ const normalized = normalizeAiSchemaInput(input);
467
+ if (!normalized.rootSchema) return null;
468
+ if (normalized.rootSchema.type !== "object" && !isRecord(normalized.rootSchema.properties)) {
469
+ return deepClone(input);
470
+ }
471
+ const updatedRoot = injectKindsIntoRootSchema(
472
+ normalized.rootSchema,
473
+ rootKindSlug,
474
+ arrayBindings,
475
+ strict
476
+ );
477
+ if (isRecord(input.schema) && typeof input.name === "string") {
478
+ return {
479
+ ...deepClone(input),
480
+ schema: updatedRoot
481
+ };
482
+ }
483
+ if (isRecord(input.json_schema)) {
484
+ const inner = buildAgentSchemaWithRenderBlockSupport(
485
+ input.json_schema,
486
+ rootKindSlug,
487
+ arrayBindings,
488
+ strict
489
+ );
490
+ return inner ? { ...deepClone(input), json_schema: inner } : null;
491
+ }
492
+ if (typeof input.name === "string") {
493
+ return {
494
+ ...deepClone(input),
495
+ schema: updatedRoot
496
+ };
497
+ }
498
+ return updatedRoot;
499
+ }
500
+ function resolveRef(ref, ctx) {
501
+ if (ref === "#" || ref === "#/") {
502
+ return { slug: ctx.schemaName, node: ctx.rootSchema };
503
+ }
504
+ const match = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
505
+ if (!match) return null;
506
+ const name = decodeURIComponent(
507
+ (match[1] ?? "").replace(/~1/g, "/").replace(/~0/g, "~")
508
+ );
509
+ const node = ctx.defs[name];
510
+ if (!isRecord(node)) return null;
511
+ const declared = isRecord(node.properties) ? readBlockKindFromProperties(node.properties) : null;
512
+ return { slug: declared ?? name, node };
513
+ }
514
+ function refToObjectField(resolved, path, ctx) {
515
+ if (ctx.refsInProgress.has(resolved.slug)) return;
516
+ ctx.refsInProgress.add(resolved.slug);
517
+ try {
518
+ registerDeclaredKindDraft(resolved.slug, resolved.node, path, ctx);
519
+ } finally {
520
+ ctx.refsInProgress.delete(resolved.slug);
521
+ }
522
+ }
523
+ function isAnyValueSchema(node) {
524
+ return node.type === void 0 && node.enum === void 0 && node.const === void 0 && node.properties === void 0 && node.items === void 0 && node.additionalProperties === void 0 && node.anyOf === void 0 && node.oneOf === void 0 && node.allOf === void 0 && node.$ref === void 0;
525
+ }
526
+ function registerDeclaredKindDraft(declaredKind, objectNode, path, ctx) {
527
+ if (ctx.blockSchemas.some((draft) => draft.slug === declaredKind)) return;
528
+ if (!isRecord(objectNode.properties)) return;
529
+ const memberRequired = new Set(
530
+ Array.isArray(objectNode.required) ? objectNode.required.filter((k) => typeof k === "string") : []
531
+ );
532
+ const fields = {};
533
+ for (const [propName, propNode] of Object.entries(objectNode.properties)) {
534
+ if (!isRecord(propNode)) continue;
535
+ if (propName === KIND_KEY) continue;
536
+ fields[propName] = convertFieldOrWiden(
537
+ propName,
538
+ propNode,
539
+ memberRequired.has(propName),
540
+ `${path}.${propName}`,
541
+ ctx
542
+ );
543
+ }
544
+ ctx.blockSchemas.push({
545
+ slug: declaredKind,
546
+ label: formatBlockLabel(declaredKind),
547
+ fields
548
+ });
549
+ }
550
+ function convertFieldOrWiden(fieldName, node, required, path, ctx) {
551
+ const before = ctx.problems.length;
552
+ const converted = convertProperty(fieldName, node, required, path, ctx);
553
+ if (converted) return converted;
554
+ for (let i = before; i < ctx.problems.length; i++) {
555
+ const problem = ctx.problems[i];
556
+ if (problem && problem.severity === "error") problem.severity = "warning";
557
+ }
558
+ ctx.problems.push({
559
+ severity: "warning",
560
+ path,
561
+ message: `Field "${fieldName}" has no exact field type \u2014 carried as any JSON value (json) rather than dropped from the kind.`
562
+ });
563
+ return { ...requiredNullableFlags(required), type: "json" };
564
+ }
565
+ function convertProperty(fieldName, node, required, path, ctx) {
566
+ const core = convertPropertyCore(fieldName, node, required, path, ctx);
567
+ const field = core === null ? null : attachNodeMetadata(node, core);
568
+ ctx.droppedMetadata.push(...collectDropped(node, path, field));
569
+ return field;
570
+ }
571
+ function convertPropertyCore(fieldName, node, required, path, ctx) {
572
+ if (typeof node.$ref === "string") {
573
+ const resolved = resolveRef(node.$ref, ctx);
574
+ if (!resolved) {
575
+ ctx.problems.push({
576
+ severity: "error",
577
+ path,
578
+ message: `Unresolvable $ref ("${node.$ref}") \u2014 only "#", "#/$defs/<name>" and "#/definitions/<name>" are supported.`
579
+ });
580
+ return null;
581
+ }
582
+ refToObjectField(resolved, path, ctx);
583
+ return {
584
+ ...requiredNullableFlags(required),
585
+ type: "object",
586
+ kind: resolved.slug
587
+ };
588
+ }
589
+ if (Array.isArray(node.anyOf) || Array.isArray(node.oneOf)) {
590
+ const variants = node.anyOf ?? node.oneOf;
591
+ const scalarTypes = /* @__PURE__ */ new Set();
592
+ const enumVariantSets = [];
593
+ const memberKinds = [];
594
+ const anonymousObjects = [];
595
+ let sawNull = false;
596
+ let unsupported = false;
597
+ for (const variant of variants) {
598
+ if (!isRecord(variant)) {
599
+ unsupported = true;
600
+ continue;
601
+ }
602
+ if (typeof variant.$ref === "string") {
603
+ const resolvedVariant = resolveRef(variant.$ref, ctx);
604
+ if (!resolvedVariant) {
605
+ ctx.problems.push({
606
+ severity: "error",
607
+ path,
608
+ message: `Unresolvable $ref inside anyOf/oneOf ("${variant.$ref}").`
609
+ });
610
+ unsupported = true;
611
+ continue;
612
+ }
613
+ refToObjectField(resolvedVariant, path, ctx);
614
+ memberKinds.push(resolvedVariant.slug);
615
+ continue;
616
+ }
617
+ const { type: type2, nullable: nullable2 } = resolvePrimaryType(variant);
618
+ if (nullable2) sawNull = true;
619
+ if (type2 === "null") {
620
+ sawNull = true;
621
+ continue;
622
+ }
623
+ if (type2 === "string" && Array.isArray(variant.enum)) {
624
+ enumVariantSets.push(
625
+ variant.enum.filter((v) => typeof v === "string")
626
+ );
627
+ continue;
628
+ }
629
+ if (type2 === "string" || type2 === "number" || type2 === "boolean") {
630
+ scalarTypes.add(type2);
631
+ continue;
632
+ }
633
+ if (type2 === "object" && isRecord(variant.properties)) {
634
+ const declared = readBlockKindFromProperties(variant.properties);
635
+ if (declared) {
636
+ memberKinds.push(declared);
637
+ registerDeclaredKindDraft(declared, variant, `${path}<${declared}>`, ctx);
638
+ } else {
639
+ anonymousObjects.push(variant);
640
+ }
641
+ continue;
642
+ }
643
+ unsupported = true;
644
+ }
645
+ if (unsupported) {
646
+ ctx.problems.push({
647
+ severity: "error",
648
+ path,
649
+ message: "anyOf/oneOf with unsupported variants cannot be converted automatically."
650
+ });
651
+ return null;
652
+ }
653
+ if (enumVariantSets.length > 0 && anonymousObjects.length === 0 && memberKinds.length === 0 && [...scalarTypes].every((s) => s === "string")) {
654
+ const values = [...new Set(enumVariantSets.flat())];
655
+ const open = scalarTypes.has("string");
656
+ return {
657
+ ...requiredNullableFlags(required, sawNull),
658
+ type: "enum",
659
+ values,
660
+ ...open ? { open: true } : {}
661
+ };
662
+ }
663
+ if (enumVariantSets.length > 0) {
664
+ ctx.problems.push({
665
+ severity: "warning",
666
+ path,
667
+ message: "anyOf/oneOf mixes an enum variant with non-string members \u2014 enum widened to string within the union."
668
+ });
669
+ scalarTypes.add("string");
670
+ }
671
+ if (anonymousObjects.length === 1 && scalarTypes.size === 0 && memberKinds.length === 0) {
672
+ const [sole] = anonymousObjects;
673
+ const converted = sole ? convertProperty(fieldName, sole, required, path, ctx) : null;
674
+ if (!converted) return null;
675
+ return sawNull ? { ...converted, nullable: true } : converted;
676
+ }
677
+ if (anonymousObjects.length > 0) {
678
+ ctx.problems.push({
679
+ severity: "error",
680
+ path,
681
+ message: "anyOf/oneOf mixing anonymous objects with other variants cannot be converted \u2014 declare __kind on each object variant."
682
+ });
683
+ return null;
684
+ }
685
+ if (scalarTypes.size === 1 && memberKinds.length === 0) {
686
+ const [scalar] = [...scalarTypes];
687
+ if (scalar) {
688
+ return { ...requiredNullableFlags(required, sawNull), type: scalar };
689
+ }
690
+ }
691
+ if (scalarTypes.size > 0 || memberKinds.length > 0) {
692
+ ctx.problems.push({
693
+ severity: "warning",
694
+ path,
695
+ message: `Converted anyOf/oneOf to union of: ${[
696
+ ...scalarTypes,
697
+ ...memberKinds
698
+ ].join(", ")}.`
699
+ });
700
+ return {
701
+ ...requiredNullableFlags(required, sawNull),
702
+ type: "union",
703
+ scalars: [...scalarTypes],
704
+ ...memberKinds.length > 0 ? { kinds: memberKinds } : {}
705
+ };
706
+ }
707
+ ctx.problems.push({
708
+ severity: "warning",
709
+ path,
710
+ message: "anyOf/oneOf carried only null variants \u2014 widened to json (any value)."
711
+ });
712
+ return { ...requiredNullableFlags(required), type: "json" };
713
+ }
714
+ if (Array.isArray(node.allOf)) {
715
+ ctx.problems.push({
716
+ severity: "warning",
717
+ path,
718
+ message: "allOf merged using first object branch only."
719
+ });
720
+ const objectBranch = node.allOf.find(
721
+ (b) => b.properties
722
+ );
723
+ if (objectBranch) {
724
+ return convertProperty(fieldName, objectBranch, required, path, ctx);
725
+ }
726
+ }
727
+ if (isAnyValueSchema(node)) {
728
+ ctx.problems.push({
729
+ severity: "info",
730
+ path,
731
+ message: `Typeless schema at "${path || "(root)"}" \u2014 any JSON value (json).`
732
+ });
733
+ return { ...requiredNullableFlags(required), type: "json" };
734
+ }
735
+ const { type, nullable, members } = resolvePrimaryType(node);
736
+ if (members.length > 1) {
737
+ const objectish = members.some((m) => m === "object" || m === "array");
738
+ if (objectish) {
739
+ ctx.problems.push({
740
+ severity: "info",
741
+ path,
742
+ message: `Union of [${members.join(", ")}] at "${path || "(root)"}" spans objects/arrays \u2014 carried as any JSON value (json).`
743
+ });
744
+ return { ...requiredNullableFlags(required), type: "json" };
745
+ }
746
+ const scalars = members.filter(
747
+ (m) => m === "string" || m === "number" || m === "boolean"
748
+ );
749
+ if (scalars.length === members.length && scalars.length > 1) {
750
+ return {
751
+ ...requiredNullableFlags(required, nullable),
752
+ type: "union",
753
+ scalars
754
+ };
755
+ }
756
+ ctx.problems.push({
757
+ severity: "warning",
758
+ path,
759
+ message: `Union of [${members.join(", ")}] at "${path || "(root)"}" has no exact field type \u2014 carried as any JSON value (json) rather than narrowed to "${type}".`
760
+ });
761
+ return { ...requiredNullableFlags(required), type: "json" };
762
+ }
763
+ if (type === "string") {
764
+ if (Array.isArray(node.enum)) {
765
+ const values = node.enum.filter(
766
+ (v) => typeof v === "string"
767
+ );
768
+ if (values.length !== node.enum.length) {
769
+ ctx.problems.push({
770
+ severity: "warning",
771
+ path,
772
+ message: "Enum contains non-string values; non-strings dropped."
773
+ });
774
+ }
775
+ return {
776
+ ...requiredNullableFlags(required, nullable),
777
+ type: "enum",
778
+ values
779
+ };
780
+ }
781
+ return {
782
+ ...requiredNullableFlags(required, nullable),
783
+ type: "string"
784
+ };
785
+ }
786
+ if (type === "number") {
787
+ return {
788
+ ...requiredNullableFlags(required, nullable),
789
+ type: "number"
790
+ };
791
+ }
792
+ if (type === "boolean") {
793
+ return {
794
+ ...requiredNullableFlags(required, nullable),
795
+ type: "boolean"
796
+ };
797
+ }
798
+ if (type === "array") {
799
+ const items = node.items;
800
+ if (!items) {
801
+ ctx.problems.push({
802
+ severity: "error",
803
+ path,
804
+ message: "Array field is missing items schema."
805
+ });
806
+ return null;
807
+ }
808
+ const itemNode = Array.isArray(items) ? items[0] : items;
809
+ if (!isRecord(itemNode)) {
810
+ ctx.problems.push({
811
+ severity: "error",
812
+ path,
813
+ message: "Array items schema must be an object."
814
+ });
815
+ return null;
816
+ }
817
+ if (typeof itemNode.$ref === "string") {
818
+ const resolvedItem = resolveRef(itemNode.$ref, ctx);
819
+ if (!resolvedItem) {
820
+ ctx.problems.push({
821
+ severity: "error",
822
+ path: `${path}[]`,
823
+ message: `Unresolvable $ref in array items ("${itemNode.$ref}").`
824
+ });
825
+ return null;
826
+ }
827
+ refToObjectField(resolvedItem, `${path}[]`, ctx);
828
+ ctx.arrayBindings.push({
829
+ arrayField: fieldName,
830
+ itemKindSlug: resolvedItem.slug
831
+ });
832
+ return {
833
+ ...requiredNullableFlags(required, nullable),
834
+ type: "array",
835
+ itemKinds: [resolvedItem.slug]
836
+ };
837
+ }
838
+ if (isAnyValueSchema(itemNode)) {
839
+ return {
840
+ ...requiredNullableFlags(required, nullable),
841
+ type: "json[]"
842
+ };
843
+ }
844
+ const itemVariants = Array.isArray(itemNode.anyOf) ? itemNode.anyOf : Array.isArray(itemNode.oneOf) ? itemNode.oneOf : null;
845
+ if (itemVariants) {
846
+ const itemEnumSets = [];
847
+ let itemPlainString = false;
848
+ let itemsAllString = true;
849
+ for (const variant of itemVariants) {
850
+ if (!isRecord(variant) || resolvePrimaryType(variant).type !== "string") {
851
+ itemsAllString = false;
852
+ break;
853
+ }
854
+ if (Array.isArray(variant.enum)) {
855
+ itemEnumSets.push(
856
+ variant.enum.filter((v) => typeof v === "string")
857
+ );
858
+ } else {
859
+ itemPlainString = true;
860
+ }
861
+ }
862
+ if (itemsAllString && itemEnumSets.length > 0) {
863
+ return {
864
+ ...requiredNullableFlags(required, nullable),
865
+ type: "string[]",
866
+ values: [...new Set(itemEnumSets.flat())],
867
+ ...itemPlainString ? { open: true } : {}
868
+ };
869
+ }
870
+ const itemKinds = [];
871
+ for (const variant of itemVariants) {
872
+ if (isRecord(variant) && typeof variant.$ref === "string") {
873
+ const resolvedVariant = resolveRef(variant.$ref, ctx);
874
+ if (!resolvedVariant) {
875
+ ctx.problems.push({
876
+ severity: "error",
877
+ path: `${path}[]`,
878
+ message: `Unresolvable $ref in array items anyOf ("${variant.$ref}").`
879
+ });
880
+ return null;
881
+ }
882
+ itemKinds.push(resolvedVariant.slug);
883
+ refToObjectField(resolvedVariant, `${path}[]<${resolvedVariant.slug}>`, ctx);
884
+ ctx.arrayBindings.push({
885
+ arrayField: fieldName,
886
+ itemKindSlug: resolvedVariant.slug
887
+ });
888
+ continue;
889
+ }
890
+ if (!isRecord(variant) || !isRecord(variant.properties)) {
891
+ ctx.problems.push({
892
+ severity: "error",
893
+ path: `${path}[]`,
894
+ message: "Array items anyOf/oneOf variants must be inline objects declaring __kind, or $refs to defs."
895
+ });
896
+ return null;
897
+ }
898
+ const declared = readBlockKindFromProperties(variant.properties);
899
+ if (!declared) {
900
+ ctx.problems.push({
901
+ severity: "error",
902
+ path: `${path}[]`,
903
+ message: "Array items anyOf/oneOf variant is missing a __kind const/enum declaration."
904
+ });
905
+ return null;
906
+ }
907
+ itemKinds.push(declared);
908
+ registerDeclaredKindDraft(declared, variant, `${path}[]<${declared}>`, ctx);
909
+ ctx.arrayBindings.push({ arrayField: fieldName, itemKindSlug: declared });
910
+ }
911
+ return {
912
+ ...requiredNullableFlags(required, nullable),
913
+ type: "array",
914
+ itemKinds
915
+ };
916
+ }
917
+ const itemType = resolvePrimaryType(itemNode).type;
918
+ if (itemType === "string") {
919
+ if (Array.isArray(itemNode.enum)) {
920
+ return {
921
+ ...requiredNullableFlags(required, nullable),
922
+ type: "string[]",
923
+ values: itemNode.enum.filter(
924
+ (v) => typeof v === "string"
925
+ )
926
+ };
927
+ }
928
+ return {
929
+ ...requiredNullableFlags(required, nullable),
930
+ type: "string[]"
931
+ };
932
+ }
933
+ if (itemType === "number") {
934
+ return {
935
+ ...requiredNullableFlags(required, nullable),
936
+ type: "number[]"
937
+ };
938
+ }
939
+ if (itemType === "boolean") {
940
+ return {
941
+ ...requiredNullableFlags(required, nullable),
942
+ type: "boolean[]"
943
+ };
944
+ }
945
+ if (itemType === "object" && isRecord(itemNode.properties)) {
946
+ const declaredItemKind = readBlockKindFromProperties(itemNode.properties);
947
+ const itemKindSlug = declaredItemKind ?? synthesizeItemKindSlug(ctx.schemaName, fieldName);
948
+ const itemRequired = new Set(
949
+ Array.isArray(itemNode.required) ? itemNode.required.filter((k) => typeof k === "string") : []
950
+ );
951
+ const itemFields = {};
952
+ for (const [propName, propNode] of Object.entries(itemNode.properties)) {
953
+ if (!isRecord(propNode)) continue;
954
+ if (propName === KIND_KEY) continue;
955
+ itemFields[propName] = convertFieldOrWiden(
956
+ propName,
957
+ propNode,
958
+ itemRequired.has(propName),
959
+ `${path}[].${propName}`,
960
+ ctx
961
+ );
962
+ }
963
+ const alreadyHasBlockKind = propNameIsBlockKind(itemNode.properties) || itemRequired.has(KIND_KEY);
964
+ ctx.arrayBindings.push({
965
+ arrayField: fieldName,
966
+ itemKindSlug
967
+ });
968
+ if (!ctx.blockSchemas.some((draft) => draft.slug === itemKindSlug)) {
969
+ ctx.blockSchemas.push({
970
+ slug: itemKindSlug,
971
+ label: declaredItemKind ? formatBlockLabel(itemKindSlug) : formatBlockLabel(`${ctx.schemaName}_${fieldName}_item`),
972
+ fields: itemFields
973
+ });
974
+ }
975
+ if (!alreadyHasBlockKind) {
976
+ ctx.problems.push({
977
+ severity: "warning",
978
+ path: `${path}[]`,
979
+ message: `Array "${fieldName}" items need __kind:"${itemKindSlug}" at runtime (OPTION 1: server injects, OPTION 2: use agent schema with __kind).`
980
+ });
981
+ }
982
+ return {
983
+ ...requiredNullableFlags(required, nullable),
984
+ type: "array",
985
+ itemKinds: [itemKindSlug]
986
+ };
987
+ }
988
+ ctx.problems.push({
989
+ severity: "error",
990
+ path,
991
+ message: `Unsupported array items type "${itemType ?? "unknown"}".`
992
+ });
993
+ return null;
994
+ }
995
+ if (type === "object") {
996
+ const ap = node.additionalProperties;
997
+ const apIsOpen = ap === true || isRecord(ap) && isAnyValueSchema(ap);
998
+ if (isRecord(node.properties)) {
999
+ const nestedRequired = new Set(
1000
+ Array.isArray(node.required) ? node.required.filter((k) => typeof k === "string") : []
1001
+ );
1002
+ const nestedFields = {};
1003
+ for (const [propName, propNode] of Object.entries(node.properties)) {
1004
+ if (!isRecord(propNode)) continue;
1005
+ if (propName === KIND_KEY) continue;
1006
+ nestedFields[propName] = convertFieldOrWiden(
1007
+ propName,
1008
+ propNode,
1009
+ nestedRequired.has(propName),
1010
+ `${path}.${propName}`,
1011
+ ctx
1012
+ );
1013
+ }
1014
+ const referencedKind = readBlockKindFromProperties(node.properties);
1015
+ if (referencedKind) {
1016
+ if (!ctx.refsInProgress.has(referencedKind)) {
1017
+ ctx.refsInProgress.add(referencedKind);
1018
+ try {
1019
+ registerDeclaredKindDraft(referencedKind, node, path, ctx);
1020
+ } finally {
1021
+ ctx.refsInProgress.delete(referencedKind);
1022
+ }
1023
+ }
1024
+ return {
1025
+ ...requiredNullableFlags(required, nullable),
1026
+ type: "object",
1027
+ kind: referencedKind
1028
+ };
1029
+ }
1030
+ if (Object.keys(nestedFields).length === 0 && !apIsOpen && isRecord(ap) && KIND_KEY in node.properties) {
1031
+ const apType = resolvePrimaryType(ap).type;
1032
+ return {
1033
+ ...requiredNullableFlags(required, nullable),
1034
+ type: "record",
1035
+ values: apType === "string" || apType === "number" || apType === "boolean" ? apType : "json"
1036
+ };
1037
+ }
1038
+ let open = apIsOpen;
1039
+ if (!apIsOpen && isRecord(ap)) {
1040
+ ctx.problems.push({
1041
+ severity: "warning",
1042
+ path,
1043
+ message: "Typed additionalProperties alongside declared properties is not representable \u2014 treated as an OPEN object (extra values unconstrained)."
1044
+ });
1045
+ open = true;
1046
+ } else if (ap === false) {
1047
+ ctx.droppedMetadata.push({
1048
+ path,
1049
+ dropped: { additionalProperties: false }
1050
+ });
1051
+ }
1052
+ return {
1053
+ ...requiredNullableFlags(required, nullable),
1054
+ type: "inline_object",
1055
+ fields: nestedFields,
1056
+ ...open ? { open: true } : {}
1057
+ };
1058
+ }
1059
+ if (apIsOpen || ap === void 0) {
1060
+ if (ap === void 0) {
1061
+ ctx.problems.push({
1062
+ severity: "info",
1063
+ path,
1064
+ message: `Bare object schema at "${path || "(root)"}" \u2014 record of any JSON values.`
1065
+ });
1066
+ }
1067
+ return {
1068
+ ...requiredNullableFlags(required, nullable),
1069
+ type: "record",
1070
+ values: "json"
1071
+ };
1072
+ }
1073
+ if (isRecord(ap)) {
1074
+ const apType = resolvePrimaryType(ap).type;
1075
+ if (apType === "string" || apType === "number" || apType === "boolean") {
1076
+ return {
1077
+ ...requiredNullableFlags(required, nullable),
1078
+ type: "record",
1079
+ values: apType
1080
+ };
1081
+ }
1082
+ ctx.problems.push({
1083
+ severity: "warning",
1084
+ path,
1085
+ message: `Record value schema at "${path}" is not scalar \u2014 widened to record of any JSON values.`
1086
+ });
1087
+ return {
1088
+ ...requiredNullableFlags(required, nullable),
1089
+ type: "record",
1090
+ values: "json"
1091
+ };
1092
+ }
1093
+ return {
1094
+ ...requiredNullableFlags(required, nullable),
1095
+ type: "inline_object",
1096
+ fields: {}
1097
+ };
1098
+ }
1099
+ ctx.problems.push({
1100
+ severity: "error",
1101
+ path,
1102
+ message: `Unsupported or missing JSON Schema type at "${path}".`
1103
+ });
1104
+ return null;
1105
+ }
1106
+ function propNameIsBlockKind(properties) {
1107
+ return KIND_KEY in properties;
1108
+ }
1109
+ function readBlockKindFromProperties(properties) {
1110
+ const kindProp = properties[KIND_KEY];
1111
+ if (!isRecord(kindProp)) return null;
1112
+ if (typeof kindProp.const === "string") return kindProp.const;
1113
+ if (Array.isArray(kindProp.enum) && typeof kindProp.enum[0] === "string") {
1114
+ return kindProp.enum[0];
1115
+ }
1116
+ return null;
1117
+ }
1118
+ function normalizeAiSchemaInput(input) {
1119
+ const parseErrors = [];
1120
+ if (!isRecord(input)) {
1121
+ return {
1122
+ name: null,
1123
+ strict: null,
1124
+ rootSchema: null,
1125
+ parseErrors: ["Input must be a JSON object."]
1126
+ };
1127
+ }
1128
+ if (isRecord(input.json_schema)) {
1129
+ return normalizeAiSchemaInput(input.json_schema);
1130
+ }
1131
+ if (isRecord(input.schema) && typeof input.name === "string") {
1132
+ return {
1133
+ name: input.name,
1134
+ strict: typeof input.strict === "boolean" ? input.strict : null,
1135
+ rootSchema: input.schema,
1136
+ parseErrors: []
1137
+ };
1138
+ }
1139
+ if (typeof input.type === "string" || Array.isArray(input.type) || input.properties || input.items) {
1140
+ const name = typeof input.name === "string" ? input.name : typeof input.title === "string" ? input.title : null;
1141
+ return {
1142
+ name,
1143
+ strict: typeof input.strict === "boolean" ? input.strict : null,
1144
+ rootSchema: input,
1145
+ parseErrors: []
1146
+ };
1147
+ }
1148
+ parseErrors.push(
1149
+ "Expected OpenAI output_schema shape { name, schema } or a root JSON Schema object."
1150
+ );
1151
+ return { name: null, strict: null, rootSchema: null, parseErrors };
1152
+ }
1153
+ function convertAiSchemaToBlockFields(schemaName, rootSchema, strict) {
1154
+ const rawDefs = isRecord(rootSchema.$defs) ? rootSchema.$defs : isRecord(rootSchema.definitions) ? rootSchema.definitions : {};
1155
+ const defs = {};
1156
+ for (const [name, node] of Object.entries(rawDefs)) {
1157
+ if (isRecord(node)) defs[name] = node;
1158
+ }
1159
+ const ctx = {
1160
+ schemaName,
1161
+ strict,
1162
+ problems: [],
1163
+ droppedMetadata: [],
1164
+ blockSchemas: [],
1165
+ arrayBindings: [],
1166
+ defs,
1167
+ rootSchema,
1168
+ refsInProgress: /* @__PURE__ */ new Set()
1169
+ };
1170
+ ctx.droppedMetadata.push(...collectDropped(rootSchema, ""));
1171
+ const rootAp = rootSchema.additionalProperties;
1172
+ const rootIsOpen = rootAp === true || isRecord(rootAp) && isAnyValueSchema(rootAp);
1173
+ const properties = rootSchema.properties;
1174
+ if (!isRecord(properties) || rootIsOpen) {
1175
+ const rootField = convertProperty("$root", rootSchema, false, "$root", ctx);
1176
+ if (!rootField) {
1177
+ ctx.problems.push({
1178
+ severity: "error",
1179
+ path: "",
1180
+ message: "Root schema could not be converted (see problems above) \u2014 expected an object with properties, a scalar/array/json root, or an open object."
1181
+ });
1182
+ return emptyConversionResult(schemaName, strict, ctx);
1183
+ }
1184
+ ctx.blockSchemas.unshift({
1185
+ slug: schemaName,
1186
+ label: formatBlockLabel(schemaName),
1187
+ fields: {},
1188
+ root: rootField
1189
+ });
1190
+ return {
1191
+ schemaName,
1192
+ strict,
1193
+ blockSchemas: ctx.blockSchemas,
1194
+ problems: ctx.problems,
1195
+ droppedMetadata: ctx.droppedMetadata
1196
+ };
1197
+ }
1198
+ const required = new Set(
1199
+ Array.isArray(rootSchema.required) ? rootSchema.required.filter((k) => typeof k === "string") : []
1200
+ );
1201
+ const convertedFields = {};
1202
+ for (const [fieldName, fieldNode] of Object.entries(properties)) {
1203
+ if (!isRecord(fieldNode)) continue;
1204
+ if (fieldName === KIND_KEY) continue;
1205
+ convertedFields[fieldName] = convertFieldOrWiden(
1206
+ fieldName,
1207
+ fieldNode,
1208
+ required.has(fieldName),
1209
+ fieldName,
1210
+ ctx
1211
+ );
1212
+ }
1213
+ const rootHasKind = propNameIsBlockKind(properties) || required.has(KIND_KEY);
1214
+ if (!rootHasKind) {
1215
+ ctx.problems.push({
1216
+ severity: "warning",
1217
+ path: "",
1218
+ message: `Root object needs __kind:"${schemaName}" at runtime (OPTION 1: server injects, OPTION 2: use agent schema with __kind).`
1219
+ });
1220
+ }
1221
+ const rootDraft = {
1222
+ slug: schemaName,
1223
+ label: formatBlockLabel(schemaName),
1224
+ fields: convertedFields
1225
+ };
1226
+ ctx.blockSchemas.unshift(rootDraft);
1227
+ if (typeof rootSchema.additionalProperties === "boolean") {
1228
+ ctx.droppedMetadata.push({
1229
+ path: "",
1230
+ dropped: { additionalProperties: rootSchema.additionalProperties }
1231
+ });
1232
+ }
1233
+ if (strict) {
1234
+ ctx.droppedMetadata.push({
1235
+ path: "",
1236
+ dropped: { strict }
1237
+ });
1238
+ }
1239
+ return {
1240
+ schemaName,
1241
+ strict,
1242
+ blockSchemas: ctx.blockSchemas,
1243
+ problems: ctx.problems,
1244
+ droppedMetadata: ctx.droppedMetadata
1245
+ };
1246
+ }
1247
+ function emptyConversionResult(schemaName, strict, ctx) {
1248
+ return {
1249
+ schemaName,
1250
+ strict,
1251
+ blockSchemas: ctx.blockSchemas,
1252
+ problems: ctx.problems,
1253
+ droppedMetadata: ctx.droppedMetadata
1254
+ };
1255
+ }
1256
+ function compareFieldSchemas(aiField, blockField, fieldName) {
1257
+ const aiPresent = aiField !== void 0;
1258
+ const blockPresent = blockField !== void 0;
1259
+ const aiSummary = aiField ? fieldSchemaSummary(aiField) : null;
1260
+ const blockSummary = blockField ? fieldSchemaSummary(blockField) : null;
1261
+ if (aiPresent && blockPresent) {
1262
+ if (aiSummary === blockSummary) {
1263
+ return {
1264
+ field: fieldName,
1265
+ aiPresent,
1266
+ blockPresent,
1267
+ aiSummary,
1268
+ blockSummary,
1269
+ status: "match"
1270
+ };
1271
+ }
1272
+ const aiRicher = aiField?.type === "enum" && blockField?.type === "string" || aiField?.type === "inline_object" && blockField?.type !== "inline_object";
1273
+ const blockRicher = blockField?.type === "enum" && aiField?.type === "string" || blockField?.required && !aiField?.required;
1274
+ return {
1275
+ field: fieldName,
1276
+ aiPresent,
1277
+ blockPresent,
1278
+ aiSummary,
1279
+ blockSummary,
1280
+ status: aiRicher ? "ai_richer" : blockRicher ? "block_richer" : "type_mismatch",
1281
+ ...aiSummary !== blockSummary && {
1282
+ detail: `${aiSummary} vs ${blockSummary}`
1283
+ }
1284
+ };
1285
+ }
1286
+ if (aiPresent) {
1287
+ return {
1288
+ field: fieldName,
1289
+ aiPresent,
1290
+ blockPresent,
1291
+ aiSummary,
1292
+ blockSummary,
1293
+ status: "ai_only"
1294
+ };
1295
+ }
1296
+ return {
1297
+ field: fieldName,
1298
+ aiPresent,
1299
+ blockPresent,
1300
+ aiSummary,
1301
+ blockSummary,
1302
+ status: "block_only"
1303
+ };
1304
+ }
1305
+ function compareWithExistingKindSchema(convertedFields, existing) {
1306
+ if (!existing) return [];
1307
+ const allFields = /* @__PURE__ */ new Set([
1308
+ ...Object.keys(convertedFields),
1309
+ ...Object.keys(existing.fields)
1310
+ ]);
1311
+ return [...allFields].sort().map(
1312
+ (field) => compareFieldSchemas(
1313
+ convertedFields[field],
1314
+ existing.fields[field],
1315
+ field
1316
+ )
1317
+ );
1318
+ }
1319
+ function runSchemaConversion(input, existingSchemas) {
1320
+ const normalized = normalizeAiSchemaInput(input);
1321
+ if (!normalized.rootSchema || !normalized.name) {
1322
+ return {
1323
+ schemaName: normalized.name,
1324
+ strict: normalized.strict,
1325
+ blockSchemas: [],
1326
+ agentSchemaWithKinds: null,
1327
+ problems: [],
1328
+ droppedMetadata: [],
1329
+ comparisons: [],
1330
+ parseErrors: normalized.parseErrors.length ? normalized.parseErrors : ["Schema name and root schema are required."]
1331
+ };
1332
+ }
1333
+ const strict = normalized.strict ?? false;
1334
+ const core = convertAiSchemaToBlockFields(
1335
+ normalized.name,
1336
+ normalized.rootSchema,
1337
+ strict
1338
+ );
1339
+ const existing = existingSchemas[normalized.name] ?? null;
1340
+ const rootDraft = core.blockSchemas[0];
1341
+ const comparisons = rootDraft ? compareWithExistingKindSchema(rootDraft.fields, existing) : [];
1342
+ const problems = [...core.problems];
1343
+ if (!existing) {
1344
+ problems.push({
1345
+ severity: "info",
1346
+ path: "",
1347
+ message: `No existing block schema with slug "${normalized.name}".`
1348
+ });
1349
+ }
1350
+ const agentSchemaWithKinds = buildAgentSchemaWithRenderBlockSupport(
1351
+ input,
1352
+ normalized.name,
1353
+ collectArrayBindingsFromDrafts(core.blockSchemas, normalized.name),
1354
+ strict
1355
+ );
1356
+ return {
1357
+ ...core,
1358
+ agentSchemaWithKinds,
1359
+ comparisons,
1360
+ problems,
1361
+ parseErrors: []
1362
+ };
1363
+ }
1364
+ function collectArrayBindingsFromDrafts(drafts, rootSlug) {
1365
+ const root = drafts.find((d) => d.slug === rootSlug);
1366
+ if (!root) return [];
1367
+ const bindings = [];
1368
+ for (const [fieldName, field] of Object.entries(root.fields)) {
1369
+ if (field.type !== "array") continue;
1370
+ for (const itemKind of field.itemKinds) {
1371
+ bindings.push({ arrayField: fieldName, itemKindSlug: itemKind });
1372
+ }
1373
+ }
1374
+ return bindings;
1375
+ }
1376
+ function validateBlockSchemaSavePlan(blockSchemas, existingSlugs, hasConversionErrors) {
1377
+ const errors = [];
1378
+ const normalizedExisting = new Set(
1379
+ existingSlugs.map((s) => s.trim().toLowerCase())
1380
+ );
1381
+ const batchSlugs = /* @__PURE__ */ new Set();
1382
+ const itemKindRefs = [];
1383
+ for (const draft of blockSchemas) {
1384
+ const slug = draft.slug.trim();
1385
+ const normalized = slug.toLowerCase();
1386
+ if (!slug) {
1387
+ errors.push("Every block schema must have a non-empty slug.");
1388
+ continue;
1389
+ }
1390
+ if (batchSlugs.has(normalized)) {
1391
+ errors.push(`Duplicate slug in conversion batch: "${slug}".`);
1392
+ }
1393
+ batchSlugs.add(normalized);
1394
+ }
1395
+ const entries = blockSchemas.map((draft) => {
1396
+ const existsInDb = normalizedExisting.has(draft.slug.trim().toLowerCase());
1397
+ return {
1398
+ draft,
1399
+ existsInDb,
1400
+ willSave: !existsInDb
1401
+ };
1402
+ });
1403
+ for (const draft of blockSchemas) {
1404
+ for (const [fieldName, field] of Object.entries(draft.fields)) {
1405
+ if (field.type !== "array") continue;
1406
+ for (const itemKind of field.itemKinds) {
1407
+ const inBatch = batchSlugs.has(itemKind.trim().toLowerCase());
1408
+ const inDb = normalizedExisting.has(itemKind.trim().toLowerCase());
1409
+ const satisfied = inBatch || inDb;
1410
+ itemKindRefs.push({
1411
+ parentSlug: draft.slug,
1412
+ field: fieldName,
1413
+ itemKind,
1414
+ satisfied,
1415
+ source: inBatch ? "batch" : inDb ? "database" : "missing"
1416
+ });
1417
+ if (!satisfied) {
1418
+ errors.push(
1419
+ `"${draft.slug}".${fieldName} references itemKind "${itemKind}" \u2014 not in this batch and not in DB.`
1420
+ );
1421
+ }
1422
+ }
1423
+ }
1424
+ }
1425
+ const newCount = entries.filter((e) => e.willSave).length;
1426
+ if (newCount === 0 && blockSchemas.length > 0) {
1427
+ errors.push("All block schema slugs already exist in the database.");
1428
+ }
1429
+ if (hasConversionErrors) {
1430
+ errors.push("Resolve conversion errors before saving.");
1431
+ }
1432
+ return {
1433
+ entries,
1434
+ itemKindRefs,
1435
+ newCount,
1436
+ canSave: errors.length === 0 && newCount > 0,
1437
+ errors
1438
+ };
1439
+ }
1440
+ function fieldsToDbPayload(fields) {
1441
+ return JSON.parse(JSON.stringify(fields));
1442
+ }
1443
+ function isDuplicateBlockSlug(slug, entries) {
1444
+ const normalized = slug.trim().toLowerCase();
1445
+ return entries.some((e) => e.slug.trim().toLowerCase() === normalized);
1446
+ }
1447
+
1448
+ // convert/kind-to-json-schema.ts
1449
+ function collectReferencedKinds(fields) {
1450
+ const out = [];
1451
+ const seen = /* @__PURE__ */ new Set();
1452
+ const add = (kind) => {
1453
+ if (!seen.has(kind)) {
1454
+ seen.add(kind);
1455
+ out.push(kind);
1456
+ }
1457
+ };
1458
+ const visit = (field) => {
1459
+ if (field.type === "object") {
1460
+ add(field.kind);
1461
+ } else if (field.type === "array") {
1462
+ field.itemKinds.forEach(add);
1463
+ } else if (field.type === "union") {
1464
+ (field.kinds ?? []).forEach(add);
1465
+ } else if (field.type === "inline_object") {
1466
+ Object.values(field.fields).forEach(visit);
1467
+ }
1468
+ };
1469
+ Object.values(fields).forEach(visit);
1470
+ return out;
1471
+ }
1472
+ function collectSchemaReferencedKinds(schema) {
1473
+ if (!schema.root) return collectReferencedKinds(schema.fields);
1474
+ return collectReferencedKinds({ [ROOT_REF_FIELD]: schema.root });
1475
+ }
1476
+ var ROOT_REF_FIELD = "__root";
1477
+ function kindSchemaToJsonSchema(kind, resolve, options = {}) {
1478
+ const strict = options.strict ?? false;
1479
+ const injectKind = options.injectKind ?? true;
1480
+ const rootSchema = resolve(kind);
1481
+ if (!rootSchema) return null;
1482
+ const visited = /* @__PURE__ */ new Set([kind]);
1483
+ const defsOrder = [];
1484
+ const resolvedDefs = /* @__PURE__ */ new Map();
1485
+ const unresolved = [];
1486
+ const queue = collectSchemaReferencedKinds(rootSchema);
1487
+ while (queue.length > 0) {
1488
+ const next = queue.shift();
1489
+ if (visited.has(next)) continue;
1490
+ visited.add(next);
1491
+ defsOrder.push(next);
1492
+ const schema = resolve(next);
1493
+ if (!schema) {
1494
+ unresolved.push(next);
1495
+ continue;
1496
+ }
1497
+ resolvedDefs.set(next, schema);
1498
+ queue.push(...collectSchemaReferencedKinds(schema));
1499
+ }
1500
+ const refFor = (slug) => slug === kind ? { $ref: "#" } : { $ref: `#/$defs/${slug}` };
1501
+ const withNull = (type, nullable) => nullable ? [type, "null"] : type;
1502
+ function fieldToJsonSchema(field) {
1503
+ const node = fieldToJsonSchemaCore(field);
1504
+ if (field.description !== void 0) node.description = field.description;
1505
+ if (field.default !== void 0) node.default = field.default;
1506
+ return node;
1507
+ }
1508
+ function fieldToJsonSchemaCore(field) {
1509
+ switch (field.type) {
1510
+ case "string":
1511
+ case "boolean":
1512
+ return { type: withNull(field.type, field.nullable) };
1513
+ case "number":
1514
+ return {
1515
+ type: withNull("number", field.nullable),
1516
+ ...!strict && field.min !== void 0 ? { minimum: field.min } : {},
1517
+ ...!strict && field.max !== void 0 ? { maximum: field.max } : {},
1518
+ ...!strict && field.step !== void 0 ? { multipleOf: field.step } : {}
1519
+ };
1520
+ case "json":
1521
+ return {};
1522
+ case "string[]": {
1523
+ const items = field.values === void 0 ? { type: "string" } : field.open ? {
1524
+ anyOf: [
1525
+ { type: "string", enum: [...field.values] },
1526
+ { type: "string" }
1527
+ ]
1528
+ } : { type: "string", enum: [...field.values] };
1529
+ return { type: withNull("array", field.nullable), items };
1530
+ }
1531
+ case "number[]":
1532
+ case "boolean[]":
1533
+ return {
1534
+ type: withNull("array", field.nullable),
1535
+ items: { type: scalarArrayItemType(field.type) }
1536
+ };
1537
+ case "json[]":
1538
+ return {
1539
+ type: withNull("array", field.nullable),
1540
+ items: {}
1541
+ };
1542
+ case "enum": {
1543
+ if (!field.open) {
1544
+ return {
1545
+ type: withNull("string", field.nullable),
1546
+ enum: [...field.values]
1547
+ };
1548
+ }
1549
+ const variants = [
1550
+ { type: "string", enum: [...field.values] },
1551
+ { type: "string" }
1552
+ ];
1553
+ if (field.nullable) variants.push({ type: "null" });
1554
+ return { anyOf: variants };
1555
+ }
1556
+ case "union": {
1557
+ const variants = field.scalars.map((scalar) => ({
1558
+ type: scalar
1559
+ }));
1560
+ for (const memberKind of field.kinds ?? []) {
1561
+ variants.push(refFor(memberKind));
1562
+ }
1563
+ if (field.nullable) variants.push({ type: "null" });
1564
+ return { anyOf: variants };
1565
+ }
1566
+ case "record":
1567
+ return {
1568
+ type: withNull("object", field.nullable),
1569
+ additionalProperties: field.values === "json" ? true : { type: field.values }
1570
+ };
1571
+ case "inline_object": {
1572
+ const properties = {};
1573
+ const required = [];
1574
+ for (const [name, child] of Object.entries(field.fields)) {
1575
+ properties[name] = fieldToJsonSchema(child);
1576
+ if (child.required) required.push(name);
1577
+ }
1578
+ return {
1579
+ type: withNull("object", field.nullable),
1580
+ properties,
1581
+ required,
1582
+ ...field.open ? { additionalProperties: true } : strict ? { additionalProperties: false } : {}
1583
+ };
1584
+ }
1585
+ case "object":
1586
+ return field.nullable ? { anyOf: [refFor(field.kind), { type: "null" }] } : refFor(field.kind);
1587
+ case "array": {
1588
+ const [soleItemKind] = field.itemKinds;
1589
+ const items = field.itemKinds.length === 1 && soleItemKind !== void 0 ? refFor(soleItemKind) : { anyOf: field.itemKinds.map(refFor) };
1590
+ return { type: withNull("array", field.nullable), items };
1591
+ }
1592
+ }
1593
+ }
1594
+ function kindObjectSchema(schema) {
1595
+ if (schema.root) {
1596
+ return fieldToJsonSchema(schema.root);
1597
+ }
1598
+ const properties = {};
1599
+ const required = [];
1600
+ for (const [name, field] of Object.entries(schema.fields)) {
1601
+ properties[name] = fieldToJsonSchema(field);
1602
+ if (field.required) required.push(name);
1603
+ }
1604
+ const node = {
1605
+ type: "object",
1606
+ properties,
1607
+ required,
1608
+ ...strict ? { additionalProperties: false } : {}
1609
+ };
1610
+ return injectKind ? injectKindIntoObjectSchema(node, schema.kind, strict) : node;
1611
+ }
1612
+ function unresolvedStub(slug) {
1613
+ const node = {
1614
+ type: "object",
1615
+ description: `Unresolved kind "${slug}" \u2014 schema not available at export time.`
1616
+ };
1617
+ return injectKind ? injectKindIntoObjectSchema(node, slug, false) : node;
1618
+ }
1619
+ const rootNode = kindObjectSchema(rootSchema);
1620
+ if (defsOrder.length === 0) {
1621
+ return { name: kind, schema: rootNode, strict, unresolved };
1622
+ }
1623
+ const defs = {};
1624
+ for (const slug of defsOrder) {
1625
+ const schema = resolvedDefs.get(slug);
1626
+ defs[slug] = schema ? kindObjectSchema(schema) : unresolvedStub(slug);
1627
+ }
1628
+ return { name: kind, schema: { ...rootNode, $defs: defs }, strict, unresolved };
1629
+ }
1630
+
1631
+ // convert/json-schema-to-kind.ts
1632
+ function kindSchemaFromJsonSchema(kind, jsonSchema) {
1633
+ if (jsonSchema === null || jsonSchema === void 0) {
1634
+ return { schema: null, children: {}, problems: [] };
1635
+ }
1636
+ const normalized = normalizeAiSchemaInput(jsonSchema);
1637
+ const rootSchema = normalized.rootSchema ?? (typeof jsonSchema === "object" && !Array.isArray(jsonSchema) ? jsonSchema : null);
1638
+ if (!rootSchema) {
1639
+ return {
1640
+ schema: null,
1641
+ children: {},
1642
+ problems: [
1643
+ {
1644
+ severity: "error",
1645
+ path: "",
1646
+ message: `Kind "${kind}": emitted_json_schema is not a JSON object.`
1647
+ }
1648
+ ]
1649
+ };
1650
+ }
1651
+ const converted = convertAiSchemaToBlockFields(kind, rootSchema, false);
1652
+ let schema = null;
1653
+ const children = {};
1654
+ for (const draft of converted.blockSchemas) {
1655
+ const asKindSchema = {
1656
+ kind: draft.slug,
1657
+ fields: draft.fields,
1658
+ ...draft.root ? { root: draft.root } : {}
1659
+ };
1660
+ if (draft.slug === kind) schema = asKindSchema;
1661
+ else children[draft.slug] = asKindSchema;
1662
+ }
1663
+ return { schema, children, problems: converted.problems };
1664
+ }
1665
+
1666
+ exports.buildAgentSchemaWithRenderBlockSupport = buildAgentSchemaWithRenderBlockSupport;
1667
+ exports.collectReferencedKinds = collectReferencedKinds;
1668
+ exports.collectSchemaReferencedKinds = collectSchemaReferencedKinds;
1669
+ exports.compareWithExistingKindSchema = compareWithExistingKindSchema;
1670
+ exports.convertAiSchemaToBlockFields = convertAiSchemaToBlockFields;
1671
+ exports.fieldsToDbPayload = fieldsToDbPayload;
1672
+ exports.injectKindIntoObjectSchema = injectKindIntoObjectSchema;
1673
+ exports.isDuplicateBlockSlug = isDuplicateBlockSlug;
1674
+ exports.kindSchemaFromJsonSchema = kindSchemaFromJsonSchema;
1675
+ exports.kindSchemaToJsonSchema = kindSchemaToJsonSchema;
1676
+ exports.normalizeAiSchemaInput = normalizeAiSchemaInput;
1677
+ exports.runSchemaConversion = runSchemaConversion;
1678
+ exports.validateBlockSchemaSavePlan = validateBlockSchemaSavePlan;
1679
+ //# sourceMappingURL=convert.cjs.map
1680
+ //# sourceMappingURL=convert.cjs.map