autoui-react 0.0.3-alpha → 0.0.5-alpha

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/dist/index.js CHANGED
@@ -1,19 +1,130 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
4
- var zod = require('zod');
3
+ var clsx = require('clsx');
4
+ var tailwindMerge = require('tailwind-merge');
5
+ var reactSlot = require('@radix-ui/react-slot');
6
+ var classVarianceAuthority = require('class-variance-authority');
5
7
  var jsxRuntime = require('react/jsx-runtime');
6
- var ai = require('ai');
8
+ var React = require('react');
7
9
  var openai = require('@ai-sdk/openai');
10
+ var ai = require('ai');
11
+ var zod = require('zod');
12
+ var DialogPrimitive = require('@radix-ui/react-dialog');
13
+ var lucideReact = require('lucide-react');
14
+ var SelectPrimitive = require('@radix-ui/react-select');
15
+ var CheckboxPrimitive = require('@radix-ui/react-checkbox');
16
+ var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
17
+ var TabsPrimitive = require('@radix-ui/react-tabs');
18
+ var LabelPrimitive = require('@radix-ui/react-label');
19
+
20
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
21
+
22
+ function _interopNamespace(e) {
23
+ if (e && e.__esModule) return e;
24
+ var n = Object.create(null);
25
+ if (e) {
26
+ Object.keys(e).forEach(function (k) {
27
+ if (k !== 'default') {
28
+ var d = Object.getOwnPropertyDescriptor(e, k);
29
+ Object.defineProperty(n, k, d.get ? d : {
30
+ enumerable: true,
31
+ get: function () { return e[k]; }
32
+ });
33
+ }
34
+ });
35
+ }
36
+ n.default = e;
37
+ return Object.freeze(n);
38
+ }
39
+
40
+ var React__default = /*#__PURE__*/_interopDefault(React);
41
+ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
42
+ var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
43
+ var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
44
+ var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
45
+ var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
46
+ var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
47
+
48
+ var __defProp = Object.defineProperty;
49
+ var __getOwnPropNames = Object.getOwnPropertyNames;
50
+ var __esm = (fn, res) => function __init() {
51
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
52
+ };
53
+ var __export = (target, all) => {
54
+ for (var name in all)
55
+ __defProp(target, name, { get: all[name], enumerable: true });
56
+ };
57
+ function cn(...inputs) {
58
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
59
+ }
60
+ var init_utils = __esm({
61
+ "src/lib/utils.ts"() {
62
+ }
63
+ });
64
+
65
+ // components/ui/button.tsx
66
+ var button_exports = {};
67
+ __export(button_exports, {
68
+ Button: () => Button2,
69
+ buttonVariants: () => buttonVariants
70
+ });
71
+ function Button2({
72
+ className,
73
+ variant,
74
+ size,
75
+ asChild = false,
76
+ ...props
77
+ }) {
78
+ const Comp = asChild ? reactSlot.Slot : "button";
79
+ return /* @__PURE__ */ jsxRuntime.jsx(
80
+ Comp,
81
+ {
82
+ "data-slot": "button",
83
+ className: cn(buttonVariants({ variant, size, className })),
84
+ ...props
85
+ }
86
+ );
87
+ }
88
+ var buttonVariants;
89
+ var init_button = __esm({
90
+ "components/ui/button.tsx"() {
91
+ init_utils();
92
+ buttonVariants = classVarianceAuthority.cva(
93
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
94
+ {
95
+ variants: {
96
+ variant: {
97
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
98
+ destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
99
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
100
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
101
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
102
+ link: "text-primary underline-offset-4 hover:underline"
103
+ },
104
+ size: {
105
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
106
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
107
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
108
+ icon: "size-9"
109
+ }
110
+ },
111
+ defaultVariants: {
112
+ variant: "default",
113
+ size: "default"
114
+ }
115
+ }
116
+ );
117
+ }
118
+ });
8
119
 
9
120
  // src/core/reducer.ts
10
121
  function cloneNode(node) {
11
122
  return {
12
123
  ...node,
13
- props: node.props ? { ...node.props } : void 0,
14
- bindings: node.bindings ? { ...node.bindings } : void 0,
15
- events: node.events ? { ...node.events } : void 0,
16
- children: node.children?.map((child) => cloneNode(child))
124
+ props: node.props ? { ...node.props } : null,
125
+ bindings: node.bindings ? { ...node.bindings } : null,
126
+ events: node.events ? { ...node.events } : null,
127
+ children: node.children ? node.children.map((child) => cloneNode(child)) : null
17
128
  };
18
129
  }
19
130
  function findNodeById(tree, nodeId) {
@@ -57,18 +168,14 @@ function updateNodeById(tree, nodeId, updater) {
57
168
  const parent = path[path.length - 2];
58
169
  const updatedParent = {
59
170
  ...parent,
60
- children: parent.children?.map(
171
+ children: parent.children ? parent.children.map(
61
172
  (child) => child.id === nodeId ? updatedNode : child
62
- )
173
+ ) : null
63
174
  };
64
175
  if (path.length === 2) {
65
176
  return updatedParent;
66
177
  }
67
- return updateNodeById(
68
- result,
69
- parent.id,
70
- () => updatedParent
71
- );
178
+ return updateNodeById(result, parent.id, () => updatedParent);
72
179
  }
73
180
  function replaceNodeById(tree, nodeId, newNode) {
74
181
  return updateNodeById(tree, nodeId, () => newNode);
@@ -110,7 +217,7 @@ function removeNodeById(tree, nodeId) {
110
217
  return result;
111
218
  return updateNodeById(result, parent.id, (node) => ({
112
219
  ...node,
113
- children: node.children?.filter((child) => child.id !== nodeId)
220
+ children: node.children ? node.children.filter((child) => child.id !== nodeId) : null
114
221
  }));
115
222
  }
116
223
  function uiReducer(state, action) {
@@ -127,7 +234,7 @@ function uiReducer(state, action) {
127
234
  ...state,
128
235
  layout: action.node,
129
236
  loading: false,
130
- error: void 0
237
+ error: null
131
238
  };
132
239
  }
133
240
  case "PARTIAL_UPDATE": {
@@ -136,7 +243,7 @@ function uiReducer(state, action) {
136
243
  ...state,
137
244
  layout: action.node,
138
245
  loading: false,
139
- error: void 0
246
+ error: null
140
247
  };
141
248
  }
142
249
  if (action.nodeId === "root" || action.nodeId === state.layout.id) {
@@ -144,19 +251,23 @@ function uiReducer(state, action) {
144
251
  ...state,
145
252
  layout: action.node,
146
253
  loading: false,
147
- error: void 0
254
+ error: null
148
255
  };
149
256
  }
150
257
  return {
151
258
  ...state,
152
259
  layout: replaceNodeById(state.layout, action.nodeId, action.node),
153
260
  loading: false,
154
- error: void 0
261
+ error: null
155
262
  };
156
263
  }
157
264
  case "ADD_NODE": {
158
265
  if (!state.layout) {
159
- return state;
266
+ return {
267
+ ...state,
268
+ error: "Cannot add node: Layout is empty.",
269
+ loading: false
270
+ };
160
271
  }
161
272
  return {
162
273
  ...state,
@@ -164,21 +275,41 @@ function uiReducer(state, action) {
164
275
  state.layout,
165
276
  action.parentId,
166
277
  action.node,
167
- action.index
278
+ action.index === null ? void 0 : action.index
168
279
  ),
169
280
  loading: false,
170
- error: void 0
281
+ error: null
171
282
  };
172
283
  }
173
284
  case "REMOVE_NODE": {
174
285
  if (!state.layout) {
175
- return state;
286
+ return {
287
+ ...state,
288
+ error: "Cannot remove node: Layout is empty.",
289
+ loading: false
290
+ };
291
+ }
292
+ try {
293
+ return {
294
+ ...state,
295
+ layout: removeNodeById(state.layout, action.nodeId),
296
+ loading: false,
297
+ error: null
298
+ };
299
+ } catch (e) {
300
+ const errorMessage = e instanceof Error ? e.message : "Failed to remove node.";
301
+ return {
302
+ ...state,
303
+ error: errorMessage,
304
+ loading: false
305
+ };
176
306
  }
307
+ }
308
+ case "ERROR": {
177
309
  return {
178
310
  ...state,
179
- layout: removeNodeById(state.layout, action.nodeId),
180
- loading: false,
181
- error: void 0
311
+ error: action.message,
312
+ loading: false
182
313
  };
183
314
  }
184
315
  case "LOADING": {
@@ -187,23 +318,84 @@ function uiReducer(state, action) {
187
318
  loading: action.isLoading
188
319
  };
189
320
  }
190
- case "ERROR": {
191
- return {
192
- ...state,
193
- error: action.message,
194
- loading: false
195
- };
196
- }
197
321
  default:
198
322
  return state;
199
323
  }
200
324
  }
201
325
  var initialState = {
202
- loading: true,
203
- history: []
326
+ layout: null,
327
+ loading: false,
328
+ history: [],
329
+ error: null
204
330
  };
205
331
 
206
332
  // src/core/action-router.ts
