orchid-ai 1.3.1 → 1.3.6

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.
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type IconName } from './Icon';
3
- import { CommandTheme, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
3
+ import { CommandTheme, CommandSuggestion, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
4
4
  interface ChatPanelProps {
5
5
  isOpen: boolean;
6
6
  setIsOpen?: (isOpen: boolean) => void;
@@ -53,6 +53,13 @@ interface ChatPanelProps {
53
53
  headerIcon?: IconName | React.ReactElement;
54
54
  headerTitle?: string;
55
55
  headerSubtitle?: string;
56
+ /** When set, replaces default behavior (setFormState + onNavigate + onClose) for command suggestions. */
57
+ onSuggestionSelect?: (s: CommandSuggestion) => void;
58
+ /**
59
+ * Applied to the full-screen modal root so the chat stacks above app chrome that uses high z-index
60
+ * (e.g. MUI AppBar ~1100, custom sidebars ~999). Default Tailwind z-50 is too low for many shells.
61
+ */
62
+ overlayZIndex?: number;
56
63
  }
57
64
  /**
58
65
  * ChatPanel component
@@ -91,7 +98,7 @@ showHistory, // Default to hidden
91
98
  showProfileBubbles, // Default to hidden
92
99
  modalPosition, // Default to left position
93
100
  serverConfig, models, defaultModel, showUsageStats, maxFileSize, features, showFloatingButton, floatingButtonIcon, floatingButtonPosition, floatingButtonSize, floatingButtonClassName, chats, setChats, currentChatId, setCurrentChatId, chatLevel, initialQuery, setInitialQuery, headerIcon, // Default to bot icon
94
- headerTitle, headerSubtitle, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
101
+ headerTitle, headerSubtitle, onSuggestionSelect, overlayZIndex, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
95
102
  /**
96
103
  * ChatInput component
97
104
  * @param query - The current query
@@ -118,6 +125,7 @@ type FloatingChatButtonProps = {
118
125
  className?: string;
119
126
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
120
127
  size?: 'sm' | 'md' | 'lg';
128
+ zIndex?: number;
121
129
  };
122
130
  /**
123
131
  * FloatingChatButton component
@@ -128,5 +136,5 @@ type FloatingChatButtonProps = {
128
136
  * @param position - Position of the floating button
129
137
  * @param size - Size of the floating button
130
138
  */
131
- export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
139
+ export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, zIndex: floatingZIndex, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
132
140
  export {};
@@ -72,5 +72,5 @@ interface ConversationProps {
72
72
  * @param autoScroll - Whether to auto-scroll to bottom on new messages
73
73
  * @param maxHeight - Maximum height of the conversation container
74
74
  */
75
- export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, setFormState, onNavigate, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
75
+ export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
76
76
  export {};
@@ -10,6 +10,7 @@ const commandTrainingRules = {
10
10
  components: {
11
11
  patterns: {
12
12
  // React component patterns
13
+ // Has /g for matchAll in training.ts; do not use String.match(componentName) (groups break).
13
14
  componentName: /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g,
14
15
  props: /interface\s+(\w+)Props\s*{([^}]*)}/g,
15
16
  state: /useState<([^>]*)>/g,
@@ -34,7 +35,8 @@ const commandTrainingRules = {
34
35
  schemas: {
35
36
  patterns: {
36
37
  // Monastery schema patterns - updated for actual file format
37
- modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/g,
38
+ // No /g: training.ts uses String.match(); with g, capture groups are omitted and modelName is always lost.
39
+ modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/,
38
40
  fields: /fields:\s*{([^}]*)}/g,
39
41
  fieldDefinitions: /(\w+):\s*{\s*(?:required:\s*(true|false),?\s*)?type:\s*['"]([^'"]+)['"](?:,\s*required:\s*(true|false))?(?:,\s*default:\s*[^,}]+)?/g,
40
42
  indexes: /indexes:\s*\[([^\]]*)\]/g,
@@ -557,6 +559,7 @@ class CommandTrainingCollector {
557
559
  if (content.formFields?.length > 0) {
558
560
  const form = {
559
561
  name: content.componentName || 'Unknown Form',
562
+ sourceFile: path.relative(this.rootDir, component.filePath),
560
563
  purpose: `Form component for data entry`,
561
564
  fields: content.formFields.map((fieldName) => ({
562
565
  name: fieldName,
@@ -685,12 +688,15 @@ class CommandTrainingCollector {
685
688
  guessEntityFromComponent(componentName) {
686
689
  if (!componentName)
687
690
  return 'Unknown';
688
- // Simple heuristic: remove common suffixes
691
+ // Strip common create/edit wrappers, then UI suffixes (order matters)
689
692
  const cleaned = componentName
693
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
690
694
  .replace(/Form$/, '')
695
+ .replace(/Modal$/, '')
696
+ .replace(/Drawer$/, '')
697
+ .replace(/Dialog$/, '')
691
698
  .replace(/Page$/, '')
692
- .replace(/Component$/, '')
693
- .replace(/Modal$/, '');
699
+ .replace(/Component$/, '');
694
700
  return cleaned || 'Unknown';
695
701
  }
696
702
  guessEntitiesFromComponent(content) {
@@ -804,7 +810,7 @@ class CommandTrainingCollector {
804
810
  this.log(`āŒ Error expanding pattern "${pattern}":`, err.message);
805
811
  }
806
812
  }
807
- return expandedPaths;
813
+ return [...new Set(expandedPaths)];
808
814
  }
809
815
  extractFileInfo(fieldName, content) {
810
816
  switch (fieldName) {
@@ -848,11 +854,22 @@ class CommandTrainingCollector {
848
854
  hooks: [],
849
855
  eventHandlers: [],
850
856
  };
851
- // Extract component name
852
- const componentMatch = content.match(patterns.componentName);
853
- if (componentMatch) {
854
- result.componentName = componentMatch[1];
855
- }
857
+ // Do not use String.match() on patterns.componentName — it has /g, so match[1] is the *second*
858
+ // full match, not capture group 1 (yields strings like `const CustomerForm =`).
859
+ const declRe = /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g;
860
+ const declNames = [];
861
+ for (const m of content.matchAll(declRe)) {
862
+ declNames.push(m[1]);
863
+ }
864
+ const isLikelyComponentSymbol = (n) => /^[A-Z]/.test(n) &&
865
+ !/^use[A-Z]/.test(n) &&
866
+ !/^Styled/i.test(n);
867
+ const preferred = [...declNames].reverse().find((n) => isLikelyComponentSymbol(n) &&
868
+ (/(?:Form|Modal|Drawer|Dialog)$/.test(n) ||
869
+ /^FormStep/i.test(n) ||
870
+ (n.includes('Form') && n.length > 4)));
871
+ const fallback = [...declNames].reverse().find(isLikelyComponentSymbol);
872
+ result.componentName = preferred ?? fallback ?? null;
856
873
  // Extract props interfaces
857
874
  const propsMatches = content.matchAll(patterns.props);
858
875
  for (const match of propsMatches) {
@@ -887,6 +904,7 @@ class CommandTrainingCollector {
887
904
  for (const match of fieldMatches) {
888
905
  result.formFields.push(match[1]);
889
906
  }
907
+ result.formFields = [...new Set(result.formFields)];
890
908
  // Extract imports
891
909
  const importMatches = content.matchAll(patterns.imports);
892
910
  for (const match of importMatches) {
@@ -1635,6 +1653,7 @@ class SchemaGenerator extends CommandTrainingCollector {
1635
1653
  };
1636
1654
  this.log(` āœ… Generated schema with ${Object.keys(properties).length} properties`);
1637
1655
  }
1656
+ this.mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas);
1638
1657
  // If no entities found, try to extract from components
1639
1658
  if (Object.keys(schemas).length === 0) {
1640
1659
  this.log(' āš ļø No entities found in training data, extracting from components...');
@@ -1642,6 +1661,87 @@ class SchemaGenerator extends CommandTrainingCollector {
1642
1661
  }
1643
1662
  return schemas;
1644
1663
  }
1664
+ /**
1665
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
1666
+ * (server models stay canonical; this adds frontend surface hints).
1667
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
1668
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
1669
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
1670
+ */
1671
+ mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas) {
1672
+ const forms = trainingData.customTrainingData?.structuredData?.components?.forms || [];
1673
+ if (!forms.length || !Object.keys(schemas).length)
1674
+ return;
1675
+ const hints = (trainingData.customTrainingData?.options?.formEntityHints || {});
1676
+ const pathPatterns = (trainingData.customTrainingData?.options?.formEntityPathPatterns ||
1677
+ []);
1678
+ /** Short UI stems that don't match lowered model names */
1679
+ const STEM_ALIASES = {
1680
+ hs: 'hsreport',
1681
+ incident: 'incidentreport',
1682
+ };
1683
+ const schemaKeys = new Set(Object.keys(schemas));
1684
+ const resolveKey = (form) => {
1685
+ if (form.sourceFile) {
1686
+ for (const p of pathPatterns) {
1687
+ if (!p?.includes || !p?.entity)
1688
+ continue;
1689
+ if (form.sourceFile.includes(p.includes)) {
1690
+ const k = p.entity.toLowerCase();
1691
+ if (schemaKeys.has(k))
1692
+ return k;
1693
+ }
1694
+ }
1695
+ }
1696
+ const tryKey = (raw) => {
1697
+ if (!raw)
1698
+ return undefined;
1699
+ const mapped = hints[raw];
1700
+ const stem = raw
1701
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
1702
+ .replace(/(?:Form|Modal|Drawer|Dialog)$/i, '');
1703
+ const stemLc = stem.toLowerCase();
1704
+ const alias = STEM_ALIASES[stemLc];
1705
+ if (alias && schemaKeys.has(alias))
1706
+ return alias;
1707
+ const candidates = [
1708
+ (mapped || raw).toLowerCase(),
1709
+ stemLc,
1710
+ ];
1711
+ for (const c of candidates) {
1712
+ if (c && schemaKeys.has(c))
1713
+ return c;
1714
+ }
1715
+ return undefined;
1716
+ };
1717
+ return tryKey(form.name) || tryKey(form.relatedEntity) || undefined;
1718
+ };
1719
+ let mergedForms = 0;
1720
+ let mergedFields = 0;
1721
+ for (const form of forms) {
1722
+ const entityKey = resolveKey(form);
1723
+ if (!entityKey)
1724
+ continue;
1725
+ const gen = schemas[entityKey];
1726
+ if (!gen?.schema?.properties)
1727
+ continue;
1728
+ const props = gen.schema.properties;
1729
+ for (const f of form.fields || []) {
1730
+ const n = f?.name;
1731
+ if (!n || typeof n !== 'string' || props[n])
1732
+ continue;
1733
+ props[n] = {
1734
+ type: 'string',
1735
+ description: `UI form field (from ${form.name}). Cross-check server model; may overlap sharing/base shapes.`,
1736
+ };
1737
+ mergedFields += 1;
1738
+ }
1739
+ mergedForms += 1;
1740
+ }
1741
+ if (mergedForms > 0) {
1742
+ this.log(`\nšŸ“Ž Merged UI form fields into ${mergedForms} entity schema(s) (+${mergedFields} properties)`);
1743
+ }
1744
+ }
1645
1745
  /**
1646
1746
  * Extract schemas from component analysis if no explicit entities found
1647
1747
  */
@@ -1955,6 +2055,9 @@ class SchemaGenerator extends CommandTrainingCollector {
1955
2055
  * Map training data field types to JSON Schema types
1956
2056
  */
1957
2057
  mapFieldType(type) {
2058
+ if (type == null || typeof type !== 'string') {
2059
+ return 'string';
2060
+ }
1958
2061
  const typeMap = {
1959
2062
  string: 'string',
1960
2063
  number: 'number',
@@ -1,3 +1,4 @@
1
+ import './orchid-chat.css';
1
2
  export { useStreamingAI } from './hooks/useStreamingAI';
2
3
  export type { StreamingModelSelection } from './hooks/useStreamingAI';
3
4
  export { useSuggestions, useDebouncedSuggestions, } from './hooks/useSuggestions';
@@ -55,6 +55,14 @@ export declare class SchemaGenerator extends CommandTrainingCollector {
55
55
  * Generate schemas from collected training data
56
56
  */
57
57
  private generateSchemas;
58
+ /**
59
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
60
+ * (server models stay canonical; this adds frontend surface hints).
61
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
62
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
63
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
64
+ */
65
+ private mergeFormUiFieldsIntoEntitySchemas;
58
66
  /**
59
67
  * Extract schemas from component analysis if no explicit entities found
60
68
  */
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type IconName } from './Icon';
3
- import { CommandTheme, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
3
+ import { CommandTheme, CommandSuggestion, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
4
4
  interface ChatPanelProps {
5
5
  isOpen: boolean;
6
6
  setIsOpen?: (isOpen: boolean) => void;
@@ -53,6 +53,13 @@ interface ChatPanelProps {
53
53
  headerIcon?: IconName | React.ReactElement;
54
54
  headerTitle?: string;
55
55
  headerSubtitle?: string;
56
+ /** When set, replaces default behavior (setFormState + onNavigate + onClose) for command suggestions. */
57
+ onSuggestionSelect?: (s: CommandSuggestion) => void;
58
+ /**
59
+ * Applied to the full-screen modal root so the chat stacks above app chrome that uses high z-index
60
+ * (e.g. MUI AppBar ~1100, custom sidebars ~999). Default Tailwind z-50 is too low for many shells.
61
+ */
62
+ overlayZIndex?: number;
56
63
  }
57
64
  /**
58
65
  * ChatPanel component
@@ -91,7 +98,7 @@ showHistory, // Default to hidden
91
98
  showProfileBubbles, // Default to hidden
92
99
  modalPosition, // Default to left position
93
100
  serverConfig, models, defaultModel, showUsageStats, maxFileSize, features, showFloatingButton, floatingButtonIcon, floatingButtonPosition, floatingButtonSize, floatingButtonClassName, chats, setChats, currentChatId, setCurrentChatId, chatLevel, initialQuery, setInitialQuery, headerIcon, // Default to bot icon
94
- headerTitle, headerSubtitle, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
101
+ headerTitle, headerSubtitle, onSuggestionSelect, overlayZIndex, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
95
102
  /**
96
103
  * ChatInput component
97
104
  * @param query - The current query
@@ -118,6 +125,7 @@ type FloatingChatButtonProps = {
118
125
  className?: string;
119
126
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
120
127
  size?: 'sm' | 'md' | 'lg';
128
+ zIndex?: number;
121
129
  };
122
130
  /**
123
131
  * FloatingChatButton component
@@ -128,5 +136,5 @@ type FloatingChatButtonProps = {
128
136
  * @param position - Position of the floating button
129
137
  * @param size - Size of the floating button
130
138
  */
131
- export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
139
+ export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, zIndex: floatingZIndex, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
132
140
  export {};
@@ -72,5 +72,5 @@ interface ConversationProps {
72
72
  * @param autoScroll - Whether to auto-scroll to bottom on new messages
73
73
  * @param maxHeight - Maximum height of the conversation container
74
74
  */
75
- export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, setFormState, onNavigate, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
75
+ export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
76
76
  export {};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import './orchid-chat.css';
1
2
  export { useStreamingAI } from './hooks/useStreamingAI';
2
3
  export type { StreamingModelSelection } from './hooks/useStreamingAI';
3
4
  export { useSuggestions, useDebouncedSuggestions, } from './hooks/useSuggestions';
package/dist/index.esm.js CHANGED
@@ -2791,7 +2791,7 @@ const getTextFromMessage$1 = (msg) => {
2791
2791
  */
2792
2792
  function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles = false, className = '', autoScroll = true, maxHeight = '100%',
2793
2793
  // AI functionality props
2794
- userId = 'demo-user', serverConfig, formData, setFormState, onNavigate, chatLevel = 'full',
2794
+ userId = 'demo-user', serverConfig, formData, chatLevel = 'full',
2795
2795
  // External chat management
2796
2796
  chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId,
2797
2797
  // Input-related props
@@ -2944,14 +2944,10 @@ additionalContext, }) {
2944
2944
  externalSetQuery?.('');
2945
2945
  externalSetAttachedFiles?.([]);
2946
2946
  }, [query, attachedFiles, streamingAI, externalSetQuery, externalSetAttachedFiles]);
2947
- // Handle suggestion clicks
2947
+ // Delegate to parent — ChatPanel composes setFormState / onNavigate / onClose in its handler
2948
2948
  const handleSuggestionClick = useCallback((s) => {
2949
- if (setFormState && s.formState)
2950
- setFormState(s.formState, s.actionType);
2951
- if (s.path && onNavigate)
2952
- onNavigate(s.path);
2953
2949
  onSuggestionClick(s);
2954
- }, [setFormState, onNavigate, onSuggestionClick]);
2950
+ }, [onSuggestionClick]);
2955
2951
  // Use external or internal state
2956
2952
  const chat = externalChat || streamingAI.chat;
2957
2953
  const isLoading = externalIsLoading || streamingAI.isLoading;
@@ -3512,8 +3508,12 @@ showHistory = false, // Default to hidden
3512
3508
  showProfileBubbles = false, // Default to hidden
3513
3509
  modalPosition = 'left', // Default to left position
3514
3510
  serverConfig, models, defaultModel, showUsageStats, maxFileSize, features = {}, showFloatingButton = false, floatingButtonIcon, floatingButtonPosition = 'bottom-right', floatingButtonSize = 'md', floatingButtonClassName = '', chats, setChats, currentChatId, setCurrentChatId, chatLevel, initialQuery, setInitialQuery, headerIcon = 'command', // Default to bot icon
3515
- headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist you with your queries', }) {
3511
+ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist you with your queries', onSuggestionSelect, overlayZIndex, }) {
3516
3512
  const handleSuggestionClick = (s) => {
3513
+ if (onSuggestionSelect) {
3514
+ onSuggestionSelect(s);
3515
+ return;
3516
+ }
3517
3517
  if (setFormState && s.formState)
3518
3518
  setFormState(s.formState, s.actionType);
3519
3519
  if (s.path)
@@ -3521,6 +3521,14 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3521
3521
  onClose();
3522
3522
  };
3523
3523
  const containerRef = useRef(null);
3524
+ const handleHistorySwitchChat = useCallback((id) => {
3525
+ setCurrentChatId?.(id);
3526
+ }, [setCurrentChatId]);
3527
+ const handleHistoryNewChat = useCallback(() => {
3528
+ const id = Date.now().toString();
3529
+ setChats?.((prev) => ({ ...prev, [id]: [] }));
3530
+ setCurrentChatId?.(id);
3531
+ }, [setChats, setCurrentChatId]);
3524
3532
  // SIMPLIFIED ANIMATION STATE
3525
3533
  const [isVisible, setIsVisible] = useState(false);
3526
3534
  const [isAnimating, setIsAnimating] = useState(false);
@@ -3670,7 +3678,7 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3670
3678
  transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
3671
3679
  }
3672
3680
  `;
3673
- return (jsxs(Fragment, { children: [jsx("style", { children: scrollbarStyles }), jsxs(ErrorBoundary, { children: [!isOpen && showFloatingButton && (jsx(FloatingChatButton, { onClick: handleOpen, theme: theme, icon: floatingButtonIcon, position: floatingButtonPosition, size: floatingButtonSize, className: floatingButtonClassName })), shouldRenderPanel && (jsxs("div", { className: "fixed inset-0 z-50", children: [jsx("div", { className: `absolute inset-0 bg-black/20 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`, onClick: handleClose }), jsx("div", { className: `fixed z-[60] top-6 transition-all duration-300 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-75'}`, style: { ...(modalPosition === 'left'
3681
+ return (jsxs(Fragment, { children: [jsx("style", { children: scrollbarStyles }), jsxs(ErrorBoundary, { children: [!isOpen && showFloatingButton && (jsx(FloatingChatButton, { onClick: handleOpen, theme: theme, icon: floatingButtonIcon, position: floatingButtonPosition, size: floatingButtonSize, className: floatingButtonClassName, zIndex: overlayZIndex })), shouldRenderPanel && (jsxs("div", { className: "fixed inset-0 z-50", style: overlayZIndex !== undefined ? { zIndex: overlayZIndex } : undefined, children: [jsx("div", { className: `absolute inset-0 bg-black/20 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`, onClick: handleClose }), jsx("div", { className: `fixed z-[60] top-6 transition-all duration-300 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-75'}`, style: { ...(modalPosition === 'left'
3674
3682
  ? { left: showHistory ? 'min(90vw, 700px)' : 'min(80vw, 550px)', marginLeft: '16px' }
3675
3683
  : { right: showHistory ? 'min(90vw, 700px)' : 'min(80vw, 550px)', marginRight: '16px' }) }, children: jsx("button", { onClick: handleClose, className: "w-10 h-10 rounded-full shadow-lg transition-all duration-200 flex items-center justify-center text-xl font-bold hover:scale-110", style: {
3676
3684
  backgroundColor: finalTheme.colors.surface.elevated,
@@ -3706,7 +3714,7 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3706
3714
  }, ref: containerRef, onClick: (e) => e.stopPropagation(), children: [jsx("div", { className: `flex items-center justify-between px-6 py-4 border-b min-h-[72px] transition-all duration-500 delay-100 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-2'}`, style: {
3707
3715
  borderColor: finalTheme.colors.border.primary,
3708
3716
  backgroundColor: finalTheme.colors.background.primary,
3709
- }, children: jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: `inline-flex items-center justify-center rounded-full w-8 h-8 transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-75 rotate-12'}`, style: { backgroundColor: finalTheme.colors.primary[600] }, children: typeof headerIcon === 'string' ? (jsx(Icon, { name: headerIcon, size: "sm", style: { color: finalTheme.colors.text.primary } })) : (headerIcon || (jsx(Icon, { name: "command", size: "sm", style: { color: finalTheme.colors.text.primary } }))) }), jsxs("div", { className: `transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-2'}`, children: [jsx("div", { className: "font-bold text-lg leading-tight", style: { color: finalTheme.colors.text.primary }, children: headerTitle }), jsx("div", { className: "text-xs", style: { color: finalTheme.colors.text.tertiary }, children: headerSubtitle })] })] }) }), jsxs("div", { className: `flex flex-1 min-h-0 h-full transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, children: [showHistory && (jsx(ChatHistorySidebar, { chats: chats || {}, currentChatId: currentChatId || 'default', switchChat: () => { }, newChat: () => { }, theme: finalTheme, isOpen: isOpen })), jsx("div", { className: "flex-1 flex flex-col min-h-0 h-full", children: jsx("div", { className: `flex-1 px-6 py-4 min-h-0 transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: {
3717
+ }, children: jsxs("div", { className: "flex items-center gap-3", children: [jsx("span", { className: `inline-flex items-center justify-center rounded-full w-8 h-8 transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-75 rotate-12'}`, style: { backgroundColor: finalTheme.colors.primary[600] }, children: typeof headerIcon === 'string' ? (jsx(Icon, { name: headerIcon, size: "sm", style: { color: finalTheme.colors.text.primary } })) : (headerIcon || (jsx(Icon, { name: "command", size: "sm", style: { color: finalTheme.colors.text.primary } }))) }), jsxs("div", { className: `transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-2'}`, children: [jsx("div", { className: "font-bold text-lg leading-tight", style: { color: finalTheme.colors.text.primary }, children: headerTitle }), jsx("div", { className: "text-xs", style: { color: finalTheme.colors.text.tertiary }, children: headerSubtitle })] })] }) }), jsxs("div", { className: `flex flex-1 min-h-0 h-full transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, children: [showHistory && (jsx(ChatHistorySidebar, { chats: chats || {}, currentChatId: currentChatId || 'default', switchChat: handleHistorySwitchChat, newChat: handleHistoryNewChat, theme: finalTheme, isOpen: isOpen })), jsx("div", { className: "flex-1 flex flex-col min-h-0 h-full", children: jsx("div", { className: `flex-1 px-6 py-4 min-h-0 transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: {
3710
3718
  backgroundColor: finalTheme.colors.background.primary,
3711
3719
  }, children: jsx(Conversation, { onSuggestionClick: handleSuggestionClick, theme: finalTheme, showProfileBubbles: showProfileBubbles, autoScroll: true, showInput: true,
3712
3720
  // AI functionality props
@@ -3779,7 +3787,7 @@ function ChatHistorySidebar({ chats, currentChatId, switchChat, newChat, theme,
3779
3787
  * @param position - Position of the floating button
3780
3788
  * @param size - Size of the floating button
3781
3789
  */
3782
- function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '', position = 'bottom-right', size = 'md', }) {
3790
+ function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '', position = 'bottom-right', size = 'md', zIndex: floatingZIndex, }) {
3783
3791
  // Note: Theme is now handled via Tailwind classes directly
3784
3792
  // Position classes
3785
3793
  const positionClasses = {
@@ -3799,7 +3807,7 @@ function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '
3799
3807
  md: { width: 24, height: 24 },
3800
3808
  lg: { width: 28, height: 28 },
3801
3809
  };
3802
- return (jsx("div", { className: `fixed z-50 ${positionClasses[position]} ${className}`, children: jsx("button", { onClick: onClick, className: `
3810
+ return (jsx("div", { className: `fixed z-50 ${positionClasses[position]} ${className}`, style: floatingZIndex !== undefined ? { zIndex: floatingZIndex } : undefined, children: jsx("button", { onClick: onClick, className: `
3803
3811
  ${sizeClasses[size]}
3804
3812
  bg-blue-600 hover:bg-blue-700
3805
3813
  text-white rounded-full shadow-lg hover:shadow-xl
package/dist/index.js CHANGED
@@ -2793,7 +2793,7 @@ const getTextFromMessage$1 = (msg) => {
2793
2793
  */
2794
2794
  function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles = false, className = '', autoScroll = true, maxHeight = '100%',
2795
2795
  // AI functionality props
2796
- userId = 'demo-user', serverConfig, formData, setFormState, onNavigate, chatLevel = 'full',
2796
+ userId = 'demo-user', serverConfig, formData, chatLevel = 'full',
2797
2797
  // External chat management
2798
2798
  chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId,
2799
2799
  // Input-related props
@@ -2946,14 +2946,10 @@ additionalContext, }) {
2946
2946
  externalSetQuery?.('');
2947
2947
  externalSetAttachedFiles?.([]);
2948
2948
  }, [query, attachedFiles, streamingAI, externalSetQuery, externalSetAttachedFiles]);
2949
- // Handle suggestion clicks
2949
+ // Delegate to parent — ChatPanel composes setFormState / onNavigate / onClose in its handler
2950
2950
  const handleSuggestionClick = React.useCallback((s) => {
2951
- if (setFormState && s.formState)
2952
- setFormState(s.formState, s.actionType);
2953
- if (s.path && onNavigate)
2954
- onNavigate(s.path);
2955
2951
  onSuggestionClick(s);
2956
- }, [setFormState, onNavigate, onSuggestionClick]);
2952
+ }, [onSuggestionClick]);
2957
2953
  // Use external or internal state
2958
2954
  const chat = externalChat || streamingAI.chat;
2959
2955
  const isLoading = externalIsLoading || streamingAI.isLoading;
@@ -3514,8 +3510,12 @@ showHistory = false, // Default to hidden
3514
3510
  showProfileBubbles = false, // Default to hidden
3515
3511
  modalPosition = 'left', // Default to left position
3516
3512
  serverConfig, models, defaultModel, showUsageStats, maxFileSize, features = {}, showFloatingButton = false, floatingButtonIcon, floatingButtonPosition = 'bottom-right', floatingButtonSize = 'md', floatingButtonClassName = '', chats, setChats, currentChatId, setCurrentChatId, chatLevel, initialQuery, setInitialQuery, headerIcon = 'command', // Default to bot icon
3517
- headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist you with your queries', }) {
3513
+ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist you with your queries', onSuggestionSelect, overlayZIndex, }) {
3518
3514
  const handleSuggestionClick = (s) => {
3515
+ if (onSuggestionSelect) {
3516
+ onSuggestionSelect(s);
3517
+ return;
3518
+ }
3519
3519
  if (setFormState && s.formState)
3520
3520
  setFormState(s.formState, s.actionType);
3521
3521
  if (s.path)
@@ -3523,6 +3523,14 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3523
3523
  onClose();
3524
3524
  };
3525
3525
  const containerRef = React.useRef(null);
3526
+ const handleHistorySwitchChat = React.useCallback((id) => {
3527
+ setCurrentChatId?.(id);
3528
+ }, [setCurrentChatId]);
3529
+ const handleHistoryNewChat = React.useCallback(() => {
3530
+ const id = Date.now().toString();
3531
+ setChats?.((prev) => ({ ...prev, [id]: [] }));
3532
+ setCurrentChatId?.(id);
3533
+ }, [setChats, setCurrentChatId]);
3526
3534
  // SIMPLIFIED ANIMATION STATE
3527
3535
  const [isVisible, setIsVisible] = React.useState(false);
3528
3536
  const [isAnimating, setIsAnimating] = React.useState(false);
@@ -3672,7 +3680,7 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3672
3680
  transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
3673
3681
  }
3674
3682
  `;
3675
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("style", { children: scrollbarStyles }), jsxRuntime.jsxs(ErrorBoundary, { children: [!isOpen && showFloatingButton && (jsxRuntime.jsx(FloatingChatButton, { onClick: handleOpen, theme: theme, icon: floatingButtonIcon, position: floatingButtonPosition, size: floatingButtonSize, className: floatingButtonClassName })), shouldRenderPanel && (jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", children: [jsxRuntime.jsx("div", { className: `absolute inset-0 bg-black/20 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`, onClick: handleClose }), jsxRuntime.jsx("div", { className: `fixed z-[60] top-6 transition-all duration-300 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-75'}`, style: { ...(modalPosition === 'left'
3683
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("style", { children: scrollbarStyles }), jsxRuntime.jsxs(ErrorBoundary, { children: [!isOpen && showFloatingButton && (jsxRuntime.jsx(FloatingChatButton, { onClick: handleOpen, theme: theme, icon: floatingButtonIcon, position: floatingButtonPosition, size: floatingButtonSize, className: floatingButtonClassName, zIndex: overlayZIndex })), shouldRenderPanel && (jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50", style: overlayZIndex !== undefined ? { zIndex: overlayZIndex } : undefined, children: [jsxRuntime.jsx("div", { className: `absolute inset-0 bg-black/20 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`, onClick: handleClose }), jsxRuntime.jsx("div", { className: `fixed z-[60] top-6 transition-all duration-300 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-75'}`, style: { ...(modalPosition === 'left'
3676
3684
  ? { left: showHistory ? 'min(90vw, 700px)' : 'min(80vw, 550px)', marginLeft: '16px' }
3677
3685
  : { right: showHistory ? 'min(90vw, 700px)' : 'min(80vw, 550px)', marginRight: '16px' }) }, children: jsxRuntime.jsx("button", { onClick: handleClose, className: "w-10 h-10 rounded-full shadow-lg transition-all duration-200 flex items-center justify-center text-xl font-bold hover:scale-110", style: {
3678
3686
  backgroundColor: finalTheme.colors.surface.elevated,
@@ -3708,7 +3716,7 @@ headerTitle = 'AI Logistics & Customs Expert', headerSubtitle = 'Ready to assist
3708
3716
  }, ref: containerRef, onClick: (e) => e.stopPropagation(), children: [jsxRuntime.jsx("div", { className: `flex items-center justify-between px-6 py-4 border-b min-h-[72px] transition-all duration-500 delay-100 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-2'}`, style: {
3709
3717
  borderColor: finalTheme.colors.border.primary,
3710
3718
  backgroundColor: finalTheme.colors.background.primary,
3711
- }, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("span", { className: `inline-flex items-center justify-center rounded-full w-8 h-8 transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-75 rotate-12'}`, style: { backgroundColor: finalTheme.colors.primary[600] }, children: typeof headerIcon === 'string' ? (jsxRuntime.jsx(Icon, { name: headerIcon, size: "sm", style: { color: finalTheme.colors.text.primary } })) : (headerIcon || (jsxRuntime.jsx(Icon, { name: "command", size: "sm", style: { color: finalTheme.colors.text.primary } }))) }), jsxRuntime.jsxs("div", { className: `transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-2'}`, children: [jsxRuntime.jsx("div", { className: "font-bold text-lg leading-tight", style: { color: finalTheme.colors.text.primary }, children: headerTitle }), jsxRuntime.jsx("div", { className: "text-xs", style: { color: finalTheme.colors.text.tertiary }, children: headerSubtitle })] })] }) }), jsxRuntime.jsxs("div", { className: `flex flex-1 min-h-0 h-full transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, children: [showHistory && (jsxRuntime.jsx(ChatHistorySidebar, { chats: chats || {}, currentChatId: currentChatId || 'default', switchChat: () => { }, newChat: () => { }, theme: finalTheme, isOpen: isOpen })), jsxRuntime.jsx("div", { className: "flex-1 flex flex-col min-h-0 h-full", children: jsxRuntime.jsx("div", { className: `flex-1 px-6 py-4 min-h-0 transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: {
3719
+ }, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("span", { className: `inline-flex items-center justify-center rounded-full w-8 h-8 transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-75 rotate-12'}`, style: { backgroundColor: finalTheme.colors.primary[600] }, children: typeof headerIcon === 'string' ? (jsxRuntime.jsx(Icon, { name: headerIcon, size: "sm", style: { color: finalTheme.colors.text.primary } })) : (headerIcon || (jsxRuntime.jsx(Icon, { name: "command", size: "sm", style: { color: finalTheme.colors.text.primary } }))) }), jsxRuntime.jsxs("div", { className: `transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-2'}`, children: [jsxRuntime.jsx("div", { className: "font-bold text-lg leading-tight", style: { color: finalTheme.colors.text.primary }, children: headerTitle }), jsxRuntime.jsx("div", { className: "text-xs", style: { color: finalTheme.colors.text.tertiary }, children: headerSubtitle })] })] }) }), jsxRuntime.jsxs("div", { className: `flex flex-1 min-h-0 h-full transition-all duration-500 delay-200 ${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`, children: [showHistory && (jsxRuntime.jsx(ChatHistorySidebar, { chats: chats || {}, currentChatId: currentChatId || 'default', switchChat: handleHistorySwitchChat, newChat: handleHistoryNewChat, theme: finalTheme, isOpen: isOpen })), jsxRuntime.jsx("div", { className: "flex-1 flex flex-col min-h-0 h-full", children: jsxRuntime.jsx("div", { className: `flex-1 px-6 py-4 min-h-0 transition-all duration-500 delay-300 ${isOpen ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`, style: {
3712
3720
  backgroundColor: finalTheme.colors.background.primary,
3713
3721
  }, children: jsxRuntime.jsx(Conversation, { onSuggestionClick: handleSuggestionClick, theme: finalTheme, showProfileBubbles: showProfileBubbles, autoScroll: true, showInput: true,
3714
3722
  // AI functionality props
@@ -3781,7 +3789,7 @@ function ChatHistorySidebar({ chats, currentChatId, switchChat, newChat, theme,
3781
3789
  * @param position - Position of the floating button
3782
3790
  * @param size - Size of the floating button
3783
3791
  */
3784
- function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '', position = 'bottom-right', size = 'md', }) {
3792
+ function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '', position = 'bottom-right', size = 'md', zIndex: floatingZIndex, }) {
3785
3793
  // Note: Theme is now handled via Tailwind classes directly
3786
3794
  // Position classes
3787
3795
  const positionClasses = {
@@ -3801,7 +3809,7 @@ function FloatingChatButton({ onClick, theme = defaultTheme, icon, className = '
3801
3809
  md: { width: 24, height: 24 },
3802
3810
  lg: { width: 28, height: 28 },
3803
3811
  };
3804
- return (jsxRuntime.jsx("div", { className: `fixed z-50 ${positionClasses[position]} ${className}`, children: jsxRuntime.jsx("button", { onClick: onClick, className: `
3812
+ return (jsxRuntime.jsx("div", { className: `fixed z-50 ${positionClasses[position]} ${className}`, style: floatingZIndex !== undefined ? { zIndex: floatingZIndex } : undefined, children: jsxRuntime.jsx("button", { onClick: onClick, className: `
3805
3813
  ${sizeClasses[size]}
3806
3814
  bg-blue-600 hover:bg-blue-700
3807
3815
  text-white rounded-full shadow-lg hover:shadow-xl
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { type IconName } from './Icon';
3
- import { CommandTheme, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
3
+ import { CommandTheme, CommandSuggestion, ChatMessage, ModelInfo, ChatTheme, ServerConfig } from '../types/types';
4
4
  interface ChatPanelProps {
5
5
  isOpen: boolean;
6
6
  setIsOpen?: (isOpen: boolean) => void;
@@ -53,6 +53,13 @@ interface ChatPanelProps {
53
53
  headerIcon?: IconName | React.ReactElement;
54
54
  headerTitle?: string;
55
55
  headerSubtitle?: string;
56
+ /** When set, replaces default behavior (setFormState + onNavigate + onClose) for command suggestions. */
57
+ onSuggestionSelect?: (s: CommandSuggestion) => void;
58
+ /**
59
+ * Applied to the full-screen modal root so the chat stacks above app chrome that uses high z-index
60
+ * (e.g. MUI AppBar ~1100, custom sidebars ~999). Default Tailwind z-50 is too low for many shells.
61
+ */
62
+ overlayZIndex?: number;
56
63
  }
57
64
  /**
58
65
  * ChatPanel component
@@ -91,7 +98,7 @@ showHistory, // Default to hidden
91
98
  showProfileBubbles, // Default to hidden
92
99
  modalPosition, // Default to left position
93
100
  serverConfig, models, defaultModel, showUsageStats, maxFileSize, features, showFloatingButton, floatingButtonIcon, floatingButtonPosition, floatingButtonSize, floatingButtonClassName, chats, setChats, currentChatId, setCurrentChatId, chatLevel, initialQuery, setInitialQuery, headerIcon, // Default to bot icon
94
- headerTitle, headerSubtitle, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
101
+ headerTitle, headerSubtitle, onSuggestionSelect, overlayZIndex, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
95
102
  /**
96
103
  * ChatInput component
97
104
  * @param query - The current query
@@ -118,6 +125,7 @@ type FloatingChatButtonProps = {
118
125
  className?: string;
119
126
  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
120
127
  size?: 'sm' | 'md' | 'lg';
128
+ zIndex?: number;
121
129
  };
122
130
  /**
123
131
  * FloatingChatButton component
@@ -128,5 +136,5 @@ type FloatingChatButtonProps = {
128
136
  * @param position - Position of the floating button
129
137
  * @param size - Size of the floating button
130
138
  */
131
- export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
139
+ export declare function FloatingChatButton({ onClick, theme, icon, className, position, size, zIndex: floatingZIndex, }: FloatingChatButtonProps): import("react/jsx-runtime").JSX.Element;
132
140
  export {};
@@ -72,5 +72,5 @@ interface ConversationProps {
72
72
  * @param autoScroll - Whether to auto-scroll to bottom on new messages
73
73
  * @param maxHeight - Maximum height of the conversation container
74
74
  */
75
- export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, setFormState, onNavigate, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
75
+ export declare function Conversation({ chat: externalChat, onSuggestionClick, theme, showProfileBubbles, className, autoScroll, maxHeight, userId, serverConfig, formData, chatLevel, chats: externalChats, setChats: externalSetChats, currentChatId: externalCurrentChatId, setCurrentChatId: externalSetCurrentChatId, query: externalQuery, setQuery: externalSetQuery, onSend: externalOnSend, isLoading: externalIsLoading, attachedFiles: externalAttachedFiles, setAttachedFiles: externalSetAttachedFiles, models, defaultModel, showUsageStats, maxFileSize, features, currentModelSelection: externalCurrentModelSelection, onModelSelectionChange: externalOnModelSelectionChange, showInput, initialQuery, setInitialQuery, showClearChat, onClearChat, additionalContext, }: ConversationProps): import("react/jsx-runtime").JSX.Element;
76
76
  export {};
@@ -6771,6 +6771,7 @@ const commandTrainingRules = {
6771
6771
  components: {
6772
6772
  patterns: {
6773
6773
  // React component patterns
6774
+ // Has /g for matchAll in training.ts; do not use String.match(componentName) (groups break).
6774
6775
  componentName: /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g,
6775
6776
  props: /interface\s+(\w+)Props\s*{([^}]*)}/g,
6776
6777
  state: /useState<([^>]*)>/g,
@@ -6795,7 +6796,8 @@ const commandTrainingRules = {
6795
6796
  schemas: {
6796
6797
  patterns: {
6797
6798
  // Monastery schema patterns - updated for actual file format
6798
- modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/g,
6799
+ // No /g: training.ts uses String.match(); with g, capture groups are omitted and modelName is always lost.
6800
+ modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/,
6799
6801
  fields: /fields:\s*{([^}]*)}/g,
6800
6802
  fieldDefinitions: /(\w+):\s*{\s*(?:required:\s*(true|false),?\s*)?type:\s*['"]([^'"]+)['"](?:,\s*required:\s*(true|false))?(?:,\s*default:\s*[^,}]+)?/g,
6801
6803
  indexes: /indexes:\s*\[([^\]]*)\]/g,
@@ -7643,6 +7645,7 @@ class CommandTrainingCollector {
7643
7645
  if (content.formFields?.length > 0) {
7644
7646
  const form = {
7645
7647
  name: content.componentName || 'Unknown Form',
7648
+ sourceFile: path__default.relative(this.rootDir, component.filePath),
7646
7649
  purpose: `Form component for data entry`,
7647
7650
  fields: content.formFields.map((fieldName) => ({
7648
7651
  name: fieldName,
@@ -7771,12 +7774,15 @@ class CommandTrainingCollector {
7771
7774
  guessEntityFromComponent(componentName) {
7772
7775
  if (!componentName)
7773
7776
  return 'Unknown';
7774
- // Simple heuristic: remove common suffixes
7777
+ // Strip common create/edit wrappers, then UI suffixes (order matters)
7775
7778
  const cleaned = componentName
7779
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
7776
7780
  .replace(/Form$/, '')
7781
+ .replace(/Modal$/, '')
7782
+ .replace(/Drawer$/, '')
7783
+ .replace(/Dialog$/, '')
7777
7784
  .replace(/Page$/, '')
7778
- .replace(/Component$/, '')
7779
- .replace(/Modal$/, '');
7785
+ .replace(/Component$/, '');
7780
7786
  return cleaned || 'Unknown';
7781
7787
  }
7782
7788
  guessEntitiesFromComponent(content) {
@@ -7890,7 +7896,7 @@ class CommandTrainingCollector {
7890
7896
  this.log(`āŒ Error expanding pattern "${pattern}":`, err.message);
7891
7897
  }
7892
7898
  }
7893
- return expandedPaths;
7899
+ return [...new Set(expandedPaths)];
7894
7900
  }
7895
7901
  extractFileInfo(fieldName, content) {
7896
7902
  switch (fieldName) {
@@ -7934,11 +7940,22 @@ class CommandTrainingCollector {
7934
7940
  hooks: [],
7935
7941
  eventHandlers: [],
7936
7942
  };
7937
- // Extract component name
7938
- const componentMatch = content.match(patterns.componentName);
7939
- if (componentMatch) {
7940
- result.componentName = componentMatch[1];
7941
- }
7943
+ // Do not use String.match() on patterns.componentName — it has /g, so match[1] is the *second*
7944
+ // full match, not capture group 1 (yields strings like `const CustomerForm =`).
7945
+ const declRe = /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g;
7946
+ const declNames = [];
7947
+ for (const m of content.matchAll(declRe)) {
7948
+ declNames.push(m[1]);
7949
+ }
7950
+ const isLikelyComponentSymbol = (n) => /^[A-Z]/.test(n) &&
7951
+ !/^use[A-Z]/.test(n) &&
7952
+ !/^Styled/i.test(n);
7953
+ const preferred = [...declNames].reverse().find((n) => isLikelyComponentSymbol(n) &&
7954
+ (/(?:Form|Modal|Drawer|Dialog)$/.test(n) ||
7955
+ /^FormStep/i.test(n) ||
7956
+ (n.includes('Form') && n.length > 4)));
7957
+ const fallback = [...declNames].reverse().find(isLikelyComponentSymbol);
7958
+ result.componentName = preferred ?? fallback ?? null;
7942
7959
  // Extract props interfaces
7943
7960
  const propsMatches = content.matchAll(patterns.props);
7944
7961
  for (const match of propsMatches) {
@@ -7973,6 +7990,7 @@ class CommandTrainingCollector {
7973
7990
  for (const match of fieldMatches) {
7974
7991
  result.formFields.push(match[1]);
7975
7992
  }
7993
+ result.formFields = [...new Set(result.formFields)];
7976
7994
  // Extract imports
7977
7995
  const importMatches = content.matchAll(patterns.imports);
7978
7996
  for (const match of importMatches) {
@@ -15729,6 +15747,7 @@ class SchemaGenerator extends CommandTrainingCollector {
15729
15747
  };
15730
15748
  this.log(` āœ… Generated schema with ${Object.keys(properties).length} properties`);
15731
15749
  }
15750
+ this.mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas);
15732
15751
  // If no entities found, try to extract from components
15733
15752
  if (Object.keys(schemas).length === 0) {
15734
15753
  this.log(' āš ļø No entities found in training data, extracting from components...');
@@ -15736,6 +15755,87 @@ class SchemaGenerator extends CommandTrainingCollector {
15736
15755
  }
15737
15756
  return schemas;
15738
15757
  }
15758
+ /**
15759
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
15760
+ * (server models stay canonical; this adds frontend surface hints).
15761
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
15762
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
15763
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
15764
+ */
15765
+ mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas) {
15766
+ const forms = trainingData.customTrainingData?.structuredData?.components?.forms || [];
15767
+ if (!forms.length || !Object.keys(schemas).length)
15768
+ return;
15769
+ const hints = (trainingData.customTrainingData?.options?.formEntityHints || {});
15770
+ const pathPatterns = (trainingData.customTrainingData?.options?.formEntityPathPatterns ||
15771
+ []);
15772
+ /** Short UI stems that don't match lowered model names */
15773
+ const STEM_ALIASES = {
15774
+ hs: 'hsreport',
15775
+ incident: 'incidentreport',
15776
+ };
15777
+ const schemaKeys = new Set(Object.keys(schemas));
15778
+ const resolveKey = (form) => {
15779
+ if (form.sourceFile) {
15780
+ for (const p of pathPatterns) {
15781
+ if (!p?.includes || !p?.entity)
15782
+ continue;
15783
+ if (form.sourceFile.includes(p.includes)) {
15784
+ const k = p.entity.toLowerCase();
15785
+ if (schemaKeys.has(k))
15786
+ return k;
15787
+ }
15788
+ }
15789
+ }
15790
+ const tryKey = (raw) => {
15791
+ if (!raw)
15792
+ return undefined;
15793
+ const mapped = hints[raw];
15794
+ const stem = raw
15795
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
15796
+ .replace(/(?:Form|Modal|Drawer|Dialog)$/i, '');
15797
+ const stemLc = stem.toLowerCase();
15798
+ const alias = STEM_ALIASES[stemLc];
15799
+ if (alias && schemaKeys.has(alias))
15800
+ return alias;
15801
+ const candidates = [
15802
+ (mapped || raw).toLowerCase(),
15803
+ stemLc,
15804
+ ];
15805
+ for (const c of candidates) {
15806
+ if (c && schemaKeys.has(c))
15807
+ return c;
15808
+ }
15809
+ return undefined;
15810
+ };
15811
+ return tryKey(form.name) || tryKey(form.relatedEntity) || undefined;
15812
+ };
15813
+ let mergedForms = 0;
15814
+ let mergedFields = 0;
15815
+ for (const form of forms) {
15816
+ const entityKey = resolveKey(form);
15817
+ if (!entityKey)
15818
+ continue;
15819
+ const gen = schemas[entityKey];
15820
+ if (!gen?.schema?.properties)
15821
+ continue;
15822
+ const props = gen.schema.properties;
15823
+ for (const f of form.fields || []) {
15824
+ const n = f?.name;
15825
+ if (!n || typeof n !== 'string' || props[n])
15826
+ continue;
15827
+ props[n] = {
15828
+ type: 'string',
15829
+ description: `UI form field (from ${form.name}). Cross-check server model; may overlap sharing/base shapes.`,
15830
+ };
15831
+ mergedFields += 1;
15832
+ }
15833
+ mergedForms += 1;
15834
+ }
15835
+ if (mergedForms > 0) {
15836
+ this.log(`\nšŸ“Ž Merged UI form fields into ${mergedForms} entity schema(s) (+${mergedFields} properties)`);
15837
+ }
15838
+ }
15739
15839
  /**
15740
15840
  * Extract schemas from component analysis if no explicit entities found
15741
15841
  */
@@ -16049,6 +16149,9 @@ class SchemaGenerator extends CommandTrainingCollector {
16049
16149
  * Map training data field types to JSON Schema types
16050
16150
  */
16051
16151
  mapFieldType(type) {
16152
+ if (type == null || typeof type !== 'string') {
16153
+ return 'string';
16154
+ }
16052
16155
  const typeMap = {
16053
16156
  string: 'string',
16054
16157
  number: 'number',
@@ -6791,6 +6791,7 @@ const commandTrainingRules = {
6791
6791
  components: {
6792
6792
  patterns: {
6793
6793
  // React component patterns
6794
+ // Has /g for matchAll in training.ts; do not use String.match(componentName) (groups break).
6794
6795
  componentName: /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g,
6795
6796
  props: /interface\s+(\w+)Props\s*{([^}]*)}/g,
6796
6797
  state: /useState<([^>]*)>/g,
@@ -6815,7 +6816,8 @@ const commandTrainingRules = {
6815
6816
  schemas: {
6816
6817
  patterns: {
6817
6818
  // Monastery schema patterns - updated for actual file format
6818
- modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/g,
6819
+ // No /g: training.ts uses String.match(); with g, capture groups are omitted and modelName is always lost.
6820
+ modelName: /\/\/\s*(\w+)\s+model\s+for\s+monastery/,
6819
6821
  fields: /fields:\s*{([^}]*)}/g,
6820
6822
  fieldDefinitions: /(\w+):\s*{\s*(?:required:\s*(true|false),?\s*)?type:\s*['"]([^'"]+)['"](?:,\s*required:\s*(true|false))?(?:,\s*default:\s*[^,}]+)?/g,
6821
6823
  indexes: /indexes:\s*\[([^\]]*)\]/g,
@@ -7663,6 +7665,7 @@ class CommandTrainingCollector {
7663
7665
  if (content.formFields?.length > 0) {
7664
7666
  const form = {
7665
7667
  name: content.componentName || 'Unknown Form',
7668
+ sourceFile: path$a.relative(this.rootDir, component.filePath),
7666
7669
  purpose: `Form component for data entry`,
7667
7670
  fields: content.formFields.map((fieldName) => ({
7668
7671
  name: fieldName,
@@ -7791,12 +7794,15 @@ class CommandTrainingCollector {
7791
7794
  guessEntityFromComponent(componentName) {
7792
7795
  if (!componentName)
7793
7796
  return 'Unknown';
7794
- // Simple heuristic: remove common suffixes
7797
+ // Strip common create/edit wrappers, then UI suffixes (order matters)
7795
7798
  const cleaned = componentName
7799
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
7796
7800
  .replace(/Form$/, '')
7801
+ .replace(/Modal$/, '')
7802
+ .replace(/Drawer$/, '')
7803
+ .replace(/Dialog$/, '')
7797
7804
  .replace(/Page$/, '')
7798
- .replace(/Component$/, '')
7799
- .replace(/Modal$/, '');
7805
+ .replace(/Component$/, '');
7800
7806
  return cleaned || 'Unknown';
7801
7807
  }
7802
7808
  guessEntitiesFromComponent(content) {
@@ -7910,7 +7916,7 @@ class CommandTrainingCollector {
7910
7916
  this.log(`āŒ Error expanding pattern "${pattern}":`, err.message);
7911
7917
  }
7912
7918
  }
7913
- return expandedPaths;
7919
+ return [...new Set(expandedPaths)];
7914
7920
  }
7915
7921
  extractFileInfo(fieldName, content) {
7916
7922
  switch (fieldName) {
@@ -7954,11 +7960,22 @@ class CommandTrainingCollector {
7954
7960
  hooks: [],
7955
7961
  eventHandlers: [],
7956
7962
  };
7957
- // Extract component name
7958
- const componentMatch = content.match(patterns.componentName);
7959
- if (componentMatch) {
7960
- result.componentName = componentMatch[1];
7961
- }
7963
+ // Do not use String.match() on patterns.componentName — it has /g, so match[1] is the *second*
7964
+ // full match, not capture group 1 (yields strings like `const CustomerForm =`).
7965
+ const declRe = /(?:export\s+)?(?:function|const)\s+(\w+)(?:\s*<[^>]*>)?\s*[=(]/g;
7966
+ const declNames = [];
7967
+ for (const m of content.matchAll(declRe)) {
7968
+ declNames.push(m[1]);
7969
+ }
7970
+ const isLikelyComponentSymbol = (n) => /^[A-Z]/.test(n) &&
7971
+ !/^use[A-Z]/.test(n) &&
7972
+ !/^Styled/i.test(n);
7973
+ const preferred = [...declNames].reverse().find((n) => isLikelyComponentSymbol(n) &&
7974
+ (/(?:Form|Modal|Drawer|Dialog)$/.test(n) ||
7975
+ /^FormStep/i.test(n) ||
7976
+ (n.includes('Form') && n.length > 4)));
7977
+ const fallback = [...declNames].reverse().find(isLikelyComponentSymbol);
7978
+ result.componentName = preferred ?? fallback ?? null;
7962
7979
  // Extract props interfaces
7963
7980
  const propsMatches = content.matchAll(patterns.props);
7964
7981
  for (const match of propsMatches) {
@@ -7993,6 +8010,7 @@ class CommandTrainingCollector {
7993
8010
  for (const match of fieldMatches) {
7994
8011
  result.formFields.push(match[1]);
7995
8012
  }
8013
+ result.formFields = [...new Set(result.formFields)];
7996
8014
  // Extract imports
7997
8015
  const importMatches = content.matchAll(patterns.imports);
7998
8016
  for (const match of importMatches) {
@@ -15749,6 +15767,7 @@ class SchemaGenerator extends CommandTrainingCollector {
15749
15767
  };
15750
15768
  this.log(` āœ… Generated schema with ${Object.keys(properties).length} properties`);
15751
15769
  }
15770
+ this.mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas);
15752
15771
  // If no entities found, try to extract from components
15753
15772
  if (Object.keys(schemas).length === 0) {
15754
15773
  this.log(' āš ļø No entities found in training data, extracting from components...');
@@ -15756,6 +15775,87 @@ class SchemaGenerator extends CommandTrainingCollector {
15756
15775
  }
15757
15776
  return schemas;
15758
15777
  }
15778
+ /**
15779
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
15780
+ * (server models stay canonical; this adds frontend surface hints).
15781
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
15782
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
15783
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
15784
+ */
15785
+ mergeFormUiFieldsIntoEntitySchemas(trainingData, schemas) {
15786
+ const forms = trainingData.customTrainingData?.structuredData?.components?.forms || [];
15787
+ if (!forms.length || !Object.keys(schemas).length)
15788
+ return;
15789
+ const hints = (trainingData.customTrainingData?.options?.formEntityHints || {});
15790
+ const pathPatterns = (trainingData.customTrainingData?.options?.formEntityPathPatterns ||
15791
+ []);
15792
+ /** Short UI stems that don't match lowered model names */
15793
+ const STEM_ALIASES = {
15794
+ hs: 'hsreport',
15795
+ incident: 'incidentreport',
15796
+ };
15797
+ const schemaKeys = new Set(Object.keys(schemas));
15798
+ const resolveKey = (form) => {
15799
+ if (form.sourceFile) {
15800
+ for (const p of pathPatterns) {
15801
+ if (!p?.includes || !p?.entity)
15802
+ continue;
15803
+ if (form.sourceFile.includes(p.includes)) {
15804
+ const k = p.entity.toLowerCase();
15805
+ if (schemaKeys.has(k))
15806
+ return k;
15807
+ }
15808
+ }
15809
+ }
15810
+ const tryKey = (raw) => {
15811
+ if (!raw)
15812
+ return undefined;
15813
+ const mapped = hints[raw];
15814
+ const stem = raw
15815
+ .replace(/^(?:Create|Edit|View|New|Batch)/i, '')
15816
+ .replace(/(?:Form|Modal|Drawer|Dialog)$/i, '');
15817
+ const stemLc = stem.toLowerCase();
15818
+ const alias = STEM_ALIASES[stemLc];
15819
+ if (alias && schemaKeys.has(alias))
15820
+ return alias;
15821
+ const candidates = [
15822
+ (mapped || raw).toLowerCase(),
15823
+ stemLc,
15824
+ ];
15825
+ for (const c of candidates) {
15826
+ if (c && schemaKeys.has(c))
15827
+ return c;
15828
+ }
15829
+ return undefined;
15830
+ };
15831
+ return tryKey(form.name) || tryKey(form.relatedEntity) || undefined;
15832
+ };
15833
+ let mergedForms = 0;
15834
+ let mergedFields = 0;
15835
+ for (const form of forms) {
15836
+ const entityKey = resolveKey(form);
15837
+ if (!entityKey)
15838
+ continue;
15839
+ const gen = schemas[entityKey];
15840
+ if (!gen?.schema?.properties)
15841
+ continue;
15842
+ const props = gen.schema.properties;
15843
+ for (const f of form.fields || []) {
15844
+ const n = f?.name;
15845
+ if (!n || typeof n !== 'string' || props[n])
15846
+ continue;
15847
+ props[n] = {
15848
+ type: 'string',
15849
+ description: `UI form field (from ${form.name}). Cross-check server model; may overlap sharing/base shapes.`,
15850
+ };
15851
+ mergedFields += 1;
15852
+ }
15853
+ mergedForms += 1;
15854
+ }
15855
+ if (mergedForms > 0) {
15856
+ this.log(`\nšŸ“Ž Merged UI form fields into ${mergedForms} entity schema(s) (+${mergedFields} properties)`);
15857
+ }
15858
+ }
15759
15859
  /**
15760
15860
  * Extract schemas from component analysis if no explicit entities found
15761
15861
  */
@@ -16069,6 +16169,9 @@ class SchemaGenerator extends CommandTrainingCollector {
16069
16169
  * Map training data field types to JSON Schema types
16070
16170
  */
16071
16171
  mapFieldType(type) {
16172
+ if (type == null || typeof type !== 'string') {
16173
+ return 'string';
16174
+ }
16072
16175
  const typeMap = {
16073
16176
  string: 'string',
16074
16177
  number: 'number',
@@ -55,6 +55,14 @@ export declare class SchemaGenerator extends CommandTrainingCollector {
55
55
  * Generate schemas from collected training data
56
56
  */
57
57
  private generateSchemas;
58
+ /**
59
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
60
+ * (server models stay canonical; this adds frontend surface hints).
61
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
62
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
63
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
64
+ */
65
+ private mergeFormUiFieldsIntoEntitySchemas;
58
66
  /**
59
67
  * Extract schemas from component analysis if no explicit entities found
60
68
  */
@@ -55,6 +55,14 @@ export declare class SchemaGenerator extends CommandTrainingCollector {
55
55
  * Generate schemas from collected training data
56
56
  */
57
57
  private generateSchemas;
58
+ /**
59
+ * Merge `name="..."` fields collected from UI forms/modals into existing entity schemas
60
+ * (server models stay canonical; this adds frontend surface hints).
61
+ * Optional `customTrainingData.options.formEntityHints`: map form component name -> schema entity key.
62
+ * Optional `formEntityPathPatterns`: `{ includes, entity }` — first match on `form.sourceFile` wins
63
+ * (disambiguates reused names like `FormStepDetails` in different feature folders).
64
+ */
65
+ private mergeFormUiFieldsIntoEntitySchemas;
58
66
  /**
59
67
  * Extract schemas from component analysis if no explicit entities found
60
68
  */
@@ -0,0 +1,2 @@
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.-right-2{right:-.5rem}.-top-1{top:-.25rem}.-top-2{top:-.5rem}.bottom-0{bottom:0}.bottom-2{bottom:.5rem}.bottom-4{bottom:1rem}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:.5rem}.left-6{left:1.5rem}.left-\[0\.5px\]{left:.5px}.right-0{right:0}.right-1{right:.25rem}.right-2{right:.5rem}.right-4{right:1rem}.right-6{right:1.5rem}.right-\[-4px\]{right:-4px}.right-full{right:100%}.top-0{top:0}.top-1{top:.25rem}.top-2{top:.5rem}.top-4{top:1rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-50{z-index:50}.z-\[10000\]{z-index:10000}.z-\[60\]{z-index:60}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.ml-2{margin-left:.5rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.line-clamp-2{-webkit-box-orient:vertical;-webkit-line-clamp:2;display:-webkit-box;overflow:hidden}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.contents{display:contents}.hidden{display:none}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.max-h-32{max-height:8rem}.max-h-64{max-height:16rem}.max-h-80{max-height:20rem}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-\[3\.5rem\]{min-height:3.5rem}.min-h-\[72px\]{min-height:72px}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-\[150px\]{width:150px}.w-full{width:100%}.min-w-0{min-width:0}.min-w-80{min-width:20rem}.max-w-32{max-width:8rem}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.flex-grow-0{flex-grow:0}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-full{--tw-translate-x:-100%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-2{--tw-translate-x:0.5rem}.translate-x-4{--tw-translate-x:1rem}.translate-x-4,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-0{--tw-translate-y:0px}.translate-y-0,.translate-y-2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-2{--tw-translate-y:0.5rem}.translate-y-4{--tw-translate-y:1rem}.translate-y-4,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-full{--tw-translate-y:100%}.rotate-0{--tw-rotate:0deg}.rotate-0,.rotate-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-12{--tw-rotate:12deg}.rotate-180{--tw-rotate:180deg}.rotate-180,.rotate-45{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-45{--tw-rotate:45deg}.rotate-90{--tw-rotate:90deg}.rotate-90,.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-75{--tw-scale-x:.75;--tw-scale-y:.75}.scale-75,.scale-95{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-help{cursor:help}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.resize-none{resize:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.125rem*var(--tw-space-y-reverse));margin-top:calc(.125rem*(1 - var(--tw-space-y-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-l-lg{border-bottom-left-radius:.5rem;border-top-left-radius:.5rem}.rounded-r-lg{border-bottom-right-radius:.5rem;border-top-right-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-amber-200{--tw-border-opacity:1;border-color:rgb(253 230 138/var(--tw-border-opacity,1))}.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}.border-current{border-color:currentColor}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-orange-200{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.border-white\/20{border-color:hsla(0,0%,100%,.2)}.border-yellow-200{--tw-border-opacity:1;border-color:rgb(254 240 138/var(--tw-border-opacity,1))}.border-opacity-50{--tw-border-opacity:0.5}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-black\/20{background-color:rgba(0,0,0,.2)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-black\/70{background-color:rgba(0,0,0,.7)}.bg-black\/80{background-color:rgba(0,0,0,.8)}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.bg-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white\/10{background-color:hsla(0,0%,100%,.1)}.bg-white\/20{background-color:hsla(0,0%,100%,.2)}.bg-yellow-100{--tw-bg-opacity:1;background-color:rgb(254 249 195/var(--tw-bg-opacity,1))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity,1))}.bg-opacity-20{--tw-bg-opacity:0.2}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-8{padding:2rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-bottom:.125rem;padding-top:.125rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pr-4{padding-right:1rem}.pr-6{padding-right:1.5rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12/var(--tw-text-opacity,1))}.text-orange-700{--tw-text-opacity:1;color:rgb(194 65 12/var(--tw-text-opacity,1))}.text-orange-800{--tw-text-opacity:1;color:rgb(154 52 18/var(--tw-text-opacity,1))}.text-purple-600{--tw-text-opacity:1;color:rgb(147 51 234/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-red-800{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/70{color:hsla(0,0%,100%,.7)}.text-yellow-600{--tw-text-opacity:1;color:rgb(202 138 4/var(--tw-text-opacity,1))}.text-yellow-700{--tw-text-opacity:1;color:rgb(161 98 7/var(--tw-text-opacity,1))}.text-yellow-800{--tw-text-opacity:1;color:rgb(133 77 14/var(--tw-text-opacity,1))}.line-through{text-decoration-line:line-through}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-duration:.15s;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.delay-100{transition-delay:.1s}.delay-200{transition-delay:.2s}.delay-300{transition-delay:.3s}.delay-500{transition-delay:.5s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.focus-within\:shadow-sm:focus-within{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:scale-105:hover{--tw-scale-x:1.05;--tw-scale-y:1.05}.hover\:scale-105:hover,.hover\:scale-110:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-110:hover{--tw-scale-x:1.1;--tw-scale-y:1.1}.hover\:bg-amber-200:hover{--tw-bg-opacity:1;background-color:rgb(253 230 138/var(--tw-bg-opacity,1))}.hover\:bg-black\/70:hover{background-color:rgba(0,0,0,.7)}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-orange-200:hover{--tw-bg-opacity:1;background-color:rgb(254 215 170/var(--tw-bg-opacity,1))}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity,1))}.hover\:bg-white\/20:hover{background-color:hsla(0,0%,100%,.2)}.hover\:text-amber-700:hover{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.hover\:text-blue-500:hover{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.hover\:text-orange-700:hover{--tw-text-opacity:1;color:rgb(194 65 12/var(--tw-text-opacity,1))}.hover\:opacity-80:hover{opacity:.8}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-4:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-200:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(191 219 254/var(--tw-ring-opacity,1))}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width:640px){.sm\:w-\[80vw\]{width:80vw}.sm\:w-\[90vw\]{width:90vw}}@media (min-width:768px){.md\:w-\[550px\]{width:550px}.md\:w-\[700px\]{width:700px}}
2
+ /*# sourceMappingURL=styles.css.map */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchid-ai",
3
- "version": "1.3.1",
3
+ "version": "1.3.6",
4
4
  "type": "module",
5
5
  "description": "AI-powered command processing and chat interface for React applications",
6
6
  "main": "dist/index.js",