333
+ var UI_GUIDANCE_BASE = `
334
+ UI Guidance:
335
+ 1. Create a focused interface that directly addresses the goal
336
+ 2. Use appropriate UI patterns (lists, forms, details, etc.)
337
+ 3. Include navigation between related views when needed
338
+ 4. Keep the interface simple and intuitive
339
+ 5. Bind to schema data where appropriate
340
+ 6. Provide event handlers for user interactions - make sure to always include both action and target properties`;
341
+ var LIST_BINDING_GUIDANCE = `7. **CRITICAL:** For \`ListView\` or \`Table\` nodes, the \`data\` binding key **MUST** point to the *exact path* of the data *array* within the context.`;
342
+ var LIST_BINDING_EXAMPLE = `Example: If the context has \`{ tasks: { data: [...] } }\`, the binding **MUST** be \`{ "bindings": { "data": "tasks.data" } }\`. If the context has \`{ userList: [...] }\`, the binding **MUST** be \`{ "bindings": { "data": "userList" } }\`. **NEVER** bind to the parent object containing the array (e.g., DO NOT USE \`{ "bindings": { "data": "tasks" } }\`).`;
343
+ var COMMON_UI_GUIDANCE = UI_GUIDANCE_BASE + "\n" + // Add a newline separator
344
+ LIST_BINDING_GUIDANCE + // Add the specific list binding rule
345
+ "\n" + // Add a newline separator
346
+ LIST_BINDING_EXAMPLE;
347
+ function processTemplate(template, values) {
348
+ return template.replace(/\${(.*?)}/g, (match, key) => {
349
+ const trimmedKey = key.trim();
350
+ return trimmedKey in values ? String(values[trimmedKey]) : match;
351
+ });
352
+ }
353
+ function buildPrompt(input, promptTemplate, templateValues) {
354
+ const { schema, goal, history, userContext } = input;
355
+ const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
356
+ const schemaString = typeof tableSchema === "object" && tableSchema !== null ? JSON.stringify(tableSchema) : String(tableSchema);
357
+ return `Table: ${tableName}
358
+ Schema: ${schemaString}`;
359
+ }).join("\n\n");
360
+ const recentEvents = history && history.length > 0 ? history.slice(-5).map(
361
+ (event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
362
+ ).join("\n") : "No recent events";
363
+ const userContextSection = userContext ? `
364
+
365
+ User Context:
366
+ ${JSON.stringify(userContext)}` : "";
367
+ if (promptTemplate && templateValues) {
368
+ const fullTemplateValues = {
369
+ ...templateValues,
370
+ schemaInfo,
371
+ recentEvents,
372
+ userContextString: userContextSection.trim(),
373
+ // Use trimmed version
374
+ commonUIGuidance: COMMON_UI_GUIDANCE,
375
+ goal
376
+ // Ensure goal is always available to templates
377
+ };
378
+ return processTemplate(promptTemplate, fullTemplateValues);
379
+ }
380
+ const interactionDescription = history && history.length > 0 ? `The user's last action was: ${history[history.length - 1].type} on node ${history[history.length - 1].nodeId}` : "The user initiated the session for the goal";
381
+ return `
382
+ You are an expert UI generator.
383
+ Create a user interface that achieves the following goal: "${goal}".
384
+ ${interactionDescription}.
385
+
386
+ Available data schema:
387
+ ${schemaInfo}
388
+
389
+ Recent user interactions:
390
+ ${recentEvents}${userContextSection}
391
+
392
+ Generate a complete UI specification in JSON format that matches the following TypeScript type:
393
+ type UISpecNode = { id: string; node_type: string; props?: Record<string, unknown>; bindings?: Record<string, unknown>; events?: Record<string, { action: string; target: string; payload?: Record<string, unknown>; }>; children?: UISpecNode[]; };
394
+ ${COMMON_UI_GUIDANCE}
395
+
396
+ Respond ONLY with the JSON UI specification and no other text.
397
+ `;
398
+ }
207
399
  var ActionType = /* @__PURE__ */ ((ActionType2) => {
208
400
  ActionType2["FULL_REFRESH"] = "FULL_REFRESH";
209
401
  ActionType2["UPDATE_NODE"] = "UPDATE_NODE";
@@ -238,19 +430,39 @@ var ActionRouter = class {
238
430
  * @returns Route resolution or null if no match
239
431
  */
240
432
  resolveRoute(event, schema, layout, dataContext, goal, userContext) {
433
+ console.log(
434
+ `[ActionRouter Debug] resolveRoute called for event type: ${event.type}`
435
+ );
241
436
  const routes = this.routes[event.type] || [];
437
+ console.log(
438
+ `[ActionRouter Debug] Found ${routes.length} routes for ${event.type}`
439
+ );
242
440
  if (routes.length === 0) {
243
- return {
441
+ console.log(
442
+ `[ActionRouter Debug] No specific route found for ${event.type}, using default FULL_REFRESH.`
443
+ );
444
+ const defaultPlannerInput = {
445
+ schema,
446
+ goal,
447
+ history: [event],
448
+ userContext: userContext || null
449
+ };
450
+ const defaultPrompt = buildPrompt(
451
+ defaultPlannerInput,
452
+ void 0,
453
+ void 0
454
+ );
455
+ const defaultResolution = {
244
456
  actionType: "FULL_REFRESH" /* FULL_REFRESH */,
245
457
  targetNodeId: layout?.id || "root",
246
- plannerInput: {
247
- schema,
248
- goal,
249
- history: [event],
250
- userContext
251
- },
252
- prompt: `Generate a new UI for the goal: "${goal}". The user just triggered: ${event.type} on node ${event.nodeId}`
458
+ plannerInput: defaultPlannerInput,
459
+ prompt: defaultPrompt
253
460
  };
461
+ console.log(
462
+ "[ActionRouter Debug] Default Resolution:",
463
+ defaultResolution
464
+ );
465
+ return defaultResolution;
254
466
  }
255
467
  const sourceNode = layout ? findNodeById(layout, event.nodeId) : void 0;
256
468
  const nodeConfig = sourceNode?.events?.[event.type];
@@ -263,6 +475,7 @@ var ActionRouter = class {
263
475
  if (!matchingRoute) {
264
476
  matchingRoute = routes[0];
265
477
  }
478
+ console.log("[ActionRouter Debug] Matching Route Config:", matchingRoute);
266
479
  const targetNodeId = nodeConfig?.target || matchingRoute.targetNodeId || event.nodeId;
267
480
  const additionalContext = {};
268
481
  if (matchingRoute.contextKeys) {
@@ -296,23 +509,35 @@ var ActionRouter = class {
296
509
  ...additionalContext
297
510
  }
298
511
  };
299
- const prompt = this.processTemplate(
512
+ const templateValues = {
513
+ goal,
514
+ eventType: event.type,
515
+ nodeId: event.nodeId,
516
+ targetNodeId,
517
+ actionType: matchingRoute.actionType,
518
+ ...userContext || {},
519
+ // Spread the original userContext (passed to resolveRoute)
520
+ ...additionalContext
521
+ // Spread additionalContext afterwards (can override userContext keys)
522
+ };
523
+ console.log("[ActionRouter Debug] Template Values:", templateValues);
524
+ const finalPrompt = buildPrompt(
525
+ plannerInput2,
300
526
  matchingRoute.promptTemplate,
301
- {
302
- goal,
303
- eventType: event.type,
304
- nodeId: event.nodeId,
305
- targetNodeId,
306
- actionType: matchingRoute.actionType,
307
- ...additionalContext
308
- }
527
+ // Pass template if it exists (can be undefined)
528
+ templateValues
529
+ // Pass templateValues (used only if promptTemplate exists)
309
530
  );
310
- return {
531
+ console.log("[ActionRouter Debug] Generated Prompt:", finalPrompt);
532
+ const finalResolution = {
311
533
  actionType: matchingRoute.actionType,
312
534
  targetNodeId,
313
535
  plannerInput: plannerInput2,
314
- prompt
536
+ prompt: finalPrompt
537
+ // Use the generated prompt
315
538
  };
539
+ console.log("[ActionRouter Debug] Final Resolution:", finalResolution);
540
+ return finalResolution;
316
541
  }
317
542
  /**
318
543
  * Process a prompt template with variables
@@ -330,8 +555,11 @@ function createDefaultRouter() {
330
555
  const router = new ActionRouter();
331
556
  router.registerRoute("CLICK", {
332
557
  actionType: "FULL_REFRESH" /* FULL_REFRESH */,
333
- targetNodeId: "root",
334
- promptTemplate: 'Generate a new UI for the goal: "${goal}". The user just clicked on node ${nodeId}'
558
+ targetNodeId: "root"
559
+ });
560
+ router.registerRoute("INIT", {
561
+ actionType: "FULL_REFRESH" /* FULL_REFRESH */,
562
+ targetNodeId: "root"
335
563
  });
336
564
  router.registerRoute("CLICK", {
337
565
  actionType: "SHOW_DETAIL" /* SHOW_DETAIL */,
@@ -361,7 +589,31 @@ function createDefaultRouter() {
361
589
  });
362
590
  return router;
363
591
  }
592
+ var componentType = zod.z.enum([
593
+ // Layout components
594
+ "Container",
595
+ "Card",
596
+ "Header",
597
+ // Input components
598
+ "Button",
599
+ "Input",
600
+ "Select",
601
+ "Textarea",
602
+ "Checkbox",
603
+ "RadioGroup",
604
+ // Data display components
605
+ "ListView",
606
+ "Detail",
607
+ "Tabs",
608
+ "Dialog",
609
+ // Typography
610
+ "Heading",
611
+ "Text"
612
+ ]);
613
+
614
+ // src/schema/ui.ts
364
615
  var uiEventType = zod.z.enum([
616
+ "INIT",
365
617
  "CLICK",
366
618
  "CHANGE",
367
619
  "SUBMIT",
@@ -373,27 +625,62 @@ var uiEventType = zod.z.enum([
373
625
  var uiEvent = zod.z.object({
374
626
  type: uiEventType,
375
627
  nodeId: zod.z.string(),
376
- timestamp: zod.z.number().optional(),
377
- payload: zod.z.record(zod.z.any()).optional()
628
+ timestamp: zod.z.number().nullable(),
629
+ payload: zod.z.record(zod.z.unknown()).nullable()
378
630
  });
379
- zod.z.enum([
380
- "AI_RESPONSE",
381
- "ERROR"
382
- ]);
383
- var uiSpecNode = zod.z.lazy(() => zod.z.object({
631
+ zod.z.enum(["AI_RESPONSE", "ERROR"]);
632
+ var runtimeRecord = zod.z.record(zod.z.any()).nullable();
633
+ var openAISimplifiedValue = zod.z.string().nullable();
634
+ var openAIRecordSimplifiedNullable = zod.z.record(openAISimplifiedValue).nullable();
635
+ var openAIEventPayloadSimplifiedNullable = zod.z.record(openAISimplifiedValue).nullable();
636
+ var openAIBaseNode = zod.z.object({
637
+ id: zod.z.string().describe("Unique identifier for the UI node."),
638
+ node_type: componentType.describe(
639
+ "The type of UI component (e.g., Container, Text, Button, ListView)."
640
+ ),
641
+ props: openAIRecordSimplifiedNullable.describe(
642
+ 'Component-specific properties (attributes). Values should be strings or null. E.g., for Header use { "title": "My Title" }; for Text use { "text": "My Text" }.'
643
+ ),
644
+ bindings: openAIRecordSimplifiedNullable.describe(
645
+ 'Data bindings map context paths to component props. Values are paths (e.g., "user.name") or templates (e.g., "{{item.title}}"). **CRITICAL for ListView/Table:** the `data` key MUST point to the *exact array path* (e.g., { "data": "tasks.data" } or { "data": "userList" }), NOT the parent object.'
646
+ ),
647
+ events: zod.z.record(
648
+ zod.z.string(),
649
+ zod.z.object({
650
+ action: zod.z.string(),
651
+ target: zod.z.string(),
652
+ payload: openAIEventPayloadSimplifiedNullable
653
+ })
654
+ ).nullable(),
655
+ // Entire events object is nullable
656
+ children: zod.z.null()
657
+ // Base children are null. When extended, it will be an array or null.
658
+ });
659
+ var openAINodeL4 = openAIBaseNode;
660
+ var openAINodeL3 = openAIBaseNode.extend({
661
+ children: zod.z.array(openAINodeL4).nullable()
662
+ });
663
+ var openAINodeL2 = openAIBaseNode.extend({
664
+ children: zod.z.array(openAINodeL3).nullable()
665
+ });
666
+ var openAIUISpec = openAIBaseNode.extend({
667
+ children: zod.z.array(openAINodeL2).nullable()
668
+ });
669
+ var uiSpecNode = zod.z.object({
384
670
  id: zod.z.string(),
385
- type: zod.z.string(),
386
- // e.g., "ListView", "Button", "TextField"
387
- props: zod.z.record(zod.z.any()).optional(),
388
- bindings: zod.z.record(zod.z.any()).optional(),
389
- // Data bindings
390
- events: zod.z.record(zod.z.string(), zod.z.object({
391
- action: zod.z.string(),
392
- target: zod.z.string().optional(),
393
- payload: zod.z.record(zod.z.any()).optional()
394
- })).optional(),
395
- children: zod.z.array(uiSpecNode).optional()
396
- }));
671
+ node_type: zod.z.string(),
672
+ props: runtimeRecord,
673
+ bindings: runtimeRecord,
674
+ events: zod.z.record(
675
+ zod.z.string(),
676
+ zod.z.object({
677
+ action: zod.z.string(),
678
+ target: zod.z.string(),
679
+ payload: runtimeRecord
680
+ })
681
+ ).nullable(),
682
+ children: zod.z.lazy(() => zod.z.array(uiSpecNode)).nullable()
683
+ });
397
684
  zod.z.discriminatedUnion("type", [
398
685
  zod.z.object({
399
686
  type: zod.z.literal("UI_EVENT"),
@@ -412,7 +699,7 @@ zod.z.discriminatedUnion("type", [
412
699
  type: zod.z.literal("ADD_NODE"),
413
700
  parentId: zod.z.string(),
414
701
  node: uiSpecNode,
415
- index: zod.z.number().optional()
702
+ index: zod.z.number().nullable()
416
703
  }),
417
704
  zod.z.object({
418
705
  type: zod.z.literal("REMOVE_NODE"),
@@ -428,16 +715,16 @@ zod.z.discriminatedUnion("type", [
428
715
  })
429
716
  ]);
430
717
  zod.z.object({
431
- layout: uiSpecNode.optional(),
718
+ layout: uiSpecNode.nullable(),
432
719
  loading: zod.z.boolean(),
433
720
  history: zod.z.array(uiEvent),
434
- error: zod.z.string().optional()
721
+ error: zod.z.string().nullable()
435
722
  });
436
723
  zod.z.object({
437
724
  schema: zod.z.record(zod.z.unknown()),
438
725
  goal: zod.z.string(),
439
- history: zod.z.array(uiEvent).optional(),
440
- userContext: zod.z.record(zod.z.unknown()).optional()
726
+ history: zod.z.array(uiEvent).nullable(),
727
+ userContext: zod.z.record(zod.z.unknown()).nullable().optional()
441
728
  });
442
729
 
443
730
  // src/core/system-events.ts
@@ -463,7 +750,7 @@ var SystemEventManager = class {
463
750
  }
464
751
  /**
465
752
  * Register a listener for a specific system event type
466
- *
753
+ *
467
754
  * @param eventType - The system event type to listen for
468
755
  * @param listener - The listener function
469
756
  * @returns Function to unregister the listener
@@ -483,7 +770,7 @@ var SystemEventManager = class {
483
770
  }
484
771
  /**
485
772
  * Emit a system event to all registered listeners
486
- *
773
+ *
487
774
  * @param event - The system event to emit
488
775
  */
489
776
  async emit(event) {
@@ -503,268 +790,917 @@ function createSystemEvent(type, data) {
503
790
  }
504
791
 
505
792
  // src/env.ts
506
- ({
507
- MOCK_PLANNER: undefined?.VITE_MOCK_PLANNER || "1",
508
- NODE_ENV: undefined?.MODE || "development"
509
- // Add other environment variables as needed
510
- });
793
+ var rawApiKeyFromEnv = process.env.VITE_OPENAI_API_KEY;
794
+ var env = {
795
+ MOCK_PLANNER: process.env.VITE_MOCK_PLANNER || "0",
796
+ // Simplified MOCK_PLANNER assignment
797
+ NODE_ENV: process.env.VITE_NODE_ENV || "production",
798
+ // Simplified NODE_ENV assignment
799
+ OPENAI_API_KEY: rawApiKeyFromEnv || ""
800
+ };
511
801
 
512
802
  // src/core/planner.ts
513
- function buildPrompt(input, targetNodeId, customPrompt) {
514
- const { schema, goal, history, userContext } = input;
515
- const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
516
- return `Table: ${tableName}
517
- Schema: ${JSON.stringify(tableSchema)}`;
518
- }).join("\n\n");
519
- const recentEvents = history?.slice(-5).map(
520
- (event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
521
- ).join("\n") || "No recent events";
522
- const userContextSection = userContext ? `
523
-
524
- User Context:
525
- ${JSON.stringify(userContext)}` : "";
526
- return `
527
- You are an expert UI generator.
528
- Create a user interface that achieves the following goal: "${goal}"
529
-
530
- Available data schema:
531
- ${schemaInfo}
532
-
533
- Recent user interactions:
534
- ${recentEvents}${userContextSection}
535
-
536
- Generate a complete UI specification in JSON format that matches the following TypeScript type:
537
- type UISpecNode = {
538
- id: string;
539
- type: string;
540
- props?: Record<string, any>;
541
- bindings?: Record<string, any>;
542
- events?: Record<string, { action: string; target?: string; payload?: Record<string, any>; }>;
543
- children?: UISpecNode[];
803
+ var getOpenAIClient = (apiKey) => {
804
+ return openai.createOpenAI({
805
+ apiKey,
806
+ // Use the provided key directly
807
+ compatibility: "strict"
808
+ });
544
809
  };
545
-
546
- UI Guidance:
547
- 1. Create a focused interface that directly addresses the goal
548
- 2. Use appropriate UI patterns (lists, forms, details, etc.)
549
- 3. Include navigation between related views when needed
550
- 4. Keep the interface simple and intuitive
551
- 5. Bind to schema data where appropriate
552
- 6. Provide event handlers for user interactions
553
-
554
- Respond ONLY with the JSON UI specification and no other text.
555
- `;
556
- }
557
810
  function mockPlanner(input, targetNodeId, customPrompt) {
811
+ if (customPrompt) {
812
+ console.log("mockPlanner received customPrompt:", customPrompt);
813
+ }
814
+ const taskSchema = input.schema.tasks;
815
+ const taskData = taskSchema?.sampleData || [
816
+ {
817
+ id: "1",
818
+ title: "Example Task 1",
819
+ description: "This is a sample task",
820
+ status: "pending",
821
+ priority: "medium"
822
+ },
823
+ {
824
+ id: "2",
825
+ title: "Example Task 2",
826
+ description: "Another sample task",
827
+ status: "completed",
828
+ priority: "high"
829
+ }
830
+ ];
558
831
  const mockNode = {
559
832
  id: targetNodeId || "root",
560
- type: "Container",
561
- props: { title: "Mock UI" },
833
+ node_type: "Container",
834
+ props: {
835
+ className: "p-4 space-y-6"
836
+ },
837
+ bindings: null,
838
+ events: null,
562
839
  children: [
563
840
  {
564
- id: "text-1",
565
- type: "Text",
566
- props: { text: "This is a mock UI for testing" }
841
+ id: "header-1",
842
+ node_type: "Header",
843
+ props: {
844
+ title: "Task Management Dashboard",
845
+ className: "mb-4"
846
+ },
847
+ bindings: null,
848
+ events: null,
849
+ children: null
850
+ },
851
+ {
852
+ id: "main-content",
853
+ node_type: "Container",
854
+ props: {
855
+ className: "grid grid-cols-1 gap-6 md:grid-cols-3"
856
+ },
857
+ bindings: null,
858
+ events: null,
859
+ children: [
860
+ {
861
+ id: "tasks-container",
862
+ node_type: "Container",
863
+ props: {
864
+ className: "md:col-span-2"
865
+ },
866
+ bindings: null,
867
+ events: null,
868
+ children: [
869
+ {
870
+ id: "list-heading",
871
+ node_type: "Container",
872
+ props: {
873
+ className: "flex justify-between items-center mb-4"
874
+ },
875
+ bindings: null,
876
+ events: null,
877
+ children: [
878
+ {
879
+ id: "list-title",
880
+ node_type: "Header",
881
+ props: {
882
+ title: "Tasks",
883
+ className: "border-none p-0 m-0"
884
+ },
885
+ bindings: null,
886
+ events: null,
887
+ children: null
888
+ },
889
+ {
890
+ id: "add-task-button",
891
+ node_type: "Button",
892
+ props: {
893
+ label: "Add Task",
894
+ variant: "default"
895
+ },
896
+ bindings: null,
897
+ events: {
898
+ onClick: {
899
+ action: "ADD_TASK",
900
+ target: "tasks-container",
901
+ payload: {}
902
+ }
903
+ },
904
+ children: null
905
+ }
906
+ ]
907
+ },
908
+ {
909
+ id: "task-list",
910
+ node_type: "ListView",
911
+ props: {
912
+ selectable: "true"
913
+ },
914
+ bindings: {
915
+ data: "tasks.data",
916
+ fields: JSON.stringify([
917
+ { key: "id", label: "ID" },
918
+ { key: "title", label: "Title" },
919
+ { key: "status", label: "Status" },
920
+ { key: "priority", label: "Priority" }
921
+ ])
922
+ },
923
+ events: {
924
+ onSelect: {
925
+ action: "SELECT_TASK",
926
+ target: "task-detail",
927
+ payload: {
928
+ source: "task-list"
929
+ }
930
+ }
931
+ },
932
+ children: null
933
+ }
934
+ ]
935
+ },
936
+ {
937
+ id: "task-detail",
938
+ node_type: "Detail",
939
+ props: {
940
+ title: "Task Details",
941
+ visible: "true"
942
+ },
943
+ bindings: {
944
+ data: JSON.stringify(taskData[0]),
945
+ fields: JSON.stringify([
946
+ { key: "title", label: "Title", type: "heading" },
947
+ { key: "description", label: "Description", type: "content" },
948
+ { key: "status", label: "Status" },
949
+ { key: "priority", label: "Priority" },
950
+ { key: "dueDate", label: "Due Date" }
951
+ ])
952
+ },
953
+ events: {
954
+ onBack: {
955
+ action: "CLOSE_DETAIL",
956
+ target: "task-detail",
957
+ payload: {}
958
+ }
959
+ },
960
+ children: null
961
+ }
962
+ ]
567
963
  }
568
964
  ]
569
965
  };
570
966
  return mockNode;
571
967
  }
968
+ async function callPlannerLLM(input, openaiApiKey, routeResolution) {
969
+ await systemEvents.emit(
970
+ createSystemEvent("PLAN_START" /* PLAN_START */, { plannerInput: input })
971
+ );
972
+ if (env.MOCK_PLANNER === "1") {
973
+ console.warn(
974
+ `Using mock planner because MOCK_PLANNER environment variable is set to "1".`
975
+ );
976
+ return mockPlanner(input);
977
+ }
978
+ if (!openaiApiKey) {
979
+ console.warn(
980
+ `OpenAI API key was not provided to callPlannerLLM. Falling back to mock planner.`
981
+ );
982
+ return mockPlanner(input);
983
+ }
984
+ const startTime = Date.now();
985
+ const prompt = routeResolution?.prompt;
986
+ if (!prompt) {
987
+ throw new Error("ActionRouter did not provide a prompt to callPlannerLLM.");
988
+ }
989
+ await systemEvents.emit(
990
+ createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
991
+ );
992
+ try {
993
+ const { object: uiSpec } = await ai.generateObject({
994
+ model: getOpenAIClient(openaiApiKey)("gpt-4o", {
995
+ structuredOutputs: true
996
+ }),
997
+ schema: openAIUISpec,
998
+ messages: [{ role: "user", content: prompt }],
999
+ temperature: 0.2,
1000
+ maxTokens: 4e3
1001
+ });
1002
+ await systemEvents.emit(
1003
+ createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
1004
+ layout: uiSpec,
1005
+ executionTimeMs: Date.now() - startTime
1006
+ })
1007
+ );
1008
+ return uiSpec;
1009
+ } catch (error) {
1010
+ console.error("Error calling LLM planner:", error);
1011
+ await systemEvents.emit(
1012
+ createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
1013
+ error: error instanceof Error ? error : new Error(String(error))
1014
+ })
1015
+ );
1016
+ throw error;
1017
+ }
1018
+ }
1019
+ async function processEvent(event, router, schema, layout, dataContext, goal, userContext, openaiApiKey) {
1020
+ const routeResolution = await router.resolveRoute(
1021
+ event,
1022
+ schema,
1023
+ layout || null,
1024
+ dataContext,
1025
+ goal,
1026
+ userContext
1027
+ );
1028
+ if (!routeResolution) {
1029
+ throw new Error(
1030
+ `No route found for event type: ${event.type}, node: ${event.nodeId}`
1031
+ );
1032
+ }
1033
+ if (routeResolution.actionType.toString() === "NoOp") {
1034
+ if (!layout)
1035
+ throw new Error("Layout is undefined and action is NoOp");
1036
+ return layout;
1037
+ }
1038
+ const plannerInputForLLM = routeResolution.plannerInput;
1039
+ const newLayout = await callPlannerLLM(
1040
+ plannerInputForLLM,
1041
+ openaiApiKey || "",
1042
+ routeResolution
1043
+ );
1044
+ return newLayout;
1045
+ }
572
1046
 
573
1047
  // src/core/state.ts
574
- var useChat = (config) => ({
575
- append: async (message) => {
576
- },
577
- data: { content: "{}" },
578
- isLoading: false,
579
- error: null,
580
- stop: () => {
581
- }
582
- });
583
1048
  function useUIStateEngine({
584
1049
  schema,
585
1050
  goal,
1051
+ openaiApiKey,
586
1052
  userContext,
587
1053
  mockMode = false,
588
- planningConfig = {},
1054
+ planningConfig,
589
1055
  router = createDefaultRouter(),
590
1056
  dataContext = {},
591
1057
  enablePartialUpdates = false
592
1058
  }) {
593
- const [state, dispatch] = react.useReducer(uiReducer, initialState);
594
- const { append, data, isLoading, error, stop } = useChat();
595
- const handleEvent = react.useCallback((event) => {
596
- dispatch({ type: "UI_EVENT", event });
597
- stop();
598
- if (enablePartialUpdates) {
599
- const route = router.resolveRoute(
600
- event,
601
- schema,
602
- state.layout,
603
- dataContext,
604
- goal,
605
- userContext
606
- );
607
- if (route) {
608
- console.log("Resolved route:", route);
609
- systemEvents.emit(
610
- createSystemEvent("PLAN_START" /* PLAN_START */, {
611
- plannerInput: route.plannerInput
612
- })
613
- );
614
- if (mockMode) {
615
- const node = mockPlanner(route.plannerInput, route.targetNodeId, route.prompt);
616
- switch (route.actionType) {
617
- case "FULL_REFRESH" /* FULL_REFRESH */:
618
- dispatch({ type: "AI_RESPONSE", node });
619
- break;
620
- case "UPDATE_NODE" /* UPDATE_NODE */:
621
- case "SHOW_DETAIL" /* SHOW_DETAIL */:
622
- case "HIDE_DETAIL" /* HIDE_DETAIL */:
623
- case "TOGGLE_STATE" /* TOGGLE_STATE */:
624
- case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
625
- case "UPDATE_FORM" /* UPDATE_FORM */:
626
- case "NAVIGATE" /* NAVIGATE */:
627
- dispatch({
628
- type: "PARTIAL_UPDATE",
629
- nodeId: route.targetNodeId,
630
- node
631
- });
632
- break;
633
- }
634
- } else {
635
- const prompt = route.prompt;
636
- systemEvents.emit(
637
- createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
638
- );
639
- append({
640
- content: prompt,
641
- role: "user"
642
- });
643
- sessionStorage.setItem("currentRoute", JSON.stringify({
644
- actionType: route.actionType,
645
- targetNodeId: route.targetNodeId
646
- }));
647
- }
648
- return;
649
- }
650
- }
651
- const input = {
652
- schema,
653
- goal,
654
- history: [...state.history, event],
655
- userContext
656
- };
657
- if (mockMode) {
658
- const node = mockPlanner();
659
- dispatch({ type: "AI_RESPONSE", node });
660
- } else {
661
- const prompt = buildPrompt(input);
662
- append({
663
- content: prompt,
664
- role: "user"
665
- });
666
- }
667
- }, [append, goal, schema, state.history, state.layout, stop, userContext, router, mockMode, dataContext, enablePartialUpdates]);
668
- react.useEffect(() => {
669
- if (isLoading) {
1059
+ if (userContext === null) {
1060
+ console.warn(
1061
+ "useUIStateEngine: userContext was explicitly set to null. This is an allowed but discouraged value. Consider using undefined if you intend to omit the user context."
1062
+ );
1063
+ }
1064
+ const [state, dispatch] = React.useReducer(uiReducer, initialState);
1065
+ const handleEvent = React.useCallback(
1066
+ async (event) => {
1067
+ dispatch({ type: "UI_EVENT", event });
670
1068
  dispatch({ type: "LOADING", isLoading: true });
671
- } else if (error) {
672
- const errorMessage = error instanceof Error ? error.message : String(error);
673
- dispatch({ type: "ERROR", message: errorMessage });
674
- systemEvents.emit(
675
- createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
676
- error: error instanceof Error ? error : new Error(String(error))
677
- })
678
- );
679
- } else if (data.content) {
680
1069
  try {
681
- systemEvents.emit(
682
- createSystemEvent("PLAN_RESPONSE_CHUNK" /* PLAN_RESPONSE_CHUNK */, {
683
- chunk: data.content,
684
- isComplete: true
685
- })
686
- );
687
- const jsonMatch = data.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || [null, data.content];
688
- const jsonStr = jsonMatch[1].trim();
689
- const parsedJson = JSON.parse(jsonStr);
690
- const validatedNode = uiSpecNode.parse(parsedJson);
691
- const routeInfoStr = sessionStorage.getItem("currentRoute");
692
- if (routeInfoStr && enablePartialUpdates) {
693
- try {
694
- const routeInfo = JSON.parse(routeInfoStr);
695
- switch (routeInfo.actionType) {
696
- case "FULL_REFRESH" /* FULL_REFRESH */:
697
- dispatch({ type: "AI_RESPONSE", node: validatedNode });
698
- break;
699
- case "UPDATE_NODE" /* UPDATE_NODE */:
700
- case "SHOW_DETAIL" /* SHOW_DETAIL */:
701
- case "HIDE_DETAIL" /* HIDE_DETAIL */:
702
- case "TOGGLE_STATE" /* TOGGLE_STATE */:
703
- case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
704
- case "UPDATE_FORM" /* UPDATE_FORM */:
705
- case "NAVIGATE" /* NAVIGATE */:
706
- dispatch({
707
- type: "PARTIAL_UPDATE",
708
- nodeId: routeInfo.targetNodeId,
709
- node: validatedNode
710
- });
711
- break;
712
- default:
713
- dispatch({ type: "AI_RESPONSE", node: validatedNode });
1070
+ let resolvedNode;
1071
+ let actionTypeForDispatch = "FULL_REFRESH" /* FULL_REFRESH */;
1072
+ let targetNodeIdForDispatch = "root";
1073
+ if (enablePartialUpdates) {
1074
+ const route = router.resolveRoute(
1075
+ event,
1076
+ schema,
1077
+ state.layout,
1078
+ dataContext,
1079
+ goal,
1080
+ userContext
1081
+ );
1082
+ if (route) {
1083
+ console.log("Resolved route:", route);
1084
+ actionTypeForDispatch = route.actionType;
1085
+ targetNodeIdForDispatch = route.targetNodeId;
1086
+ systemEvents.emit(
1087
+ createSystemEvent("PLAN_START" /* PLAN_START */, {
1088
+ plannerInput: route.plannerInput
1089
+ })
1090
+ );
1091
+ if (mockMode) {
1092
+ resolvedNode = mockPlanner(
1093
+ route.plannerInput,
1094
+ route.targetNodeId,
1095
+ route.prompt
1096
+ );
1097
+ } else {
1098
+ resolvedNode = await callPlannerLLM(
1099
+ route.plannerInput,
1100
+ openaiApiKey || "",
1101
+ route
1102
+ );
1103
+ }
1104
+ } else {
1105
+ const input = {
1106
+ schema,
1107
+ goal,
1108
+ history: [...state.history, event],
1109
+ userContext
1110
+ };
1111
+ if (mockMode) {
1112
+ resolvedNode = mockPlanner(input);
1113
+ } else {
1114
+ resolvedNode = await callPlannerLLM(
1115
+ input,
1116
+ openaiApiKey || "",
1117
+ void 0
1118
+ );
714
1119
  }
715
- sessionStorage.removeItem("currentRoute");
716
- } catch (e) {
717
- console.error("Error parsing route info:", e);
718
- dispatch({ type: "AI_RESPONSE", node: validatedNode });
719
1120
  }
720
1121
  } else {
721
- dispatch({ type: "AI_RESPONSE", node: validatedNode });
1122
+ const input = {
1123
+ schema,
1124
+ goal,
1125
+ history: [...state.history, event],
1126
+ // event is already in history from UI_EVENT dispatch
1127
+ userContext
1128
+ };
1129
+ if (mockMode) {
1130
+ resolvedNode = mockPlanner(input);
1131
+ } else {
1132
+ resolvedNode = await callPlannerLLM(
1133
+ input,
1134
+ openaiApiKey || "",
1135
+ void 0
1136
+ );
1137
+ }
722
1138
  }
723
- systemEvents.emit(
724
- createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
725
- layout: validatedNode,
726
- executionTimeMs: 0
727
- // Not available here
728
- })
729
- );
730
- } catch (parseError) {
731
- console.error("Failed to parse LLM response:", parseError);
732
- dispatch({
733
- type: "ERROR",
734
- message: "Failed to parse LLM response"
735
- });
1139
+ switch (actionTypeForDispatch) {
1140
+ case "UPDATE_NODE" /* UPDATE_NODE */:
1141
+ case "SHOW_DETAIL" /* SHOW_DETAIL */:
1142
+ case "HIDE_DETAIL" /* HIDE_DETAIL */:
1143
+ case "TOGGLE_STATE" /* TOGGLE_STATE */:
1144
+ case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
1145
+ case "UPDATE_FORM" /* UPDATE_FORM */:
1146
+ case "NAVIGATE" /* NAVIGATE */:
1147
+ dispatch({
1148
+ type: "PARTIAL_UPDATE",
1149
+ nodeId: targetNodeIdForDispatch,
1150
+ node: resolvedNode
1151
+ });
1152
+ break;
1153
+ case "FULL_REFRESH" /* FULL_REFRESH */:
1154
+ default:
1155
+ dispatch({ type: "AI_RESPONSE", node: resolvedNode });
1156
+ break;
1157
+ }
1158
+ } catch (e) {
1159
+ const errorMessage = e instanceof Error ? e.message : String(e);
1160
+ dispatch({ type: "ERROR", message: errorMessage });
736
1161
  systemEvents.emit(
737
1162
  createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
738
- error: parseError instanceof Error ? parseError : new Error("Parse error")
1163
+ error: e instanceof Error ? e : new Error(String(e))
739
1164
  })
740
1165
  );
1166
+ } finally {
1167
+ dispatch({ type: "LOADING", isLoading: false });
741
1168
  }
742
- }
743
- }, [data.content, error, isLoading, enablePartialUpdates]);
744
- react.useEffect(() => {
745
- const input = {
746
- schema,
1169
+ },
1170
+ [
1171
+ // append, // REMOVE
747
1172
  goal,
748
- history: [],
749
- userContext
750
- };
751
- if (mockMode) {
752
- const node = mockPlanner();
753
- dispatch({ type: "AI_RESPONSE", node });
754
- } else {
755
- const prompt = buildPrompt(input);
756
- append({
757
- content: prompt,
758
- role: "user"
759
- });
760
- }
761
- }, [append, goal, schema, userContext, mockMode]);
762
- return {
763
- state,
764
- dispatch,
1173
+ schema,
1174
+ state.history,
1175
+ // Keep state.history if input preparation needs it
1176
+ state.layout,
1177
+ // stop, // REMOVE
1178
+ userContext,
1179
+ router,
1180
+ mockMode,
1181
+ dataContext,
1182
+ openaiApiKey,
1183
+ enablePartialUpdates,
1184
+ dispatch
1185
+ // Add dispatch
1186
+ ]
1187
+ );
1188
+ React.useEffect(() => {
1189
+ const initialFetch = async () => {
1190
+ dispatch({ type: "LOADING", isLoading: true });
1191
+ try {
1192
+ const input = {
1193
+ schema,
1194
+ goal,
1195
+ history: [],
1196
+ // Initial history is empty
1197
+ userContext
1198
+ };
1199
+ let node;
1200
+ if (mockMode) {
1201
+ node = mockPlanner(input);
1202
+ } else {
1203
+ const initEvent = {
1204
+ type: "INIT",
1205
+ // Assuming "INIT" is your initial event type
1206
+ nodeId: "system",
1207
+ // Or some other appropriate initial nodeId
1208
+ timestamp: Date.now(),
1209
+ payload: null
1210
+ };
1211
+ const route = router.resolveRoute(
1212
+ initEvent,
1213
+ schema,
1214
+ null,
1215
+ // No existing layout on initial fetch
1216
+ dataContext,
1217
+ goal,
1218
+ userContext
1219
+ );
1220
+ if (!route || !route.prompt) {
1221
+ console.error(
1222
+ "[UIStateEngine] Initial fetch: Failed to resolve route or get prompt for INIT event."
1223
+ );
1224
+ throw new Error("Failed to initialize UI due to routing error.");
1225
+ }
1226
+ systemEvents.emit(
1227
+ createSystemEvent("PLAN_START" /* PLAN_START */, {
1228
+ plannerInput: route.plannerInput
1229
+ })
1230
+ );
1231
+ node = await callPlannerLLM(
1232
+ route.plannerInput,
1233
+ // Use plannerInput from the resolved route
1234
+ openaiApiKey || "",
1235
+ route
1236
+ // Pass the entire route object
1237
+ );
1238
+ }
1239
+ dispatch({ type: "AI_RESPONSE", node });
1240
+ } catch (e) {
1241
+ const errorMessage = e instanceof Error ? e.message : String(e);
1242
+ dispatch({ type: "ERROR", message: errorMessage });
1243
+ systemEvents.emit(
1244
+ // Also emit system event for initial load error
1245
+ createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
1246
+ error: e instanceof Error ? e : new Error(String(e))
1247
+ })
1248
+ );
1249
+ } finally {
1250
+ dispatch({ type: "LOADING", isLoading: false });
1251
+ }
1252
+ };
1253
+ initialFetch();
1254
+ }, [goal, schema, userContext, mockMode, dispatch, openaiApiKey]);
1255
+ return {
1256
+ state,
1257
+ dispatch,
765
1258
  handleEvent
766
1259
  };
767
1260
  }
1261
+
1262
+ // src/adapters/shadcn.tsx
1263
+ init_utils();
1264
+
1265
+ // components/ui/dialog.tsx
1266
+ init_utils();
1267
+ function Dialog({
1268
+ ...props
1269
+ }) {
1270
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
1271
+ }
1272
+ function DialogPortal({
1273
+ ...props
1274
+ }) {
1275
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
1276
+ }
1277
+ function DialogOverlay({
1278
+ className,
1279
+ ...props
1280
+ }) {
1281
+ return /* @__PURE__ */ jsxRuntime.jsx(
1282
+ DialogPrimitive__namespace.Overlay,
1283
+ {
1284
+ "data-slot": "dialog-overlay",
1285
+ className: cn(
1286
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1287
+ className
1288
+ ),
1289
+ ...props
1290
+ }
1291
+ );
1292
+ }
1293
+ function DialogContent({
1294
+ className,
1295
+ children,
1296
+ ...props
1297
+ }) {
1298
+ return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
1299
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1300
+ /* @__PURE__ */ jsxRuntime.jsxs(
1301
+ DialogPrimitive__namespace.Content,
1302
+ {
1303
+ "data-slot": "dialog-content",
1304
+ className: cn(
1305
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
1306
+ className
1307
+ ),
1308
+ ...props,
1309
+ children: [
1310
+ children,
1311
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [
1312
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
1313
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1314
+ ] })
1315
+ ]
1316
+ }
1317
+ )
1318
+ ] });
1319
+ }
1320
+ function DialogHeader({ className, ...props }) {
1321
+ return /* @__PURE__ */ jsxRuntime.jsx(
1322
+ "div",
1323
+ {
1324
+ "data-slot": "dialog-header",
1325
+ className: cn("flex flex-col gap-2 text-center sm:text-left", className),
1326
+ ...props
1327
+ }
1328
+ );
1329
+ }
1330
+ function DialogTitle({
1331
+ className,
1332
+ ...props
1333
+ }) {
1334
+ return /* @__PURE__ */ jsxRuntime.jsx(
1335
+ DialogPrimitive__namespace.Title,
1336
+ {
1337
+ "data-slot": "dialog-title",
1338
+ className: cn("text-lg leading-none font-semibold", className),
1339
+ ...props
1340
+ }
1341
+ );
1342
+ }
1343
+ function DialogDescription({
1344
+ className,
1345
+ ...props
1346
+ }) {
1347
+ return /* @__PURE__ */ jsxRuntime.jsx(
1348
+ DialogPrimitive__namespace.Description,
1349
+ {
1350
+ "data-slot": "dialog-description",
1351
+ className: cn("text-muted-foreground text-sm", className),
1352
+ ...props
1353
+ }
1354
+ );
1355
+ }
1356
+
1357
+ // components/ui/card.tsx
1358
+ init_utils();
1359
+ function Card({ className, ...props }) {
1360
+ return /* @__PURE__ */ jsxRuntime.jsx(
1361
+ "div",
1362
+ {
1363
+ "data-slot": "card",
1364
+ className: cn(
1365
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
1366
+ className
1367
+ ),
1368
+ ...props
1369
+ }
1370
+ );
1371
+ }
1372
+ function CardContent({ className, ...props }) {
1373
+ return /* @__PURE__ */ jsxRuntime.jsx(
1374
+ "div",
1375
+ {
1376
+ "data-slot": "card-content",
1377
+ className: cn("px-6", className),
1378
+ ...props
1379
+ }
1380
+ );
1381
+ }
1382
+
1383
+ // components/ui/input.tsx
1384
+ init_utils();
1385
+ function Input({ className, type, ...props }) {
1386
+ return /* @__PURE__ */ jsxRuntime.jsx(
1387
+ "input",
1388
+ {
1389
+ type,
1390
+ "data-slot": "input",
1391
+ className: cn(
1392
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1393
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
1394
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
1395
+ className
1396
+ ),
1397
+ ...props
1398
+ }
1399
+ );
1400
+ }
1401
+
1402
+ // components/ui/textarea.tsx
1403
+ init_utils();
1404
+ function Textarea({ className, ...props }) {
1405
+ return /* @__PURE__ */ jsxRuntime.jsx(
1406
+ "textarea",
1407
+ {
1408
+ "data-slot": "textarea",
1409
+ className: cn(
1410
+ "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1411
+ className
1412
+ ),
1413
+ ...props
1414
+ }
1415
+ );
1416
+ }
1417
+
1418
+ // components/ui/select.tsx
1419
+ init_utils();
1420
+ function Select({
1421
+ ...props
1422
+ }) {
1423
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Root, { "data-slot": "select", ...props });
1424
+ }
1425
+ function SelectValue({
1426
+ ...props
1427
+ }) {
1428
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Value, { "data-slot": "select-value", ...props });
1429
+ }
1430
+ function SelectTrigger({
1431
+ className,
1432
+ size = "default",
1433
+ children,
1434
+ ...props
1435
+ }) {
1436
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1437
+ SelectPrimitive__namespace.Trigger,
1438
+ {
1439
+ "data-slot": "select-trigger",
1440
+ "data-size": size,
1441
+ className: cn(
1442
+ "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1443
+ className
1444
+ ),
1445
+ ...props,
1446
+ children: [
1447
+ children,
1448
+ /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-4 opacity-50" }) })
1449
+ ]
1450
+ }
1451
+ );
1452
+ }
1453
+ function SelectContent({
1454
+ className,
1455
+ children,
1456
+ position = "popper",
1457
+ ...props
1458
+ }) {
1459
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1460
+ SelectPrimitive__namespace.Content,
1461
+ {
1462
+ "data-slot": "select-content",
1463
+ className: cn(
1464
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
1465
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
1466
+ className
1467
+ ),
1468
+ position,
1469
+ ...props,
1470
+ children: [
1471
+ /* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
1472
+ /* @__PURE__ */ jsxRuntime.jsx(
1473
+ SelectPrimitive__namespace.Viewport,
1474
+ {
1475
+ className: cn(
1476
+ "p-1",
1477
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
1478
+ ),
1479
+ children
1480
+ }
1481
+ ),
1482
+ /* @__PURE__ */ jsxRuntime.jsx(SelectScrollDownButton, {})
1483
+ ]
1484
+ }
1485
+ ) });
1486
+ }
1487
+ function SelectItem({
1488
+ className,
1489
+ children,
1490
+ ...props
1491
+ }) {
1492
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1493
+ SelectPrimitive__namespace.Item,
1494
+ {
1495
+ "data-slot": "select-item",
1496
+ className: cn(
1497
+ "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
1498
+ className
1499
+ ),
1500
+ ...props,
1501
+ children: [
1502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-4" }) }) }),
1503
+ /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
1504
+ ]
1505
+ }
1506
+ );
1507
+ }
1508
+ function SelectScrollUpButton({
1509
+ className,
1510
+ ...props
1511
+ }) {
1512
+ return /* @__PURE__ */ jsxRuntime.jsx(
1513
+ SelectPrimitive__namespace.ScrollUpButton,
1514
+ {
1515
+ "data-slot": "select-scroll-up-button",
1516
+ className: cn(
1517
+ "flex cursor-default items-center justify-center py-1",
1518
+ className
1519
+ ),
1520
+ ...props,
1521
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "size-4" })
1522
+ }
1523
+ );
1524
+ }
1525
+ function SelectScrollDownButton({
1526
+ className,
1527
+ ...props
1528
+ }) {
1529
+ return /* @__PURE__ */ jsxRuntime.jsx(
1530
+ SelectPrimitive__namespace.ScrollDownButton,
1531
+ {
1532
+ "data-slot": "select-scroll-down-button",
1533
+ className: cn(
1534
+ "flex cursor-default items-center justify-center py-1",
1535
+ className
1536
+ ),
1537
+ ...props,
1538
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-4" })
1539
+ }
1540
+ );
1541
+ }
1542
+
1543
+ // components/ui/checkbox.tsx
1544
+ init_utils();
1545
+ function Checkbox({
1546
+ className,
1547
+ ...props
1548
+ }) {
1549
+ return /* @__PURE__ */ jsxRuntime.jsx(
1550
+ CheckboxPrimitive__namespace.Root,
1551
+ {
1552
+ "data-slot": "checkbox",
1553
+ className: cn(
1554
+ "peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
1555
+ className
1556
+ ),
1557
+ ...props,
1558
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1559
+ CheckboxPrimitive__namespace.Indicator,
1560
+ {
1561
+ "data-slot": "checkbox-indicator",
1562
+ className: "flex items-center justify-center text-current transition-none",
1563
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-3.5" })
1564
+ }
1565
+ )
1566
+ }
1567
+ );
1568
+ }
1569
+
1570
+ // components/ui/radio-group.tsx
1571
+ init_utils();
1572
+ function RadioGroup({
1573
+ className,
1574
+ ...props
1575
+ }) {
1576
+ return /* @__PURE__ */ jsxRuntime.jsx(
1577
+ RadioGroupPrimitive__namespace.Root,
1578
+ {
1579
+ "data-slot": "radio-group",
1580
+ className: cn("grid gap-3", className),
1581
+ ...props
1582
+ }
1583
+ );
1584
+ }
1585
+ function RadioGroupItem({
1586
+ className,
1587
+ ...props
1588
+ }) {
1589
+ return /* @__PURE__ */ jsxRuntime.jsx(
1590
+ RadioGroupPrimitive__namespace.Item,
1591
+ {
1592
+ "data-slot": "radio-group-item",
1593
+ className: cn(
1594
+ "border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
1595
+ className
1596
+ ),
1597
+ ...props,
1598
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1599
+ RadioGroupPrimitive__namespace.Indicator,
1600
+ {
1601
+ "data-slot": "radio-group-indicator",
1602
+ className: "relative flex items-center justify-center",
1603
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleIcon, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" })
1604
+ }
1605
+ )
1606
+ }
1607
+ );
1608
+ }
1609
+
1610
+ // components/ui/tabs.tsx
1611
+ init_utils();
1612
+ function Tabs({
1613
+ className,
1614
+ ...props
1615
+ }) {
1616
+ return /* @__PURE__ */ jsxRuntime.jsx(
1617
+ TabsPrimitive__namespace.Root,
1618
+ {
1619
+ "data-slot": "tabs",
1620
+ className: cn("flex flex-col gap-2", className),
1621
+ ...props
1622
+ }
1623
+ );
1624
+ }
1625
+ function TabsList({
1626
+ className,
1627
+ ...props
1628
+ }) {
1629
+ return /* @__PURE__ */ jsxRuntime.jsx(
1630
+ TabsPrimitive__namespace.List,
1631
+ {
1632
+ "data-slot": "tabs-list",
1633
+ className: cn(
1634
+ "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
1635
+ className
1636
+ ),
1637
+ ...props
1638
+ }
1639
+ );
1640
+ }
1641
+ function TabsTrigger({
1642
+ className,
1643
+ ...props
1644
+ }) {
1645
+ return /* @__PURE__ */ jsxRuntime.jsx(
1646
+ TabsPrimitive__namespace.Trigger,
1647
+ {
1648
+ "data-slot": "tabs-trigger",
1649
+ className: cn(
1650
+ "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1651
+ className
1652
+ ),
1653
+ ...props
1654
+ }
1655
+ );
1656
+ }
1657
+ function TabsContent({
1658
+ className,
1659
+ ...props
1660
+ }) {
1661
+ return /* @__PURE__ */ jsxRuntime.jsx(
1662
+ TabsPrimitive__namespace.Content,
1663
+ {
1664
+ "data-slot": "tabs-content",
1665
+ className: cn("flex-1 outline-none", className),
1666
+ ...props
1667
+ }
1668
+ );
1669
+ }
1670
+
1671
+ // components/ui/label.tsx
1672
+ init_utils();
1673
+ function Label2({
1674
+ className,
1675
+ ...props
1676
+ }) {
1677
+ return /* @__PURE__ */ jsxRuntime.jsx(
1678
+ LabelPrimitive__namespace.Root,
1679
+ {
1680
+ "data-slot": "label",
1681
+ className: cn(
1682
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
1683
+ className
1684
+ ),
1685
+ ...props
1686
+ }
1687
+ );
1688
+ }
1689
+ var parseStyleString = (styleString) => {
1690
+ if (typeof styleString !== "string") {
1691
+ return typeof styleString === "object" ? styleString : {};
1692
+ }
1693
+ const style = {};
1694
+ styleString.split(";").forEach((declaration) => {
1695
+ const [property, value] = declaration.split(":");
1696
+ if (property && value) {
1697
+ const camelCasedProperty = property.trim().replace(/-([a-z])/g, (g) => g[1].toUpperCase());
1698
+ style[camelCasedProperty] = value.trim();
1699
+ }
1700
+ });
1701
+ return style;
1702
+ };
1703
+ var isArrayOf = (guard) => (arr) => Array.isArray(arr) && arr.every(guard);
768
1704
  var ShimmerBlock = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-8 bg-gray-200 animate-pulse rounded" });
769
1705
  var ShimmerTable = ({ rows = 3 }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-2", children: [
770
1706
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-10 bg-gray-200 animate-pulse rounded" }),
@@ -778,119 +1714,696 @@ var ShimmerCard = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-f
778
1714
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5/6 h-4 bg-gray-200 animate-pulse rounded" })
779
1715
  ] })
780
1716
  ] });
781
- var Container = (props) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full ${props.className || ""}`, style: props.style, children: props.children });
782
- var Header = ({ title }) => /* @__PURE__ */ jsxRuntime.jsx("header", { className: "py-4 px-6 border-b mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: title }) });
1717
+ var Container = (props) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `autoui-mock-container ${props.className || ""}`, children: props.children });
1718
+ var Header = ({
1719
+ title,
1720
+ className
1721
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
1722
+ "header",
1723
+ {
1724
+ className: `py-4 px-6 border-b border-gray-300 mb-4 bg-gray-50 dark:bg-gray-800 ${className || ""}`,
1725
+ children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-800 dark:text-white", children: title })
1726
+ }
1727
+ );
783
1728
  var Button = ({ onClick, children, variant = "default" }) => /* @__PURE__ */ jsxRuntime.jsx(
784
1729
  "button",
785
1730
  {
786
- className: `px-4 py-2 rounded font-medium ${variant === "default" ? "bg-blue-600 text-white" : variant === "outline" ? "border border-gray-300 text-gray-700" : "bg-red-600 text-white"}`,
787
- onClick,
1731
+ className: `px-4 py-2 rounded-md font-medium transition-colors ${variant === "default" ? "bg-blue-600 text-white hover:bg-blue-700" : variant === "outline" ? "border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800" : "bg-red-600 text-white hover:bg-red-700"}`,
1732
+ onClick: () => onClick?.(),
788
1733
  children
789
1734
  }
790
1735
  );
791
- var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full", children: [
792
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: field.label }, field.key)) }) }),
793
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
794
- "tr",
795
- {
796
- onClick: () => selectable && onSelect && onSelect(item),
797
- className: selectable ? "cursor-pointer hover:bg-gray-50" : "",
798
- children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: item[field.key] }, field.key))
799
- },
800
- index
801
- )) })
802
- ] }) });
803
1736
  var Detail = ({ data, fields = [], title, visible = true, onBack }) => {
804
1737
  if (!visible)
805
1738
  return null;
806
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full border rounded-lg p-6 space-y-4", children: [
807
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
808
- title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-medium", children: title }),
1739
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full border border-gray-300 dark:border-gray-700 rounded-lg p-6 space-y-4 bg-white dark:bg-gray-900 shadow-sm", children: [
1740
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center border-b border-gray-200 dark:border-gray-700 pb-3", children: [
1741
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-medium text-gray-800 dark:text-white", children: title }),
809
1742
  onBack && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: onBack, children: "Back" })
810
1743
  ] }),
811
1744
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: fields.map((field) => {
812
1745
  if (field.type === "heading") {
813
- return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-semibold", children: data?.[field.key] }, field.key);
1746
+ return /* @__PURE__ */ jsxRuntime.jsx(
1747
+ "h3",
1748
+ {
1749
+ className: "text-xl font-semibold text-gray-800 dark:text-white",
1750
+ children: data?.[field.key] ?? ""
1751
+ },
1752
+ field.key
1753
+ );
814
1754
  }
815
1755
  if (field.type === "content") {
816
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-gray-700", children: data?.[field.key] }, field.key);
1756
+ return /* @__PURE__ */ jsxRuntime.jsx(
1757
+ "div",
1758
+ {
1759
+ className: "text-sm text-gray-700 dark:text-gray-300",
1760
+ children: data?.[field.key] ?? ""
1761
+ },
1762
+ field.key
1763
+ );
817
1764
  }
818
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
819
- field.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500", children: field.label }),
820
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: data?.[field.key] })
821
- ] }, field.key);
1765
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1766
+ "div",
1767
+ {
1768
+ className: "flex flex-col border-b border-gray-100 dark:border-gray-800 py-2",
1769
+ children: [
1770
+ field.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400 font-medium", children: field.label }),
1771
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800 dark:text-gray-200", children: data?.[field.key] ?? "" })
1772
+ ]
1773
+ },
1774
+ field.key
1775
+ );
822
1776
  }) })
823
1777
  ] });
824
1778
  };
825
- var createEventHandler = (node, eventName) => {
826
- const eventConfig = node.events?.[eventName];
827
- if (!eventConfig)
1779
+ var getSafeProp = (props, key, validator, defaultValue) => {
1780
+ if (props && typeof props === "object" && key in props) {
1781
+ const value = props[key];
1782
+ if (validator(value)) {
1783
+ return value;
1784
+ }
1785
+ }
1786
+ return defaultValue;
1787
+ };
1788
+ var isObject = (value) => typeof value === "object" && value !== null;
1789
+ var isString = (value) => typeof value === "string";
1790
+ var isBoolean = (value) => typeof value === "boolean";
1791
+ var isButtonVariant = (value) => isString(value) && ["default", "outline", "destructive"].includes(value);
1792
+ var getSafeBinding = (bindings, key, validator, defaultValue) => {
1793
+ if (bindings && typeof bindings === "object" && key in bindings) {
1794
+ const value = bindings[key];
1795
+ if (validator(value)) {
1796
+ return value;
1797
+ }
1798
+ }
1799
+ return defaultValue;
1800
+ };
1801
+ var isReactNode = (value) => {
1802
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || typeof value === "undefined" || typeof value === "object" && value !== null && "$$typeof" in value;
1803
+ };
1804
+ var isRecordWithReactNodeValues = (value) => isObject(value) && Object.values(value).every(isReactNode);
1805
+ var isSelectOptionObject = (item) => isObject(item) && isString(item.value) && isString(item.label);
1806
+ var isTabObject = (item) => (
1807
+ // Allow content to be optional initially
1808
+ isObject(item) && isString(item.value) && isString(item.label) && (item.content === void 0 || isUISpecNode(item.content))
1809
+ );
1810
+ var isUISpecNode = (value) => {
1811
+ if (!isObject(value))
1812
+ return false;
1813
+ return isString(value.id) && isString(value.node_type);
1814
+ };
1815
+ var isDetailFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label) && (item.type === void 0 || isString(item.type));
1816
+ var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
1817
+ const eventConfig = node.events?.[uiEventType2];
1818
+ if (!processEvent2 || !eventConfig)
828
1819
  return void 0;
829
- return () => {
830
- console.log(`Event triggered: ${eventName} on node ${node.id}`, {
831
- action: eventConfig.action,
832
- target: eventConfig.target,
833
- payload: eventConfig.payload
834
- });
1820
+ return (eventPayload) => {
1821
+ const fullEvent = {
1822
+ type: uiEventType2,
1823
+ nodeId: node.id,
1824
+ timestamp: Date.now(),
1825
+ payload: {
1826
+ ...eventConfig.payload || {},
1827
+ ...eventPayload || {}
1828
+ }
1829
+ };
1830
+ processEvent2(fullEvent);
835
1831
  };
836
1832
  };
837
1833
  var adapterMap = {
838
- Container: (node) => /* @__PURE__ */ jsxRuntime.jsx(Container, { style: node.props?.style, className: node.props?.className, children: node.children?.map((child) => renderNode(child)) }),
839
- Header: (node) => /* @__PURE__ */ jsxRuntime.jsx(Header, { title: node.props?.title || "Untitled" }),
840
- Button: (node) => /* @__PURE__ */ jsxRuntime.jsx(
841
- Button,
1834
+ Container: (node, processEvent2) => {
1835
+ const { className, style: styleProp, key, ...restProps } = node.props || {};
1836
+ const children = node.children?.map(
1837
+ (child) => (
1838
+ // Use React.cloneElement to add the key prop to the element returned by renderNode
1839
+ React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
1840
+ )
1841
+ );
1842
+ const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
1843
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1844
+ "div",
1845
+ {
1846
+ className: cn("autoui-container", className),
1847
+ style,
1848
+ ...restProps,
1849
+ "data-id": node.id,
1850
+ children: [
1851
+ (() => {
1852
+ console.log(
1853
+ `[Adapter Debug] Rendering Container: id=${node.id}, props=`,
1854
+ node.props
1855
+ );
1856
+ return null;
1857
+ })(),
1858
+ children
1859
+ ]
1860
+ },
1861
+ key
1862
+ );
1863
+ },
1864
+ Header: (node) => /* @__PURE__ */ jsxRuntime.jsx(
1865
+ Header,
842
1866
  {
843
- variant: node.props?.variant,
844
- onClick: createEventHandler(node, "onClick"),
845
- children: node.props?.label || "Button"
1867
+ title: getSafeProp(node.props, "title", isString, "Untitled"),
1868
+ className: getSafeProp(node.props, "className", isString, "")
846
1869
  }
847
1870
  ),
848
- ListView: (node) => /* @__PURE__ */ jsxRuntime.jsx(
849
- Table,
1871
+ Button: (node, processEvent2) => /* @__PURE__ */ jsxRuntime.jsx(
1872
+ Button,
850
1873
  {
851
- items: node.bindings?.items || [],
852
- fields: node.bindings?.fields || [],
853
- selectable: node.props?.selectable,
854
- onSelect: createEventHandler(node, "onSelect")
1874
+ variant: getSafeProp(node.props, "variant", isButtonVariant, "default"),
1875
+ onClick: createEventHandler(node, "onClick", "CLICK", processEvent2),
1876
+ children: getSafeProp(node.props, "label", isString, "Button")
855
1877
  }
856
1878
  ),
857
- Detail: (node) => /* @__PURE__ */ jsxRuntime.jsx(
858
- Detail,
859
- {
860
- data: node.bindings?.data,
861
- fields: node.bindings?.fields || [],
862
- title: node.props?.title,
863
- visible: node.props?.visible !== false,
864
- onBack: createEventHandler(node, "onBack")
1879
+ ListView: (node, processEvent2) => {
1880
+ const { className, style: styleProp, key, ...restProps } = node.props || {};
1881
+ const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
1882
+ console.log(
1883
+ `[Adapter Debug] Rendering ListView: id=${node.id}, props=`,
1884
+ node.props
1885
+ );
1886
+ const children = node.children?.map(
1887
+ (child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
1888
+ );
1889
+ return /* @__PURE__ */ jsxRuntime.jsx(
1890
+ "div",
1891
+ {
1892
+ className: cn(
1893
+ "autoui-listview-container space-y-2",
1894
+ className
1895
+ ),
1896
+ style,
1897
+ ...restProps,
1898
+ "data-id": node.id,
1899
+ children
1900
+ },
1901
+ key
1902
+ );
1903
+ },
1904
+ Detail: (node, processEvent2) => {
1905
+ const data = getSafeBinding(
1906
+ node.bindings,
1907
+ "data",
1908
+ isRecordWithReactNodeValues,
1909
+ {}
1910
+ );
1911
+ const fields = getSafeBinding(
1912
+ node.bindings,
1913
+ "fields",
1914
+ isArrayOf(isDetailFieldObject),
1915
+ []
1916
+ );
1917
+ const title = getSafeProp(node.props, "title", isString, "");
1918
+ const visible = getSafeProp(node.props, "visible", isBoolean, true);
1919
+ return /* @__PURE__ */ jsxRuntime.jsx(
1920
+ Detail,
1921
+ {
1922
+ data,
1923
+ fields,
1924
+ title,
1925
+ visible,
1926
+ onBack: createEventHandler(node, "onBack", "CLICK", processEvent2)
1927
+ }
1928
+ );
1929
+ },
1930
+ Card: (node, processEvent2) => {
1931
+ const { className, style: styleProp, key, ...restProps } = node.props || {};
1932
+ const children = node.children?.map(
1933
+ (child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
1934
+ );
1935
+ const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
1936
+ return /* @__PURE__ */ jsxRuntime.jsx(
1937
+ Card,
1938
+ {
1939
+ className: cn("autoui-card", className),
1940
+ style,
1941
+ ...restProps,
1942
+ "data-id": node.id,
1943
+ children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-0", children: [
1944
+ " ",
1945
+ children
1946
+ ] })
1947
+ },
1948
+ key
1949
+ );
1950
+ },
1951
+ Input: (node, processEvent2) => {
1952
+ const name = getSafeProp(node.props, "name", isString, "inputName");
1953
+ const label = getSafeProp(node.props, "label", isString, "");
1954
+ const value = getSafeBinding(node.bindings, "value", isString, "");
1955
+ const placeholder = getSafeProp(node.props, "placeholder", isString, "");
1956
+ const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
1957
+ const className = getSafeProp(node.props, "className", isString, "");
1958
+ const handleChange = (e) => {
1959
+ const handler = createEventHandler(
1960
+ node,
1961
+ "onChange",
1962
+ "CHANGE",
1963
+ processEvent2
1964
+ );
1965
+ if (handler)
1966
+ handler({ value: e.target.value });
1967
+ };
1968
+ const handleFocus = () => {
1969
+ const handler = createEventHandler(
1970
+ node,
1971
+ "onFocus",
1972
+ "FOCUS",
1973
+ processEvent2
1974
+ );
1975
+ if (handler)
1976
+ handler({});
1977
+ };
1978
+ const handleBlur = () => {
1979
+ const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
1980
+ if (handler)
1981
+ handler({});
1982
+ };
1983
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid w-full max-w-sm items-center gap-1.5", children: [
1984
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
1985
+ /* @__PURE__ */ jsxRuntime.jsx(
1986
+ Input,
1987
+ {
1988
+ id: name,
1989
+ name,
1990
+ placeholder,
1991
+ disabled,
1992
+ value,
1993
+ onChange: handleChange,
1994
+ onFocus: handleFocus,
1995
+ onBlur: handleBlur,
1996
+ className
1997
+ }
1998
+ )
1999
+ ] });
2000
+ },
2001
+ Select: (node, processEvent2) => {
2002
+ const name = getSafeProp(node.props, "name", isString, "selectName");
2003
+ const label = getSafeProp(node.props, "label", isString, "");
2004
+ const placeholder = getSafeProp(
2005
+ node.props,
2006
+ "placeholder",
2007
+ isString,
2008
+ "Select..."
2009
+ );
2010
+ const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
2011
+ const value = getSafeBinding(node.bindings, "value", isString, "");
2012
+ const options = getSafeBinding(
2013
+ node.bindings,
2014
+ "options",
2015
+ isArrayOf(isSelectOptionObject),
2016
+ []
2017
+ );
2018
+ const className = getSafeProp(node.props, "className", isString, "");
2019
+ const handleValueChange = (selectedValue) => {
2020
+ const handler = createEventHandler(
2021
+ node,
2022
+ "onValueChange",
2023
+ "CHANGE",
2024
+ processEvent2
2025
+ );
2026
+ if (handler)
2027
+ handler({ value: selectedValue });
2028
+ };
2029
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2030
+ "div",
2031
+ {
2032
+ className: cn("grid w-full max-w-sm items-center gap-1.5", className),
2033
+ children: [
2034
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
2035
+ /* @__PURE__ */ jsxRuntime.jsxs(
2036
+ Select,
2037
+ {
2038
+ name,
2039
+ value,
2040
+ onValueChange: handleValueChange,
2041
+ disabled,
2042
+ children: [
2043
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: name, children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder }) }),
2044
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
2045
+ ]
2046
+ }
2047
+ )
2048
+ ]
2049
+ }
2050
+ );
2051
+ },
2052
+ Textarea: (node, processEvent2) => {
2053
+ const { key, ...propsWithoutKey } = node.props || {};
2054
+ const name = getSafeProp(propsWithoutKey, "name", isString, "textareaName");
2055
+ const label = getSafeProp(propsWithoutKey, "label", isString, "");
2056
+ const placeholder = getSafeProp(
2057
+ propsWithoutKey,
2058
+ "placeholder",
2059
+ isString,
2060
+ ""
2061
+ );
2062
+ const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
2063
+ const rows = getSafeProp(
2064
+ propsWithoutKey,
2065
+ "rows",
2066
+ (v) => typeof v === "number",
2067
+ 3
2068
+ );
2069
+ const value = getSafeBinding(node.bindings, "value", isString, "");
2070
+ const className = getSafeProp(propsWithoutKey, "className", isString, "");
2071
+ const handleChange = (e) => {
2072
+ const handler = createEventHandler(
2073
+ node,
2074
+ "onChange",
2075
+ "CHANGE",
2076
+ processEvent2
2077
+ );
2078
+ if (handler)
2079
+ handler({ value: e.target.value });
2080
+ };
2081
+ const handleFocus = () => {
2082
+ const handler = createEventHandler(
2083
+ node,
2084
+ "onFocus",
2085
+ "FOCUS",
2086
+ processEvent2
2087
+ );
2088
+ if (handler)
2089
+ handler({});
2090
+ };
2091
+ const handleBlur = () => {
2092
+ const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
2093
+ if (handler)
2094
+ handler({});
2095
+ };
2096
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid w-full gap-1.5", children: [
2097
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
2098
+ /* @__PURE__ */ jsxRuntime.jsx(
2099
+ Textarea,
2100
+ {
2101
+ id: name,
2102
+ name,
2103
+ placeholder,
2104
+ disabled,
2105
+ rows,
2106
+ value,
2107
+ onChange: handleChange,
2108
+ onFocus: handleFocus,
2109
+ onBlur: handleBlur,
2110
+ className
2111
+ }
2112
+ )
2113
+ ] }, key);
2114
+ },
2115
+ Checkbox: (node, processEvent2) => {
2116
+ const { key, ...propsWithoutKey } = node.props || {};
2117
+ const name = getSafeProp(propsWithoutKey, "name", isString, "checkboxName");
2118
+ const label = getSafeProp(propsWithoutKey, "label", isString, "");
2119
+ const checked = getSafeBinding(node.bindings, "checked", isBoolean, false);
2120
+ const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
2121
+ const className = getSafeProp(propsWithoutKey, "className", isString, "");
2122
+ const handleCheckedChange = (isChecked) => {
2123
+ if (typeof isChecked === "boolean") {
2124
+ const handler = createEventHandler(
2125
+ node,
2126
+ "onCheckedChange",
2127
+ "CHANGE",
2128
+ processEvent2
2129
+ );
2130
+ if (handler)
2131
+ handler({ checked: isChecked });
2132
+ }
2133
+ };
2134
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2135
+ "div",
2136
+ {
2137
+ className: cn("flex items-center space-x-2", className),
2138
+ children: [
2139
+ /* @__PURE__ */ jsxRuntime.jsx(
2140
+ Checkbox,
2141
+ {
2142
+ id: name,
2143
+ name,
2144
+ checked,
2145
+ disabled,
2146
+ onCheckedChange: handleCheckedChange
2147
+ }
2148
+ ),
2149
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, className: "cursor-pointer", children: label })
2150
+ ]
2151
+ },
2152
+ key
2153
+ );
2154
+ },
2155
+ RadioGroup: (node, processEvent2) => {
2156
+ const { key, ...propsWithoutKey } = node.props || {};
2157
+ const name = getSafeProp(
2158
+ propsWithoutKey,
2159
+ "name",
2160
+ isString,
2161
+ "radioGroupName"
2162
+ );
2163
+ const label = getSafeProp(propsWithoutKey, "label", isString, "");
2164
+ const value = getSafeBinding(node.bindings, "value", isString, "");
2165
+ const options = getSafeBinding(
2166
+ node.bindings,
2167
+ "options",
2168
+ isArrayOf(isSelectOptionObject),
2169
+ []
2170
+ );
2171
+ const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
2172
+ const className = getSafeProp(propsWithoutKey, "className", isString, "");
2173
+ const handleValueChange = (selectedValue) => {
2174
+ const handler = createEventHandler(
2175
+ node,
2176
+ "onValueChange",
2177
+ "CHANGE",
2178
+ processEvent2
2179
+ );
2180
+ if (handler)
2181
+ handler({ value: selectedValue });
2182
+ };
2183
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2184
+ "div",
2185
+ {
2186
+ className: cn("grid gap-1.5", className),
2187
+ children: [
2188
+ label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { className: "mb-1", children: label }),
2189
+ /* @__PURE__ */ jsxRuntime.jsx(
2190
+ RadioGroup,
2191
+ {
2192
+ name,
2193
+ value,
2194
+ onValueChange: handleValueChange,
2195
+ disabled,
2196
+ className: "flex flex-col space-y-1",
2197
+ children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
2198
+ /* @__PURE__ */ jsxRuntime.jsx(
2199
+ RadioGroupItem,
2200
+ {
2201
+ value: option.value,
2202
+ id: `${name}-${option.value}`
2203
+ }
2204
+ ),
2205
+ /* @__PURE__ */ jsxRuntime.jsx(
2206
+ Label2,
2207
+ {
2208
+ htmlFor: `${name}-${option.value}`,
2209
+ className: "cursor-pointer",
2210
+ children: option.label
2211
+ }
2212
+ )
2213
+ ] }, option.value))
2214
+ }
2215
+ )
2216
+ ]
2217
+ },
2218
+ key
2219
+ );
2220
+ },
2221
+ Tabs: (node, processEvent2) => {
2222
+ const { key, ...propsWithoutKey } = node.props || {};
2223
+ const rawTabs = getSafeBinding(
2224
+ node.bindings,
2225
+ "tabs",
2226
+ isArrayOf(isTabObject),
2227
+ []
2228
+ );
2229
+ const defaultValue = getSafeProp(
2230
+ propsWithoutKey,
2231
+ "defaultValue",
2232
+ isString,
2233
+ rawTabs[0]?.value || ""
2234
+ );
2235
+ const className = getSafeProp(propsWithoutKey, "className", isString, "");
2236
+ const handleValueChange = (value) => {
2237
+ const handler = createEventHandler(
2238
+ node,
2239
+ "onValueChange",
2240
+ "CHANGE",
2241
+ processEvent2
2242
+ );
2243
+ if (handler)
2244
+ handler({ value });
2245
+ };
2246
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2247
+ Tabs,
2248
+ {
2249
+ defaultValue,
2250
+ onValueChange: handleValueChange,
2251
+ className: cn("autoui-tabs w-full", className),
2252
+ "data-id": node.id,
2253
+ children: [
2254
+ /* @__PURE__ */ jsxRuntime.jsx(TabsList, { children: rawTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { value: tab.value, children: tab.label }, tab.value)) }),
2255
+ rawTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: tab.value, children: tab.content ? renderNode(tab.content, processEvent2) : null }, tab.value))
2256
+ ]
2257
+ },
2258
+ key
2259
+ );
2260
+ },
2261
+ Dialog: (node, processEvent2) => {
2262
+ const isOpen = getSafeBinding(
2263
+ node.bindings,
2264
+ "open",
2265
+ isBoolean,
2266
+ getSafeProp(node.props, "open", isBoolean, false)
2267
+ );
2268
+ const {
2269
+ title,
2270
+ description,
2271
+ className,
2272
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2273
+ style: _styleProp,
2274
+ key,
2275
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2276
+ open: _openProp,
2277
+ ...restProps
2278
+ } = node.props || {};
2279
+ const children = node.children?.map(
2280
+ (child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
2281
+ );
2282
+ const handleOpenChange = (open) => {
2283
+ if (!open) {
2284
+ const handler = createEventHandler(
2285
+ node,
2286
+ "onClose",
2287
+ // Assumed event name in UISpec
2288
+ "CLICK",
2289
+ // Use CLICK as the event type for closing dialogs
2290
+ processEvent2
2291
+ );
2292
+ if (handler) {
2293
+ handler({});
2294
+ }
2295
+ }
2296
+ };
2297
+ console.log(
2298
+ `[Adapter Debug] Rendering Dialog: id=${node.id}, props=`,
2299
+ node.props,
2300
+ `isOpen=${isOpen}`
2301
+ );
2302
+ return /* @__PURE__ */ jsxRuntime.jsx(
2303
+ Dialog,
2304
+ {
2305
+ open: isOpen,
2306
+ onOpenChange: handleOpenChange,
2307
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2308
+ DialogContent,
2309
+ {
2310
+ className: cn("autoui-dialog-content", className),
2311
+ ...restProps,
2312
+ "data-id": node.id,
2313
+ children: [
2314
+ (title || description) && /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
2315
+ title && /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
2316
+ description && /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
2317
+ ] }),
2318
+ children
2319
+ ]
2320
+ }
2321
+ )
2322
+ },
2323
+ key
2324
+ );
2325
+ },
2326
+ Heading: (node) => {
2327
+ const { className, style: styleProp, key, ...restProps } = node.props || {};
2328
+ const text = getSafeProp(node.props, "text", isString, "Heading");
2329
+ let level = getSafeProp(
2330
+ node.props,
2331
+ "level",
2332
+ (v) => typeof v === "number" && v >= 1 && v <= 6,
2333
+ 2
2334
+ );
2335
+ if (typeof level !== "number" || level < 1 || level > 6) {
2336
+ level = 2;
865
2337
  }
866
- )
2338
+ const Tag = `h${level}`;
2339
+ const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
2340
+ const headingStyles = {
2341
+ 1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl",
2342
+ 2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0",
2343
+ 3: "scroll-m-20 text-2xl font-semibold tracking-tight",
2344
+ 4: "scroll-m-20 text-xl font-semibold tracking-tight"
2345
+ // Add styles for h5, h6 if needed, using text-lg, text-base etc.
2346
+ }[level] || "text-lg font-semibold";
2347
+ return /* @__PURE__ */ jsxRuntime.jsx(
2348
+ Tag,
2349
+ {
2350
+ className: cn(headingStyles, className),
2351
+ style,
2352
+ ...restProps,
2353
+ children: text
2354
+ },
2355
+ key
2356
+ );
2357
+ },
2358
+ Text: (node) => {
2359
+ const { className, style: styleProp, key, ...restProps } = node.props || {};
2360
+ const text = getSafeProp(node.props, "text", isString, "Some text");
2361
+ const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
2362
+ return /* @__PURE__ */ jsxRuntime.jsx(
2363
+ "p",
2364
+ {
2365
+ className: cn("leading-7", className),
2366
+ style,
2367
+ ...restProps,
2368
+ children: text
2369
+ },
2370
+ key
2371
+ );
2372
+ }
867
2373
  };
868
- function renderNode(node) {
869
- const Component = adapterMap[node.type];
870
- if (Component) {
871
- return Component(node);
872
- }
873
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 border border-red-300 rounded", children: [
874
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-red-500", children: [
875
- "Unsupported component: ",
876
- node.type
877
- ] }),
878
- node.children?.map((child) => renderNode(child))
879
- ] });
2374
+ function renderNode(node, processEvent2) {
2375
+ const mappedComponent = adapterMap[node.node_type];
2376
+ if (mappedComponent) {
2377
+ return mappedComponent(node, processEvent2);
2378
+ }
2379
+ console.warn(`Unknown node type: ${node.node_type}`);
2380
+ return React__default.default.createElement(
2381
+ Container,
2382
+ {},
2383
+ `Unknown node type: ${node.node_type}`
2384
+ );
880
2385
  }
881
- async function renderNode2(node, adapter = "shadcn") {
2386
+ var renderedNodesCache = /* @__PURE__ */ new Map();
2387
+ var MAX_CACHE_SIZE = 10;
2388
+ var CACHE_TTL = 5e3;
2389
+ async function renderNode2(node, adapter = "shadcn", processEvent2) {
882
2390
  const startTime = Date.now();
2391
+ const nodeId = node.id;
2392
+ const cachedItem = renderedNodesCache.get(nodeId);
2393
+ if (cachedItem && startTime - cachedItem.timestamp < CACHE_TTL) {
2394
+ return cachedItem.element;
2395
+ }
883
2396
  await systemEvents.emit(
884
2397
  createSystemEvent("RENDER_START" /* RENDER_START */, { layout: node })
885
2398
  );
886
2399
  let result;
887
2400
  switch (adapter) {
888
2401
  case "shadcn":
889
- result = renderNode(node);
2402
+ result = renderNode(node, processEvent2);
890
2403
  break;
891
2404
  default:
892
2405
  console.warn(`Unsupported adapter: ${adapter}, falling back to shadcn`);
893
- result = renderNode(node);
2406
+ result = renderNode(node, processEvent2);
894
2407
  }
895
2408
  await systemEvents.emit(
896
2409
  createSystemEvent("RENDER_COMPLETE" /* RENDER_COMPLETE */, {
@@ -898,13 +2411,23 @@ async function renderNode2(node, adapter = "shadcn") {
898
2411
  renderTimeMs: Date.now() - startTime
899
2412
  })
900
2413
  );
2414
+ renderedNodesCache.set(nodeId, {
2415
+ element: result,
2416
+ timestamp: startTime
2417
+ });
2418
+ if (renderedNodesCache.size > MAX_CACHE_SIZE) {
2419
+ const oldestKey = [...renderedNodesCache.entries()].sort(
2420
+ ([, a], [, b]) => a.timestamp - b.timestamp
2421
+ )[0][0];
2422
+ renderedNodesCache.delete(oldestKey);
2423
+ }
901
2424
  return result;
902
2425
  }
903
2426
  function renderShimmer(node, adapter = "shadcn") {
904
2427
  if (!node) {
905
2428
  return /* @__PURE__ */ jsxRuntime.jsx(ShimmerBlock, {});
906
2429
  }
907
- switch (node.type) {
2430
+ switch (node.node_type) {
908
2431
  case "ListView":
909
2432
  return /* @__PURE__ */ jsxRuntime.jsx(ShimmerTable, { rows: 3 });
910
2433
  case "Detail":
@@ -917,6 +2440,16 @@ function renderShimmer(node, adapter = "shadcn") {
917
2440
  }
918
2441
 
919
2442
  // src/core/bindings.ts
2443
+ var bindingsCache = /* @__PURE__ */ new Map();
2444
+ var MAX_CACHE_SIZE2 = 50;
2445
+ var CACHE_TTL2 = 2e3;
2446
+ var nodeCacheTimestamps = /* @__PURE__ */ new Map();
2447
+ function hashDataContext(context) {
2448
+ return JSON.stringify(context);
2449
+ }
2450
+ function createCacheKey(nodeId, context) {
2451
+ return `${nodeId}:${hashDataContext(context)}`;
2452
+ }
920
2453
  function getValueByPath(context, path) {
921
2454
  const parts = path.split(".");
922
2455
  let current = context;
@@ -932,68 +2465,265 @@ function getValueByPath(context, path) {
932
2465
  return current;
933
2466
  }
934
2467
  function setValueByPath(context, path, value) {
2468
+ if (!path) {
2469
+ return context;
2470
+ }
935
2471
  const result = { ...context };
936
2472
  const parts = path.split(".");
937
2473
  let current = result;
938
2474
  for (let i = 0; i < parts.length - 1; i++) {
939
2475
  const part = parts[i];
940
- if (!(part in current) || current[part] === null || current[part] === void 0) {
941
- current[part] = {};
2476
+ if (typeof current !== "object" || current === null) {
2477
+ console.warn(
2478
+ `setValueByPath: Cannot traverse path "${path}". Parent segment "${parts[i - 1] || "(root)"}" is not an object.`
2479
+ );
2480
+ return context;
942
2481
  }
943
- current = current[part];
944
- if (typeof current !== "object") {
945
- current = {};
2482
+ const currentAsObject = current;
2483
+ const nextPartValue = currentAsObject[part];
2484
+ if (nextPartValue === void 0 || nextPartValue === null) {
2485
+ currentAsObject[part] = {};
2486
+ } else if (typeof nextPartValue !== "object") {
2487
+ console.warn(
2488
+ `setValueByPath: Cannot create nested path "${path}". Segment "${part}" is not an object.`
2489
+ );
2490
+ return context;
2491
+ } else {
2492
+ currentAsObject[part] = { ...nextPartValue };
946
2493
  }
2494
+ current = currentAsObject[part];
947
2495
  }
948
2496
  const lastPart = parts[parts.length - 1];
949
- current[lastPart] = value;
2497
+ if (typeof current === "object" && current !== null) {
2498
+ current[lastPart] = value;
2499
+ } else {
2500
+ console.warn(
2501
+ `setValueByPath: Could not set value for path "${path}". Final segment parent is not an object.`
2502
+ );
2503
+ return context;
2504
+ }
950
2505
  return result;
951
2506
  }
952
- function processBinding(binding, context) {
2507
+ function processBinding(binding, context, itemData) {
953
2508
  if (typeof binding === "string") {
954
- return getValueByPath(context, binding);
2509
+ const exactMatchArr = binding.match(/^{{(.*)}}$/);
2510
+ const pathInsideExact = exactMatchArr ? exactMatchArr[1].trim() : null;
2511
+ if (pathInsideExact !== null && !pathInsideExact.includes("{{") && !pathInsideExact.includes("}}")) {
2512
+ const pathToResolve = pathInsideExact;
2513
+ let resolvedValue = void 0;
2514
+ console.log(
2515
+ `[processBinding Debug] Processing EXACT template: "${binding}", Path: "${pathToResolve}", Has itemData: ${!!itemData}`
2516
+ );
2517
+ if (itemData) {
2518
+ try {
2519
+ console.log(
2520
+ `[processBinding Debug] itemData content (EXACT):`,
2521
+ JSON.parse(JSON.stringify(itemData))
2522
+ );
2523
+ } catch {
2524
+ }
2525
+ }
2526
+ if ((pathToResolve.startsWith("item.") || pathToResolve.startsWith("row.")) && itemData) {
2527
+ if (pathToResolve.startsWith("item.")) {
2528
+ resolvedValue = getValueByPath(itemData, pathToResolve.substring(5));
2529
+ } else {
2530
+ resolvedValue = getValueByPath(itemData, pathToResolve.substring(4));
2531
+ }
2532
+ } else if (itemData && pathToResolve in itemData) {
2533
+ resolvedValue = getValueByPath(itemData, pathToResolve);
2534
+ }
2535
+ if (resolvedValue === void 0) {
2536
+ resolvedValue = getValueByPath(context, pathToResolve);
2537
+ }
2538
+ return resolvedValue;
2539
+ } else if (binding.includes("{{") && binding.includes("}}")) {
2540
+ console.log(
2541
+ `[processBinding Debug] Processing EMBEDDED templates: "${binding}", Has itemData: ${!!itemData}`
2542
+ );
2543
+ if (itemData) {
2544
+ try {
2545
+ console.log(
2546
+ `[processBinding Debug] itemData content (EMBEDDED):`,
2547
+ JSON.parse(JSON.stringify(itemData))
2548
+ );
2549
+ } catch {
2550
+ }
2551
+ }
2552
+ const resolvedString = binding.replaceAll(
2553
+ /{{(.*?)}}/g,
2554
+ // Non-greedy match inside braces
2555
+ (match, path) => {
2556
+ const trimmedPath = path.trim();
2557
+ let resolvedValue = void 0;
2558
+ if ((trimmedPath.startsWith("item.") || trimmedPath.startsWith("row.")) && itemData) {
2559
+ if (trimmedPath.startsWith("item.")) {
2560
+ resolvedValue = getValueByPath(
2561
+ itemData,
2562
+ trimmedPath.substring(5)
2563
+ );
2564
+ } else {
2565
+ resolvedValue = getValueByPath(
2566
+ itemData,
2567
+ trimmedPath.substring(4)
2568
+ );
2569
+ }
2570
+ } else if (itemData && trimmedPath in itemData) {
2571
+ resolvedValue = getValueByPath(itemData, trimmedPath);
2572
+ }
2573
+ if (resolvedValue === void 0) {
2574
+ resolvedValue = getValueByPath(context, trimmedPath);
2575
+ }
2576
+ return resolvedValue === null || resolvedValue === void 0 ? "" : String(resolvedValue);
2577
+ }
2578
+ );
2579
+ return resolvedString;
2580
+ } else {
2581
+ const pathToResolve = binding;
2582
+ let resolvedValue = void 0;
2583
+ console.log(
2584
+ `[processBinding Debug] Processing PATH string: "${pathToResolve}", Has itemData: ${!!itemData}`
2585
+ );
2586
+ if (itemData && !pathToResolve.includes(".") && pathToResolve in itemData) {
2587
+ resolvedValue = getValueByPath(itemData, pathToResolve);
2588
+ }
2589
+ if (resolvedValue === void 0) {
2590
+ resolvedValue = getValueByPath(context, pathToResolve);
2591
+ }
2592
+ return resolvedValue;
2593
+ }
955
2594
  }
956
2595
  if (Array.isArray(binding)) {
957
- return binding.map((item) => processBinding(item, context));
2596
+ return binding.map((item) => processBinding(item, context, itemData));
958
2597
  }
959
2598
  if (binding !== null && typeof binding === "object") {
960
2599
  const result = {};
961
2600
  for (const [key, value] of Object.entries(binding)) {
962
- result[key] = processBinding(value, context);
2601
+ result[key] = processBinding(value, context, itemData);
963
2602
  }
964
2603
  return result;
965
2604
  }
966
2605
  return binding;
967
2606
  }
968
- async function resolveBindings(node, context) {
969
- await systemEvents.emit(
970
- createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, { layout: node })
971
- );
2607
+ async function resolveBindings(node, context, itemData) {
2608
+ const effectiveContext = itemData ? { ...context, item: itemData } : context;
2609
+ const currentTime = Date.now();
2610
+ const cacheKey = createCacheKey(node.id, effectiveContext);
2611
+ const cachedNode = bindingsCache.get(cacheKey);
2612
+ const cachedTimestamp = nodeCacheTimestamps.get(cacheKey);
2613
+ if (cachedNode && cachedTimestamp && currentTime - cachedTimestamp < CACHE_TTL2) {
2614
+ return cachedNode;
2615
+ }
2616
+ if (!itemData) {
2617
+ await systemEvents.emit(
2618
+ createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, {
2619
+ layout: node
2620
+ })
2621
+ );
2622
+ }
972
2623
  const result = {
973
2624
  ...node,
974
- props: node.props ? { ...node.props } : void 0,
975
- events: node.events ? { ...node.events } : void 0
2625
+ props: node.props ? JSON.parse(JSON.stringify(node.props)) : null,
2626
+ events: node.events ? JSON.parse(JSON.stringify(node.events)) : null,
2627
+ bindings: node.bindings ? JSON.parse(JSON.stringify(node.bindings)) : null,
2628
+ children: null
2629
+ // Initialize children to null
976
2630
  };
2631
+ const resolvedBindings = {};
977
2632
  if (node.bindings) {
978
- for (const [key, binding] of Object.entries(node.bindings)) {
979
- const value = processBinding(binding, context);
980
- if (value !== void 0) {
981
- if (!result.props) {
2633
+ for (const [key, bindingValue] of Object.entries(node.bindings)) {
2634
+ const resolvedValue = processBinding(bindingValue, context, itemData);
2635
+ resolvedBindings[key] = resolvedValue;
2636
+ if (resolvedValue !== void 0) {
2637
+ if (!result.props)
982
2638
  result.props = {};
983
- }
984
- result.props[key] = value;
2639
+ result.props[key] = resolvedValue;
985
2640
  }
986
2641
  }
987
2642
  }
988
- if (node.children) {
989
- result.children = await Promise.all(node.children.map((child) => resolveBindings(child, context)));
2643
+ result.bindings = null;
2644
+ if (node.events) {
2645
+ result.events = processBinding(
2646
+ node.events,
2647
+ context,
2648
+ itemData
2649
+ );
2650
+ } else {
2651
+ result.events = null;
2652
+ }
2653
+ const dataBindingValue = resolvedBindings["data"] ?? resolvedBindings["items"];
2654
+ if ((node.node_type === "ListView" || node.node_type === "Table") && Array.isArray(dataBindingValue) && node.children && node.children.length > 0) {
2655
+ const templateChild = node.children[0];
2656
+ const mappedChildren = await Promise.all(
2657
+ dataBindingValue.map(async (currentItemData, index) => {
2658
+ try {
2659
+ if (typeof currentItemData !== "object" || currentItemData === null) {
2660
+ console.warn(
2661
+ `List item at index ${index} for node ${node.id} is not an object:`,
2662
+ currentItemData
2663
+ );
2664
+ return null;
2665
+ }
2666
+ const currentItemAsRecord = currentItemData;
2667
+ const itemId = currentItemAsRecord.id;
2668
+ const instanceId = `${templateChild.id}-${itemId || index}`;
2669
+ const childNodeInstance = JSON.parse(
2670
+ JSON.stringify(templateChild)
2671
+ );
2672
+ childNodeInstance.id = instanceId;
2673
+ const resolvedChild = await resolveBindings(
2674
+ childNodeInstance,
2675
+ context,
2676
+ currentItemAsRecord
2677
+ );
2678
+ if (!resolvedChild.props)
2679
+ resolvedChild.props = {};
2680
+ resolvedChild.props.key = itemId || `${node.id}-item-${index}`;
2681
+ return resolvedChild;
2682
+ } catch (error) {
2683
+ console.error(
2684
+ `[resolveBindings Error] Error processing item at index ${index} for node ${node.id}:`,
2685
+ error,
2686
+ "Item Data:",
2687
+ currentItemData
2688
+ );
2689
+ return null;
2690
+ }
2691
+ })
2692
+ );
2693
+ result.children = mappedChildren.filter(
2694
+ (child) => child !== null
2695
+ );
2696
+ } else if (node.children && node.children.length > 0) {
2697
+ result.children = await Promise.all(
2698
+ node.children.map((child) => resolveBindings(child, context, itemData))
2699
+ );
2700
+ } else {
2701
+ result.children = [];
2702
+ }
2703
+ if (!itemData) {
2704
+ await systemEvents.emit(
2705
+ createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
2706
+ originalLayout: node,
2707
+ resolvedLayout: result
2708
+ })
2709
+ );
2710
+ }
2711
+ bindingsCache.set(cacheKey, result);
2712
+ nodeCacheTimestamps.set(cacheKey, currentTime);
2713
+ if (bindingsCache.size > MAX_CACHE_SIZE2) {
2714
+ let oldestKey = null;
2715
+ let oldestTimestamp = currentTime;
2716
+ for (const [key, timestamp] of nodeCacheTimestamps.entries()) {
2717
+ if (timestamp < oldestTimestamp) {
2718
+ oldestTimestamp = timestamp;
2719
+ oldestKey = key;
2720
+ }
2721
+ }
2722
+ if (oldestKey) {
2723
+ bindingsCache.delete(oldestKey);
2724
+ nodeCacheTimestamps.delete(oldestKey);
2725
+ }
990
2726
  }
991
- await systemEvents.emit(
992
- createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
993
- originalLayout: node,
994
- resolvedLayout: result
995
- })
996
- );
997
2727
  return result;
998
2728
  }
999
2729
  function executeAction(action, targetId, payload, context = {}, layoutTree) {
@@ -1029,7 +2759,7 @@ var EventManager = class {
1029
2759
  }
1030
2760
  /**
1031
2761
  * Register a hook for specific event types
1032
- *
2762
+ *
1033
2763
  * @param eventTypes - Event types to register for, or 'all' for all events
1034
2764
  * @param hook - Hook function to execute
1035
2765
  * @returns Unregister function
@@ -1062,7 +2792,7 @@ var EventManager = class {
1062
2792
  }
1063
2793
  /**
1064
2794
  * Process an event through all registered hooks
1065
- *
2795
+ *
1066
2796
  * @param event - The UI event to process
1067
2797
  * @returns Whether the default action should proceed
1068
2798
  */
@@ -1108,6 +2838,45 @@ function createEventHook(eventTypes, hook, options) {
1108
2838
  }
1109
2839
  };
1110
2840
  }
2841
+
2842
+ // src/core/component-detection.ts
2843
+ function areShadcnComponentsAvailable() {
2844
+ try {
2845
+ init_button();
2846
+ return true;
2847
+ } catch (error) {
2848
+ return false;
2849
+ }
2850
+ }
2851
+ function getMissingComponentsMessage() {
2852
+ return `Missing required shadcn components. Please run:
2853
+ > npm run setup-shadcn`;
2854
+ }
2855
+ function correctListBindingsRecursive(node, dataContext) {
2856
+ const correctedNode = JSON.parse(JSON.stringify(node));
2857
+ if ((correctedNode.node_type === "ListView" || correctedNode.node_type === "Table") && correctedNode.bindings?.data) {
2858
+ const bindingPath = correctedNode.bindings.data;
2859
+ if (typeof bindingPath === "string") {
2860
+ const pathSegments = bindingPath.split(".");
2861
+ const mainKey = pathSegments[0];
2862
+ if (pathSegments.length === 1) {
2863
+ const potentialDataContextEntry = dataContext[mainKey];
2864
+ if (potentialDataContextEntry && typeof potentialDataContextEntry === "object" && potentialDataContextEntry !== null && "data" in potentialDataContextEntry && Array.isArray(potentialDataContextEntry.data)) {
2865
+ correctedNode.bindings.data = `${mainKey}.data`;
2866
+ console.log(
2867
+ `[AutoUI Debug] Corrected list binding for node '${correctedNode.id}': from '${mainKey}' to '${mainKey}.data'`
2868
+ );
2869
+ }
2870
+ }
2871
+ }
2872
+ }
2873
+ if (correctedNode.children) {
2874
+ correctedNode.children = correctedNode.children.map(
2875
+ (child) => correctListBindingsRecursive(child, dataContext)
2876
+ );
2877
+ }
2878
+ return correctedNode;
2879
+ }
1111
2880
  var AutoUI = ({
1112
2881
  schema,
1113
2882
  goal,
@@ -1117,25 +2886,34 @@ var AutoUI = ({
1117
2886
  eventHooks,
1118
2887
  systemEventHooks,
1119
2888
  debugMode = false,
1120
- mockMode = true,
1121
- databaseConfig,
2889
+ mockMode = false,
1122
2890
  planningConfig,
1123
2891
  integration = {},
1124
2892
  scope = {},
1125
- enablePartialUpdates = false
2893
+ enablePartialUpdates = false,
2894
+ openaiApiKey
1126
2895
  }) => {
1127
- const [schemaAdapterInstance, setSchemaAdapterInstance] = react.useState(null);
1128
- const [dataContext, setDataContext] = react.useState({});
2896
+ const [schemaAdapterInstance] = React.useState(null);
2897
+ const [dataContext, setDataContext] = React.useState({});
2898
+ const [componentsAvailable, setComponentsAvailable] = React.useState(true);
1129
2899
  const effectiveSchema = schema;
1130
2900
  const scopedGoal = goal;
1131
- react.useEffect(() => {
2901
+ React.useEffect(() => {
2902
+ if (componentAdapter === "shadcn") {
2903
+ setComponentsAvailable(areShadcnComponentsAvailable());
2904
+ }
2905
+ }, [componentAdapter]);
2906
+ React.useEffect(() => {
1132
2907
  const unregisters = [];
1133
2908
  if (systemEventHooks) {
1134
2909
  Object.entries(systemEventHooks).forEach(([eventType, hooks]) => {
1135
2910
  if (!hooks)
1136
2911
  return;
1137
2912
  hooks.forEach((hook) => {
1138
- const unregister = systemEvents.on(eventType, hook);
2913
+ const unregister = systemEvents.on(
2914
+ eventType,
2915
+ hook
2916
+ );
1139
2917
  unregisters.push(unregister);
1140
2918
  });
1141
2919
  });
@@ -1144,7 +2922,9 @@ var AutoUI = ({
1144
2922
  const debugHook = (event) => {
1145
2923
  console.debug(`[AutoUI Debug] System Event:`, event);
1146
2924
  };
1147
- Object.values(SystemEventType).forEach((eventType) => {
2925
+ Object.values(SystemEventType).filter(
2926
+ (eventType) => eventType !== "RENDER_START" /* RENDER_START */ && eventType !== "BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */
2927
+ ).forEach((eventType) => {
1148
2928
  const unregister = systemEvents.on(eventType, debugHook);
1149
2929
  unregisters.push(unregister);
1150
2930
  });
@@ -1153,7 +2933,7 @@ var AutoUI = ({
1153
2933
  unregisters.forEach((unregister) => unregister());
1154
2934
  };
1155
2935
  }, [systemEventHooks, debugMode]);
1156
- react.useEffect(() => {
2936
+ React.useEffect(() => {
1157
2937
  const initializeDataContext = async () => {
1158
2938
  let initialData = {};
1159
2939
  if (schemaAdapterInstance) {
@@ -1183,103 +2963,162 @@ var AutoUI = ({
1183
2963
  planningConfig,
1184
2964
  router: void 0,
1185
2965
  dataContext,
1186
- enablePartialUpdates
2966
+ enablePartialUpdates,
2967
+ openaiApiKey
1187
2968
  });
1188
- const eventManagerRef = react.useRef(new EventManager());
1189
- react.useEffect(() => {
2969
+ const eventManagerRef = React.useRef(new EventManager());
2970
+ React.useEffect(() => {
1190
2971
  if (!eventHooks)
1191
2972
  return;
1192
2973
  const unregisters = [];
1193
2974
  if (eventHooks.all) {
1194
- const unregister = eventManagerRef.current.register("all", async (ctx) => {
1195
- for (const hook of eventHooks.all || []) {
1196
- await hook(ctx);
1197
- if (ctx.isPropagationStopped())
1198
- break;
2975
+ const unregister = eventManagerRef.current.register(
2976
+ "all",
2977
+ async (ctx) => {
2978
+ for (const hook of eventHooks.all || []) {
2979
+ await hook(ctx);
2980
+ if (ctx.isPropagationStopped())
2981
+ break;
2982
+ }
1199
2983
  }
1200
- });
2984
+ );
1201
2985
  unregisters.push(unregister);
1202
2986
  }
1203
2987
  Object.entries(eventHooks).forEach(([type, hooks]) => {
1204
2988
  if (type === "all" || !hooks)
1205
2989
  return;
1206
- const unregister = eventManagerRef.current.register([type], async (ctx) => {
1207
- for (const hook of hooks) {
1208
- await hook(ctx);
1209
- if (ctx.isPropagationStopped())
1210
- break;
2990
+ const unregister = eventManagerRef.current.register(
2991
+ [type],
2992
+ async (ctx) => {
2993
+ for (const hook of hooks) {
2994
+ await hook(ctx);
2995
+ if (ctx.isPropagationStopped())
2996
+ break;
2997
+ }
1211
2998
  }
1212
- });
2999
+ );
1213
3000
  unregisters.push(unregister);
1214
3001
  });
1215
3002
  return () => {
1216
3003
  unregisters.forEach((unregister) => unregister());
1217
3004
  };
1218
3005
  }, [eventHooks]);
1219
- react.useCallback(async (event) => {
1220
- const shouldProceed = await eventManagerRef.current.processEvent(event);
1221
- if (onEvent) {
1222
- onEvent(event);
1223
- }
1224
- if (!shouldProceed) {
1225
- console.info("Event processing was prevented by hooks", event);
1226
- return;
1227
- }
1228
- const findNodeById2 = (node, id) => {
1229
- if (!node)
1230
- return void 0;
1231
- if (node.id === id)
1232
- return node;
1233
- if (node.children) {
1234
- for (const child of node.children) {
1235
- const found = findNodeById2(child, id);
1236
- if (found)
1237
- return found;
3006
+ const processEvent2 = React.useCallback(
3007
+ async (event) => {
3008
+ const shouldProceed = await eventManagerRef.current.processEvent(event);
3009
+ if (onEvent) {
3010
+ onEvent(event);
3011
+ }
3012
+ if (!shouldProceed) {
3013
+ console.info("Event processing was prevented by hooks", event);
3014
+ return;
3015
+ }
3016
+ const findNodeById2 = (node, id) => {
3017
+ if (!node)
3018
+ return void 0;
3019
+ if (node.id === id)
3020
+ return node;
3021
+ if (node.children) {
3022
+ for (const child of node.children) {
3023
+ const found = findNodeById2(child, id);
3024
+ if (found)
3025
+ return found;
3026
+ }
1238
3027
  }
3028
+ return void 0;
3029
+ };
3030
+ const sourceNode = findNodeById2(state.layout, event.nodeId);
3031
+ if (!sourceNode) {
3032
+ console.warn(`Node not found for event: ${event.nodeId}`);
3033
+ handleEvent(event);
3034
+ return;
1239
3035
  }
1240
- return void 0;
1241
- };
1242
- const sourceNode = findNodeById2(state.layout, event.nodeId);
1243
- if (!sourceNode) {
1244
- console.warn(`Node not found for event: ${event.nodeId}`);
1245
- handleEvent(event);
1246
- return;
1247
- }
1248
- const eventConfig = sourceNode.events?.[event.type];
1249
- if (!eventConfig) {
1250
- console.warn(`No event config found for ${event.type} on node ${event.nodeId}`);
3036
+ const eventConfig = sourceNode.events?.[event.type];
3037
+ if (!eventConfig) {
3038
+ console.warn(
3039
+ `No event config found for ${event.type} on node ${event.nodeId}`
3040
+ );
3041
+ handleEvent(event);
3042
+ return;
3043
+ }
3044
+ const newContext = executeAction(
3045
+ eventConfig.action,
3046
+ eventConfig.target || "",
3047
+ // Provide empty string as fallback if target is null
3048
+ {
3049
+ ...eventConfig.payload,
3050
+ ...event.payload
3051
+ },
3052
+ dataContext,
3053
+ state.layout || void 0
3054
+ );
3055
+ setDataContext(newContext);
1251
3056
  handleEvent(event);
1252
- return;
1253
- }
1254
- const newContext = executeAction(
1255
- eventConfig.action,
1256
- eventConfig.target,
1257
- {
1258
- ...eventConfig.payload,
1259
- ...event.payload
1260
- },
1261
- dataContext,
1262
- state.layout
1263
- );
1264
- setDataContext(newContext);
1265
- handleEvent(event);
1266
- }, [dataContext, handleEvent, onEvent, state.layout]);
1267
- const [resolvedLayout, setResolvedLayout] = react.useState(void 0);
1268
- const [renderedNode, setRenderedNode] = react.useState(null);
1269
- react.useEffect(() => {
1270
- if (state.layout) {
1271
- resolveBindings(state.layout, dataContext).then((resolved) => setResolvedLayout(resolved)).catch((err) => console.error("Error resolving bindings:", err));
3057
+ },
3058
+ [dataContext, handleEvent, onEvent, state.layout]
3059
+ );
3060
+ const [resolvedLayout, setResolvedLayout] = React.useState(
3061
+ void 0
3062
+ );
3063
+ const [renderedNode, setRenderedNode] = React.useState(
3064
+ null
3065
+ );
3066
+ const resolveLayoutBindings = React.useCallback(async () => {
3067
+ if (state.layout && dataContext) {
3068
+ console.log(
3069
+ "[AutoUI Debug] DataContext before resolving bindings:",
3070
+ JSON.stringify(dataContext, null, 2)
3071
+ );
3072
+ console.log(
3073
+ "[AutoUI Debug] Raw layout before resolving (from planner):",
3074
+ JSON.stringify(state.layout, null, 2)
3075
+ );
3076
+ const correctedLayout = correctListBindingsRecursive(
3077
+ state.layout,
3078
+ dataContext
3079
+ );
3080
+ console.log(
3081
+ "[AutoUI Debug] Layout after binding correction (before resolving):",
3082
+ JSON.stringify(correctedLayout, null, 2)
3083
+ );
3084
+ const resolved = await resolveBindings(correctedLayout, dataContext);
3085
+ setResolvedLayout(resolved);
3086
+ console.log(
3087
+ "[AutoUI Debug] Resolved layout after bindings:",
3088
+ JSON.stringify(resolved, null, 2)
3089
+ );
1272
3090
  } else {
1273
3091
  setResolvedLayout(void 0);
1274
3092
  }
1275
3093
  }, [state.layout, dataContext]);
1276
- react.useEffect(() => {
3094
+ React.useEffect(() => {
3095
+ resolveLayoutBindings();
3096
+ }, [resolveLayoutBindings]);
3097
+ const renderResolvedLayout = React.useCallback(async () => {
1277
3098
  if (resolvedLayout) {
1278
- renderNode2(resolvedLayout, componentAdapter).then((rendered) => setRenderedNode(rendered)).catch((err) => console.error("Error rendering node:", err));
3099
+ try {
3100
+ const rendered = await renderNode2(
3101
+ resolvedLayout,
3102
+ componentAdapter,
3103
+ processEvent2
3104
+ );
3105
+ setRenderedNode(rendered);
3106
+ } catch (err) {
3107
+ console.error("Error rendering node:", err);
3108
+ }
1279
3109
  } else {
1280
3110
  setRenderedNode(null);
1281
3111
  }
1282
- }, [resolvedLayout, componentAdapter]);
3112
+ }, [resolvedLayout, componentAdapter, processEvent2]);
3113
+ React.useEffect(() => {
3114
+ renderResolvedLayout();
3115
+ }, [renderResolvedLayout]);
3116
+ if (!componentsAvailable) {
3117
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error p-4 border border-red-300 bg-red-50 text-red-700 rounded", children: [
3118
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "Component Library Not Found" }),
3119
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-line", children: getMissingComponentsMessage() })
3120
+ ] });
3121
+ }
1283
3122
  return /* @__PURE__ */ jsxRuntime.jsxs(
1284
3123
  "div",
1285
3124
  {
@@ -1298,9 +3137,22 @@ var AutoUI = ({
1298
3137
  // Render the resolved layout
1299
3138
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "autoui-content", children: renderedNode })
1300
3139
  ),
1301
- state.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error", children: [
1302
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-title", children: "Error generating UI" }),
1303
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-message", children: state.error })
3140
+ state.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error p-4 border border-red-300 bg-red-50 dark:bg-red-900 dark:border-red-700 rounded-md", children: [
3141
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-title text-lg font-semibold text-red-700 dark:text-red-300 mb-2", children: "Error generating UI" }),
3142
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-message text-sm text-red-600 dark:text-red-300", children: state.error }),
3143
+ !mockMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 text-sm text-red-600 dark:text-red-300", children: [
3144
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "This could be because:" }),
3145
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "list-disc pl-5 mt-2", children: [
3146
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your OpenAI API key is missing or invalid" }),
3147
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "The OpenAI service is experiencing issues" }),
3148
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your API rate limit has been exceeded" })
3149
+ ] }),
3150
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2", children: [
3151
+ "Try setting ",
3152
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: "mockMode=true" }),
3153
+ " to use sample data instead."
3154
+ ] })
3155
+ ] })
1304
3156
  ] })
1305
3157
  ]
1306
3158
  }
@@ -1353,26 +3205,26 @@ var DrizzleAdapter = class {
1353
3205
  */
1354
3206
  mapDataType(drizzleType) {
1355
3207
  const typeMap = {
1356
- "serial": "integer",
1357
- "integer": "integer",
1358
- "int": "integer",
1359
- "bigint": "integer",
1360
- "text": "string",
1361
- "varchar": "string",
1362
- "char": "string",
1363
- "boolean": "boolean",
1364
- "bool": "boolean",
1365
- "timestamp": "datetime",
1366
- "timestamptz": "datetime",
1367
- "date": "date",
1368
- "time": "time",
1369
- "json": "object",
1370
- "jsonb": "object",
1371
- "real": "number",
1372
- "float": "number",
1373
- "double": "number",
1374
- "numeric": "number",
1375
- "decimal": "number"
3208
+ serial: "integer",
3209
+ integer: "integer",
3210
+ int: "integer",
3211
+ bigint: "integer",
3212
+ text: "string",
3213
+ varchar: "string",
3214
+ char: "string",
3215
+ boolean: "boolean",
3216
+ bool: "boolean",
3217
+ timestamp: "datetime",
3218
+ timestamptz: "datetime",
3219
+ date: "date",
3220
+ time: "time",
3221
+ json: "object",
3222
+ jsonb: "object",
3223
+ real: "number",
3224
+ float: "number",
3225
+ double: "number",
3226
+ numeric: "number",
3227
+ decimal: "number"
1376
3228
  };
1377
3229
  return typeMap[drizzleType.toLowerCase()] || "string";
1378
3230
  }
@@ -1415,35 +3267,120 @@ function createSchemaAdapter(options) {
1415
3267
  case "custom":
1416
3268
  return options.adapter;
1417
3269
  default:
1418
- throw new Error(`Unsupported schema adapter type: ${options.type}`);
1419
- }
1420
- }
1421
- async function generateComponent(schema) {
1422
- try {
1423
- const { text } = await ai.generateText({
1424
- model: openai.openai("gpt-4"),
1425
- prompt: `Generate a React component based on this data schema: ${JSON.stringify(schema)}`
1426
- });
1427
- return text;
1428
- } catch (error) {
1429
- console.error("Error generating component:", error);
1430
- throw error;
3270
+ throw new Error(
3271
+ `Unsupported schema adapter type: ${options.type}`
3272
+ );
1431
3273
  }
1432
3274
  }
1433
- async function generateUIDescription(schema) {
1434
- const { text } = await ai.generateText({
1435
- model: openai.openai("gpt-4"),
1436
- prompt: `Generate a React component description based on this data schema: ${JSON.stringify(schema)}.
1437
- Include what fields should be displayed and what user interactions might be needed.`
1438
- });
1439
- return text;
1440
- }
1441
- async function generateUIComponent(schema) {
1442
- const { text } = await ai.generateText({
1443
- model: openai.openai("gpt-4"),
1444
- prompt: `Generate a basic React component based on this data schema: ${JSON.stringify(schema)}.`
1445
- });
1446
- return text;
3275
+
3276
+ // src/ai-utils.ts
3277
+ var generateComponent = async (prompt) => {
3278
+ console.warn(
3279
+ "generateComponent is a placeholder and will be implemented in a future version"
3280
+ );
3281
+ return `<div>Generated Component for: ${prompt}</div>`;
3282
+ };
3283
+ var generateUIDescription = async (prompt) => {
3284
+ console.warn(
3285
+ "generateUIDescription is a placeholder and will be implemented in a future version"
3286
+ );
3287
+ return `Description for ${prompt}`;
3288
+ };
3289
+ var generateUIComponent = async (prompt) => {
3290
+ console.warn(
3291
+ "generateUIComponent is a placeholder and will be implemented in a future version"
3292
+ );
3293
+ return `<div>Generated UI Component for: ${prompt}</div>`;
3294
+ };
3295
+ function usePlanner(options) {
3296
+ const {
3297
+ schema,
3298
+ goal,
3299
+ openaiApiKey,
3300
+ userContext,
3301
+ initialLayout,
3302
+ mockMode: optionsMockMode
3303
+ } = options;
3304
+ const [layout, setLayout] = React.useState(
3305
+ initialLayout || void 0
3306
+ );
3307
+ const [loading, setLoading] = React.useState(false);
3308
+ const [error, setError] = React.useState(null);
3309
+ const router = options.router || createDefaultRouter();
3310
+ const dataContext = {};
3311
+ const initialFetchAttempted = React.useRef(false);
3312
+ const mockMode = optionsMockMode || !openaiApiKey;
3313
+ const generateInitialLayout = React.useCallback(async () => {
3314
+ setLoading(true);
3315
+ setError(null);
3316
+ try {
3317
+ const plannerInput2 = {
3318
+ schema,
3319
+ goal,
3320
+ userContext: userContext || null,
3321
+ history: null
3322
+ };
3323
+ let generatedLayout;
3324
+ if (mockMode) {
3325
+ console.warn(
3326
+ "Using mock planner in usePlanner hook (mockMode enabled or API key missing)."
3327
+ );
3328
+ generatedLayout = mockPlanner(plannerInput2);
3329
+ } else {
3330
+ generatedLayout = await callPlannerLLM(
3331
+ plannerInput2,
3332
+ openaiApiKey,
3333
+ void 0
3334
+ );
3335
+ }
3336
+ setLayout(generatedLayout);
3337
+ } catch (err) {
3338
+ setError(err instanceof Error ? err : new Error(String(err)));
3339
+ } finally {
3340
+ setLoading(false);
3341
+ }
3342
+ }, [schema, goal, userContext, openaiApiKey, mockMode]);
3343
+ const handleEvent = React.useCallback(
3344
+ async (event) => {
3345
+ if (!layout) {
3346
+ setError(new Error("Cannot handle event - no layout exists"));
3347
+ return;
3348
+ }
3349
+ setLoading(true);
3350
+ setError(null);
3351
+ try {
3352
+ const updatedLayout = await processEvent(
3353
+ event,
3354
+ router,
3355
+ schema,
3356
+ layout,
3357
+ dataContext,
3358
+ goal,
3359
+ userContext,
3360
+ openaiApiKey
3361
+ );
3362
+ setLayout(updatedLayout);
3363
+ } catch (err) {
3364
+ setError(err instanceof Error ? err : new Error(String(err)));
3365
+ } finally {
3366
+ setLoading(false);
3367
+ }
3368
+ },
3369
+ [layout, router, schema, dataContext, goal, userContext, openaiApiKey]
3370
+ );
3371
+ React.useEffect(() => {
3372
+ if (options.initialLayout === void 0 && layout === void 0 && !initialFetchAttempted.current) {
3373
+ initialFetchAttempted.current = true;
3374
+ generateInitialLayout();
3375
+ }
3376
+ }, [options.initialLayout, layout, generateInitialLayout]);
3377
+ return {
3378
+ layout,
3379
+ loading,
3380
+ error,
3381
+ handleEvent,
3382
+ generateInitialLayout
3383
+ };
1447
3384
  }
1448
3385
 
1449
3386
  exports.ActionRouter = ActionRouter;
@@ -1462,5 +3399,6 @@ exports.systemEvents = systemEvents;
1462
3399
  exports.uiEvent = uiEvent;
1463
3400
  exports.uiEventType = uiEventType;
1464
3401
  exports.uiSpecNode = uiSpecNode;
3402
+ exports.usePlanner = usePlanner;
1465
3403
  //# sourceMappingURL=out.js.map
1466
3404
  //# sourceMappingURL=index.js.map