@vc-shell/framework 1.2.2 → 1.2.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/core/composables/index.ts +2 -0
  2. package/core/composables/useAssets/index.ts +72 -28
  3. package/core/composables/useAsync/index.ts +4 -1
  4. package/core/composables/useBladeRegistry/index.ts +6 -5
  5. package/core/composables/useBreadcrumbs/index.ts +4 -1
  6. package/core/composables/useErrorHandler/index.ts +4 -1
  7. package/core/composables/useFunctions/debounce.ts +0 -1
  8. package/core/composables/useFunctions/delay.ts +0 -1
  9. package/core/composables/useFunctions/index.ts +0 -1
  10. package/core/composables/useFunctions/once.ts +0 -1
  11. package/core/composables/useFunctions/sleep.ts +0 -1
  12. package/core/composables/useFunctions/throttle.ts +0 -1
  13. package/core/composables/useGlobalSearch/index.ts +3 -3
  14. package/core/composables/useMenuService/index.ts +5 -2
  15. package/core/composables/useNotifications/index.ts +5 -2
  16. package/core/composables/useTheme/index.ts +4 -1
  17. package/core/composables/useUser/index.ts +189 -20
  18. package/core/composables/useWidgets/index.ts +5 -2
  19. package/core/constants/defaults.ts +76 -0
  20. package/core/constants/index.ts +2 -0
  21. package/core/constants/ui.ts +68 -0
  22. package/core/interceptors/index.ts +5 -2
  23. package/core/plugins/ai-agent/README.md +336 -0
  24. package/core/plugins/ai-agent/components/VcAiAgentPanel.vue +125 -0
  25. package/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue +182 -0
  26. package/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue +77 -0
  27. package/core/plugins/ai-agent/components/index.ts +1 -0
  28. package/core/plugins/ai-agent/composables/index.ts +4 -0
  29. package/core/plugins/ai-agent/composables/useAiAgent.ts +231 -0
  30. package/core/plugins/ai-agent/composables/useAiAgentContext.ts +280 -0
  31. package/core/plugins/ai-agent/constants.ts +89 -0
  32. package/core/plugins/ai-agent/index.ts +91 -0
  33. package/core/plugins/ai-agent/services/ai-agent-service.ts +598 -0
  34. package/core/plugins/ai-agent/types.ts +310 -0
  35. package/core/plugins/modularity/index.ts +8 -6
  36. package/core/plugins/modularity/loader.ts +36 -33
  37. package/core/plugins/signalR/index.ts +6 -3
  38. package/core/services/app-bar-menu-service.ts +4 -1
  39. package/core/services/dashboard-service.ts +4 -1
  40. package/core/services/index.ts +2 -0
  41. package/core/services/menu-service.ts +4 -1
  42. package/core/services/settings-menu-service.ts +4 -1
  43. package/core/services/toolbar-service.ts +18 -3
  44. package/core/services/widget-service.ts +7 -4
  45. package/core/types/index.ts +3 -0
  46. package/core/types/services.ts +194 -0
  47. package/core/utilities/errorTypes.ts +126 -0
  48. package/core/utilities/index.ts +2 -0
  49. package/core/utilities/logger.ts +120 -0
  50. package/dist/core/composables/useAssets/index.d.ts.map +1 -1
  51. package/dist/core/composables/useAsync/index.d.ts.map +1 -1
  52. package/dist/core/composables/useBladeRegistry/index.d.ts.map +1 -1
  53. package/dist/core/composables/useBreadcrumbs/index.d.ts.map +1 -1
  54. package/dist/core/composables/useErrorHandler/index.d.ts.map +1 -1
  55. package/dist/core/composables/useFunctions/debounce.d.ts.map +1 -1
  56. package/dist/core/composables/useFunctions/delay.d.ts.map +1 -1
  57. package/dist/core/composables/useFunctions/index.d.ts.map +1 -1
  58. package/dist/core/composables/useFunctions/once.d.ts.map +1 -1
  59. package/dist/core/composables/useFunctions/sleep.d.ts.map +1 -1
  60. package/dist/core/composables/useFunctions/throttle.d.ts.map +1 -1
  61. package/dist/core/composables/useGlobalSearch/index.d.ts.map +1 -1
  62. package/dist/core/composables/useMenuService/index.d.ts.map +1 -1
  63. package/dist/core/composables/useNotifications/index.d.ts.map +1 -1
  64. package/dist/core/composables/useTheme/index.d.ts.map +1 -1
  65. package/dist/core/composables/useUser/index.d.ts +8 -0
  66. package/dist/core/composables/useUser/index.d.ts.map +1 -1
  67. package/dist/core/composables/useWidgets/index.d.ts.map +1 -1
  68. package/dist/core/constants/defaults.d.ts +63 -0
  69. package/dist/core/constants/defaults.d.ts.map +1 -0
  70. package/dist/core/constants/index.d.ts +2 -0
  71. package/dist/core/constants/index.d.ts.map +1 -1
  72. package/dist/core/constants/ui.d.ts +50 -0
  73. package/dist/core/constants/ui.d.ts.map +1 -0
  74. package/dist/core/interceptors/index.d.ts.map +1 -1
  75. package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts +3 -0
  76. package/dist/core/plugins/ai-agent/components/VcAiAgentPanel.vue.d.ts.map +1 -0
  77. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts +15 -0
  78. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentHeader.vue.d.ts.map +1 -0
  79. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts +10 -0
  80. package/dist/core/plugins/ai-agent/components/_internal/VcAiAgentIframe.vue.d.ts.map +1 -0
  81. package/dist/core/plugins/ai-agent/components/index.d.ts +2 -0
  82. package/dist/core/plugins/ai-agent/components/index.d.ts.map +1 -0
  83. package/dist/core/plugins/ai-agent/composables/index.d.ts +4 -0
  84. package/dist/core/plugins/ai-agent/composables/index.d.ts.map +1 -0
  85. package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts +95 -0
  86. package/dist/core/plugins/ai-agent/composables/useAiAgent.d.ts.map +1 -0
  87. package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts +55 -0
  88. package/dist/core/plugins/ai-agent/composables/useAiAgentContext.d.ts.map +1 -0
  89. package/dist/core/plugins/ai-agent/constants.d.ts +47 -0
  90. package/dist/core/plugins/ai-agent/constants.d.ts.map +1 -0
  91. package/dist/core/plugins/ai-agent/index.d.ts +48 -0
  92. package/dist/core/plugins/ai-agent/index.d.ts.map +1 -0
  93. package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts +45 -0
  94. package/dist/core/plugins/ai-agent/services/ai-agent-service.d.ts.map +1 -0
  95. package/dist/core/plugins/ai-agent/types.d.ts +258 -0
  96. package/dist/core/plugins/ai-agent/types.d.ts.map +1 -0
  97. package/dist/core/plugins/modularity/index.d.ts.map +1 -1
  98. package/dist/core/plugins/modularity/loader.d.ts.map +1 -1
  99. package/dist/core/plugins/signalR/index.d.ts.map +1 -1
  100. package/dist/core/services/app-bar-menu-service.d.ts.map +1 -1
  101. package/dist/core/services/dashboard-service.d.ts.map +1 -1
  102. package/dist/core/services/menu-service.d.ts.map +1 -1
  103. package/dist/core/services/settings-menu-service.d.ts.map +1 -1
  104. package/dist/core/services/toolbar-service.d.ts.map +1 -1
  105. package/dist/core/services/widget-service.d.ts.map +1 -1
  106. package/dist/core/types/index.d.ts.map +1 -1
  107. package/dist/core/types/services.d.ts +169 -0
  108. package/dist/core/types/services.d.ts.map +1 -0
  109. package/dist/core/utilities/errorTypes.d.ts +61 -0
  110. package/dist/core/utilities/errorTypes.d.ts.map +1 -0
  111. package/dist/core/utilities/index.d.ts +2 -0
  112. package/dist/core/utilities/index.d.ts.map +1 -1
  113. package/dist/core/utilities/logger.d.ts +259 -0
  114. package/dist/core/utilities/logger.d.ts.map +1 -0
  115. package/dist/framework.js +9623 -8417
  116. package/dist/index.css +1 -1
  117. package/dist/index.d.ts +19 -0
  118. package/dist/index.d.ts.map +1 -1
  119. package/dist/injection-keys.d.ts +21 -6
  120. package/dist/injection-keys.d.ts.map +1 -1
  121. package/dist/shared/components/app-switcher/composables/useAppSwitcher/index.d.ts.map +1 -1
  122. package/dist/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue.d.ts.map +1 -1
  123. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/index.d.ts.map +1 -1
  124. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.d.ts.map +1 -1
  125. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.d.ts.map +1 -1
  126. package/dist/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.d.ts.map +1 -1
  127. package/dist/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.d.ts.map +1 -1
  128. package/dist/shared/components/draggable-dashboard/composables/useLayoutPersistence.d.ts.map +1 -1
  129. package/dist/shared/components/notifications/composables/useContainer/index.d.ts.map +1 -1
  130. package/dist/shared/components/notifications/composables/useInstance/index.d.ts.map +1 -1
  131. package/dist/shared/components/notifications/core/notification.d.ts.map +1 -1
  132. package/dist/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue.d.ts.map +1 -1
  133. package/dist/shared/components/sign-in/useExternalProvider.d.ts.map +1 -1
  134. package/dist/shared/composables/index.d.ts +1 -0
  135. package/dist/shared/composables/index.d.ts.map +1 -1
  136. package/dist/shared/composables/useExternalWidgets.d.ts.map +1 -1
  137. package/dist/shared/composables/useMenuExpanded.d.ts.map +1 -1
  138. package/dist/shared/composables/useTableSelection.d.ts +57 -0
  139. package/dist/shared/composables/useTableSelection.d.ts.map +1 -0
  140. package/dist/shared/composables/useTableSort.d.ts.map +1 -1
  141. package/dist/shared/modules/assets-manager/components/assets-manager/assets-manager.vue.d.ts.map +1 -1
  142. package/dist/shared/pages/LoginPage/components/login/Login.vue.d.ts.map +1 -1
  143. package/dist/shared/utilities/colorUtils.d.ts +0 -6
  144. package/dist/shared/utilities/colorUtils.d.ts.map +1 -1
  145. package/dist/tsconfig.tsbuildinfo +1 -1
  146. package/dist/ui/components/atoms/vc-banner/vc-banner.vue.d.ts.map +1 -1
  147. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts +0 -15
  148. package/dist/ui/components/atoms/vc-button/vc-button.vue.d.ts.map +1 -1
  149. package/dist/ui/components/atoms/vc-container/vc-container.vue.d.ts.map +1 -1
  150. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
  151. package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
  152. package/dist/ui/components/atoms/vc-image/vc-image.vue.d.ts.map +1 -1
  153. package/dist/ui/components/atoms/vc-link/vc-link.vue.d.ts.map +1 -1
  154. package/dist/ui/components/atoms/vc-loading/vc-loading.vue.d.ts.map +1 -1
  155. package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts +0 -5
  156. package/dist/ui/components/atoms/vc-status/vc-status.vue.d.ts.map +1 -1
  157. package/dist/ui/components/atoms/vc-tooltip/vc-tooltip.vue.d.ts.map +1 -1
  158. package/dist/ui/components/atoms/vc-video/vc-video.vue.d.ts.map +1 -1
  159. package/dist/ui/components/atoms/vc-widget/vc-widget.vue.d.ts.map +1 -1
  160. package/dist/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue.d.ts.map +1 -1
  161. package/dist/ui/components/molecules/vc-input/vc-input.vue.d.ts.map +1 -1
  162. package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts.map +1 -1
  163. package/dist/ui/components/molecules/vc-toast/vc-toast.vue.d.ts.map +1 -1
  164. package/dist/ui/components/organisms/vc-app/vc-app.vue.d.ts.map +1 -1
  165. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue.d.ts.map +1 -1
  166. package/dist/ui/components/organisms/vc-blade/vc-blade.vue.d.ts.map +1 -1
  167. package/dist/ui/components/organisms/vc-login-form/vc-login-form.vue.d.ts.map +1 -1
  168. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
  169. package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts.map +1 -1
  170. package/dist/ui/components/organisms/vc-table/composables/useTableColumnResize.d.ts.map +1 -1
  171. package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts.map +1 -1
  172. package/dist/ui/components/organisms/vc-table/composables/useTableSelection.d.ts.map +1 -1
  173. package/dist/ui/components/organisms/vc-table/composables/useTableState.d.ts.map +1 -1
  174. package/dist/{vendor-lodash-es-BqkGj3Jl.js → vendor-lodash-es-SgOIjJF8.js} +2 -0
  175. package/package.json +5 -5
  176. package/shared/components/app-switcher/composables/useAppSwitcher/index.ts +4 -1
  177. package/shared/components/blade-navigation/components/vc-blade-navigation/vc-blade-navigation.vue +67 -4
  178. package/shared/components/blade-navigation/composables/useBladeNavigation/index.ts +13 -10
  179. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeActions.ts +7 -4
  180. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/bladeRouteResolver.ts +4 -1
  181. package/shared/components/blade-navigation/composables/useBladeNavigation/internal/routerUtils.ts +4 -1
  182. package/shared/components/change-password/change-password.vue +1 -1
  183. package/shared/components/draggable-dashboard/composables/useDashboardDragAndDrop.ts +14 -5
  184. package/shared/components/draggable-dashboard/composables/useLayoutPersistence.ts +5 -2
  185. package/shared/components/index.ts +2 -0
  186. package/shared/components/notifications/composables/useContainer/index.ts +8 -6
  187. package/shared/components/notifications/composables/useInstance/index.ts +4 -1
  188. package/shared/components/notifications/core/notification.ts +10 -7
  189. package/shared/components/popup-handler/components/vc-popup-container/vc-popup-container.vue +20 -1
  190. package/shared/components/sign-in/useExternalProvider.ts +6 -4
  191. package/shared/composables/index.ts +1 -0
  192. package/shared/composables/useExternalWidgets.ts +7 -4
  193. package/shared/composables/useMenuExpanded.ts +15 -1
  194. package/shared/composables/useTableSelection.ts +151 -0
  195. package/shared/composables/useTableSort.ts +4 -4
  196. package/shared/modules/assets-manager/components/assets-manager/assets-manager.vue +6 -3
  197. package/shared/pages/LoginPage/components/login/Login.vue +4 -1
  198. package/shared/utilities/colorUtils.ts +5 -12
  199. package/ui/components/atoms/vc-banner/vc-banner.vue +4 -1
  200. package/ui/components/atoms/vc-button/vc-button.vue +2 -25
  201. package/ui/components/atoms/vc-container/vc-container.vue +12 -3
  202. package/ui/components/atoms/vc-icon/vc-icon.vue +0 -10
  203. package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +5 -2
  204. package/ui/components/atoms/vc-image/vc-image.vue +4 -1
  205. package/ui/components/atoms/vc-link/vc-link.vue +59 -54
  206. package/ui/components/atoms/vc-loading/vc-loading.vue +4 -0
  207. package/ui/components/atoms/vc-status/vc-status.vue +0 -5
  208. package/ui/components/atoms/vc-status-icon/vc-status-icon.vue +4 -4
  209. package/ui/components/atoms/vc-tooltip/vc-tooltip.vue +8 -1
  210. package/ui/components/atoms/vc-video/vc-video.vue +4 -2
  211. package/ui/components/atoms/vc-widget/vc-widget.vue +4 -1
  212. package/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.vue +7 -2
  213. package/ui/components/molecules/vc-input/vc-input.vue +0 -1
  214. package/ui/components/molecules/vc-pagination/vc-pagination.vue +6 -1
  215. package/ui/components/molecules/vc-rating/vc-rating.vue +1 -1
  216. package/ui/components/molecules/vc-textarea/vc-textarea.vue +1 -1
  217. package/ui/components/molecules/vc-toast/vc-toast.vue +11 -1
  218. package/ui/components/organisms/vc-app/vc-app.vue +22 -3
  219. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-button.vue +4 -1
  220. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/vc-blade-toolbar.vue +14 -14
  221. package/ui/components/organisms/vc-blade/vc-blade.vue +3 -1
  222. package/ui/components/organisms/vc-login-form/vc-login-form.vue +3 -1
  223. package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +34 -2
  224. package/ui/components/organisms/vc-table/composables/useTableActions.ts +7 -10
  225. package/ui/components/organisms/vc-table/composables/useTableColumnResize.ts +4 -1
  226. package/ui/components/organisms/vc-table/composables/useTableRowReorder.ts +5 -2
  227. package/ui/components/organisms/vc-table/composables/useTableSelection.ts +26 -18
  228. package/ui/components/organisms/vc-table/composables/useTableState.ts +4 -1
  229. package/core/services/global-search-service.ts +0 -36
  230. package/dist/core/services/global-search-service.d.ts +0 -10
  231. package/dist/core/services/global-search-service.d.ts.map +0 -1
@@ -0,0 +1,280 @@
1
+ import { inject, ref, computed, watch, onUnmounted, type Ref, type ComputedRef } from "vue";
2
+ import { mergeWith, isPlainObject } from "lodash-es";
3
+ import { AiAgentServiceKey, BladeInstanceKey } from "../../../../injection-keys";
4
+ import type { IAiAgentServiceInternal } from "../services/ai-agent-service";
5
+ import type {
6
+ ISuggestion,
7
+ UseAiAgentContextOptions,
8
+ UseAiAgentContextReturn,
9
+ IPreviewChangesPayload,
10
+ AiAgentContextType,
11
+ } from "../types";
12
+ import { createLogger } from "../../../utilities";
13
+
14
+ const logger = createLogger("use-ai-agent-context");
15
+
16
+ /**
17
+ * Custom merge function for AI agent preview changes.
18
+ * Handles sparse arrays where null means "skip this index".
19
+ *
20
+ * @example
21
+ * // Nested objects - deep merge
22
+ * deepMergeChanges({seo: {title: "Old", desc: "Desc"}}, {seo: {title: "New"}})
23
+ * // → {seo: {title: "New", desc: "Desc"}}
24
+ *
25
+ * @example
26
+ * // Sparse arrays - null skips index
27
+ * deepMergeChanges({items: [{a:1}, {b:2}]}, {items: [null, {c:3}]})
28
+ * // → {items: [{a:1}, {b:2, c:3}]}
29
+ */
30
+ function deepMergeChanges<T extends object>(target: T, source: object): T {
31
+ const customizer = (targetVal: unknown, sourceVal: unknown): unknown => {
32
+ // If source value is null/undefined, keep target value (skip this index/field)
33
+ if (sourceVal === null || sourceVal === undefined) {
34
+ return targetVal;
35
+ }
36
+
37
+ // If both are arrays, merge by index with sparse array support
38
+ if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {
39
+ const result = [...targetVal];
40
+ sourceVal.forEach((item, index) => {
41
+ if (item !== null && item !== undefined) {
42
+ if (isPlainObject(item) && isPlainObject(result[index])) {
43
+ // Recursively merge objects in array
44
+ result[index] = deepMergeChanges(result[index] as object, item);
45
+ } else {
46
+ // Replace primitive or non-object values
47
+ result[index] = item;
48
+ }
49
+ }
50
+ // null/undefined in source array = skip this index
51
+ });
52
+ return result;
53
+ }
54
+
55
+ // For objects, let mergeWith handle recursively with this customizer
56
+ return undefined;
57
+ };
58
+
59
+ return mergeWith({}, target, source, customizer);
60
+ }
61
+
62
+ /**
63
+ * Checks if the ref value is an array
64
+ */
65
+ function isArrayRef<T>(dataRef: Ref<T> | Ref<T[]>): dataRef is Ref<T[]> {
66
+ return Array.isArray(dataRef.value);
67
+ }
68
+
69
+ /**
70
+ * Normalizes any ref value to an array for sending to the AI agent
71
+ */
72
+ function normalizeToArray<T>(value: T | T[]): T[] {
73
+ if (Array.isArray(value)) {
74
+ return value;
75
+ }
76
+ return value != null ? [value] : [];
77
+ }
78
+
79
+ /**
80
+ * Gets the target object for applying changes based on ref type
81
+ */
82
+ function getTargetForChanges<T>(dataRef: Ref<T> | Ref<T[]>): T | undefined {
83
+ if (isArrayRef(dataRef)) {
84
+ // Array ref - return first item
85
+ return dataRef.value[0];
86
+ }
87
+ // Single object ref - return the object directly
88
+ return dataRef.value;
89
+ }
90
+
91
+ /**
92
+ * Composable for binding blade data to AI agent context.
93
+ *
94
+ * This composable automatically:
95
+ * - Sends data updates to the AI agent when dataRef changes
96
+ * - Normalizes single objects to arrays for the AI agent
97
+ * - Handles PREVIEW_CHANGES messages to update form data
98
+ * - Provides preview state for visual feedback
99
+ *
100
+ * @example List blade (array of selected items)
101
+ * ```typescript
102
+ * const { selectedItems } = useTableSelection<Offer>();
103
+ *
104
+ * useAiAgentContext({ dataRef: selectedItems });
105
+ * ```
106
+ *
107
+ * @example Details blade (single object - automatically wrapped in array)
108
+ * ```typescript
109
+ * const offer = ref<Offer>({});
110
+ *
111
+ * // Just pass the ref directly - no need to wrap in array!
112
+ * const { previewState } = useAiAgentContext({ dataRef: offer });
113
+ *
114
+ * // Use previewState.isActive to show preview indicator
115
+ * ```
116
+ *
117
+ * @example With custom suggestions
118
+ * ```typescript
119
+ * useAiAgentContext({
120
+ * dataRef: offer,
121
+ * suggestions: [
122
+ * {
123
+ * id: "translate",
124
+ * title: "Translate description",
125
+ * icon: "translation",
126
+ * iconColor: "#FF4A4A",
127
+ * prompt: "Translate the offer description to English"
128
+ * },
129
+ * ],
130
+ * });
131
+ * ```
132
+ */
133
+ export function useAiAgentContext<T extends { id: string; objectType: string; name: string; [key: string]: unknown }>(
134
+ options: UseAiAgentContextOptions<T>,
135
+ ): UseAiAgentContextReturn {
136
+ const { dataRef, suggestions } = options;
137
+
138
+ // Try to get the service (may not be available if plugin not installed)
139
+ const service = inject(AiAgentServiceKey) as IAiAgentServiceInternal | undefined;
140
+
141
+ // Get current blade instance to identify which blade this context belongs to
142
+ const bladeInstance = inject(BladeInstanceKey, null);
143
+ const bladeId = computed(() => bladeInstance?.value?.id);
144
+
145
+ // Preview state
146
+ const isPreviewActive = ref(false);
147
+ const changedFieldsList = ref<string[]>([]);
148
+
149
+ // If service is not available, return dummy preview state
150
+ if (!service) {
151
+ logger.debug("AiAgentService not available, context binding disabled");
152
+ return {
153
+ previewState: {
154
+ isActive: computed(() => false),
155
+ changedFields: computed(() => []),
156
+ },
157
+ };
158
+ }
159
+
160
+ // Determine context type based on dataRef type
161
+ // Array ref = list blade (multiple selected items)
162
+ // Single object ref = details blade (single item being edited)
163
+ const detectedContextType: AiAgentContextType = isArrayRef(dataRef) ? "list" : "details";
164
+
165
+ // Set context data in service (items, contextType, and suggestions)
166
+ // Always sends an array to the service, normalizing single objects
167
+ // Context is bound to specific blade ID
168
+ const updateContextData = () => {
169
+ const items = normalizeToArray(dataRef.value).map((item) => ({
170
+ id: item.id,
171
+ objectType: item.objectType,
172
+ name: item.name,
173
+ }));
174
+ service._setContextData(items, detectedContextType, suggestions, bladeId.value);
175
+ console.log(
176
+ `[USE-AI-AGENT-CONTEXT] Context updated: ${items.length} items, type: ${detectedContextType}, blade: ${bladeId.value}`,
177
+ );
178
+ };
179
+
180
+ // Log that the handler is being registered
181
+ console.log("[USE-AI-AGENT-CONTEXT] Registering PREVIEW_CHANGES handler for blade:", bladeId.value);
182
+
183
+ // Watch dataRef for changes and update context
184
+ const stopWatch = watch(
185
+ dataRef,
186
+ () => {
187
+ updateContextData();
188
+ // Clear preview state when data changes from outside
189
+ if (isPreviewActive.value) {
190
+ isPreviewActive.value = false;
191
+ changedFieldsList.value = [];
192
+ }
193
+ },
194
+ { deep: true, immediate: true },
195
+ );
196
+
197
+ // Handle PREVIEW_CHANGES messages
198
+ // Applies changes to the target object (single ref or first item in array)
199
+ const unsubscribe = service._onPreviewChanges((payload: IPreviewChangesPayload) => {
200
+ console.log("[USE-AI-AGENT-CONTEXT] PREVIEW_CHANGES handler called", {
201
+ bladeId: bladeId.value,
202
+ payloadKeys: Object.keys(payload.data || {}),
203
+ changedFields: payload.changedFields,
204
+ hasDataRef: !!dataRef,
205
+ dataRefValue: dataRef?.value ? "present" : "empty",
206
+ });
207
+
208
+ const target = getTargetForChanges(dataRef);
209
+ if (!target) {
210
+ console.warn("[USE-AI-AGENT-CONTEXT] Cannot apply preview changes: no data in dataRef", {
211
+ bladeId: bladeId.value,
212
+ dataRefValue: dataRef?.value,
213
+ });
214
+ return;
215
+ }
216
+
217
+ const targetObj = target as Record<string, unknown>;
218
+ const updatedData = payload.data;
219
+
220
+ console.log("[USE-AI-AGENT-CONTEXT] Applying preview changes", {
221
+ bladeId: bladeId.value,
222
+ targetObjKeys: Object.keys(targetObj),
223
+ updatedDataKeys: Object.keys(updatedData),
224
+ updatedDataPreview: JSON.stringify(updatedData).substring(0, 500),
225
+ });
226
+
227
+ // Deep merge changes into target object
228
+ // Supports:
229
+ // - Nested objects: {"seo": {"metaTitle": "New"}} merges into existing seo
230
+ // - Sparse arrays: [null, {"price": 50}] updates index 1 only (null = skip)
231
+ const mergedResult = deepMergeChanges(targetObj, updatedData);
232
+
233
+ // Copy merged result back to target object (to trigger Vue reactivity)
234
+ Object.keys(mergedResult).forEach((key) => {
235
+ targetObj[key] = mergedResult[key as keyof typeof mergedResult];
236
+ });
237
+
238
+ console.log("[USE-AI-AGENT-CONTEXT] Deep merge completed", {
239
+ bladeId: bladeId.value,
240
+ resultPreview: JSON.stringify(targetObj).substring(0, 500),
241
+ });
242
+
243
+ // Update preview state
244
+ isPreviewActive.value = true;
245
+ changedFieldsList.value = payload.changedFields || Object.keys(updatedData);
246
+
247
+ console.log("[USE-AI-AGENT-CONTEXT] Preview changes applied successfully", {
248
+ bladeId: bladeId.value,
249
+ changedFields: changedFieldsList.value,
250
+ isPreviewActive: isPreviewActive.value,
251
+ targetObjAfter: JSON.stringify(targetObj).substring(0, 500),
252
+ });
253
+ });
254
+
255
+ // Cleanup on unmount
256
+ onUnmounted(() => {
257
+ stopWatch();
258
+ unsubscribe();
259
+ // Clear context for this specific blade when component unmounts
260
+ service._setContextData([], "list", undefined, bladeId.value);
261
+ logger.debug(`Context cleared on unmount for blade: ${bladeId.value}`);
262
+ });
263
+
264
+ return {
265
+ previewState: {
266
+ isActive: computed(() => isPreviewActive.value),
267
+ changedFields: computed(() => changedFieldsList.value),
268
+ },
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Clears the preview state manually.
274
+ * Useful when user saves or discards changes.
275
+ */
276
+ export function clearPreviewState(previewState: UseAiAgentContextReturn["previewState"]): void {
277
+ // This is a helper for external clearing if needed
278
+ // The actual state is cleared when dataRef changes
279
+ logger.debug("Preview state cleared manually");
280
+ }
@@ -0,0 +1,89 @@
1
+ import type { IAiAgentConfig, ISuggestion } from "./types";
2
+
3
+ /**
4
+ * Default configuration for AI agent panel
5
+ */
6
+ export const DEFAULT_AI_AGENT_CONFIG: IAiAgentConfig = {
7
+ url: "",
8
+ title: "Virto OZ",
9
+ width: 350,
10
+ expandedWidth: 500,
11
+ allowedOrigins: ["*"],
12
+ };
13
+
14
+ /**
15
+ * Environment variable name for AI agent URL
16
+ */
17
+ export const AI_AGENT_URL_ENV_KEY = "APP_AI_AGENT_URL";
18
+
19
+ /**
20
+ * Message types for Shell -> Chat communication
21
+ */
22
+ export const SHELL_TO_CHAT_MESSAGE_TYPES = {
23
+ INIT_CONTEXT: "INIT_CONTEXT",
24
+ UPDATE_CONTEXT: "UPDATE_CONTEXT",
25
+ } as const;
26
+
27
+ /**
28
+ * Message types for Chat -> Shell communication
29
+ */
30
+ export const CHAT_TO_SHELL_MESSAGE_TYPES = {
31
+ CHAT_READY: "CHAT_READY",
32
+ NAVIGATE_TO_APP: "NAVIGATE_TO_APP",
33
+ EXPAND_IN_CHAT: "EXPAND_IN_CHAT",
34
+ RELOAD_BLADE: "RELOAD_BLADE",
35
+ PREVIEW_CHANGES: "PREVIEW_CHANGES",
36
+ APPLY_CHANGES: "APPLY_CHANGES",
37
+ DOWNLOAD_FILE: "DOWNLOAD_FILE",
38
+ SHOW_MORE: "SHOW_MORE",
39
+ CHAT_ERROR: "CHAT_ERROR",
40
+ } as const;
41
+
42
+ /**
43
+ * Default suggestions when no custom suggestions provided
44
+ */
45
+ export const DEFAULT_SUGGESTIONS: ISuggestion[] = [
46
+ {
47
+ id: "generate-report",
48
+ title: "Generate a report",
49
+ icon: "analytics-01",
50
+ iconColor: "#57AB79",
51
+ prompt: "Generate a report",
52
+ },
53
+ {
54
+ id: "find-sales",
55
+ title: "Find sales statistics",
56
+ icon: "progress-02",
57
+ iconColor: "#FFBA35",
58
+ prompt: "Find sales statistics",
59
+ },
60
+ {
61
+ id: "translate",
62
+ title: "Translate description",
63
+ icon: "translation",
64
+ iconColor: "#FF4A4A",
65
+ prompt: "Translate description",
66
+ },
67
+ {
68
+ id: "top-sales",
69
+ title: "Find top sales report",
70
+ icon: "analytics-up",
71
+ iconColor: "#319ED4",
72
+ prompt: "Find top sales report",
73
+ },
74
+ ];
75
+
76
+ /**
77
+ * Default toolbar button ID for AI agent
78
+ */
79
+ export const AI_AGENT_TOOLBAR_BUTTON_ID = "ai-agent-toggle";
80
+
81
+ /**
82
+ * Default toolbar button icon
83
+ */
84
+ export const AI_AGENT_TOOLBAR_BUTTON_ICON = "lucide-sparkles";
85
+
86
+ /**
87
+ * Default toolbar button title
88
+ */
89
+ export const AI_AGENT_TOOLBAR_BUTTON_TITLE = "AI Assistant";
@@ -0,0 +1,91 @@
1
+ import type { App } from "vue";
2
+ import type { IAiAgentConfig } from "./types";
3
+ import { DEFAULT_AI_AGENT_CONFIG, AI_AGENT_URL_ENV_KEY } from "./constants";
4
+ import { createLogger } from "../../utilities";
5
+
6
+ const logger = createLogger("ai-agent-plugin");
7
+
8
+ /**
9
+ * Options for the AI Agent Plugin
10
+ */
11
+ export interface AiAgentPluginOptions {
12
+ /**
13
+ * AI Agent configuration.
14
+ * URL can also be set via APP_AI_AGENT_URL environment variable.
15
+ */
16
+ config?: Partial<IAiAgentConfig>;
17
+
18
+ /**
19
+ * Whether to add the AI button to all blade toolbars automatically.
20
+ * Default: true
21
+ */
22
+ addGlobalToolbarButton?: boolean;
23
+ }
24
+
25
+ /**
26
+ * Vue plugin for AI Agent integration.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * import { createApp } from "vue";
31
+ * import { aiAgentPlugin } from "@vc-shell/framework";
32
+ *
33
+ * const app = createApp(App);
34
+ *
35
+ * // Install with options
36
+ * app.use(aiAgentPlugin, {
37
+ * config: {
38
+ * title: "AI Assistant",
39
+ * width: 400,
40
+ * },
41
+ * addGlobalToolbarButton: true,
42
+ * });
43
+ * ```
44
+ */
45
+ export const aiAgentPlugin = {
46
+ install(app: App, options: AiAgentPluginOptions = {}) {
47
+ const { config = {}, addGlobalToolbarButton = true } = options;
48
+
49
+ // Get URL from environment variable if not provided
50
+ let url = config.url || "";
51
+ if (!url && typeof import.meta !== "undefined" && import.meta.env) {
52
+ url = import.meta.env[AI_AGENT_URL_ENV_KEY] || "";
53
+ }
54
+
55
+ // Skip installation if no URL configured
56
+ if (!url) {
57
+ logger.info("AI Agent plugin skipped: no URL configured. Set APP_AI_AGENT_URL env variable or pass config.url option.");
58
+ return;
59
+ }
60
+
61
+ // Merge config with defaults
62
+ const finalConfig: IAiAgentConfig = {
63
+ ...DEFAULT_AI_AGENT_CONFIG,
64
+ ...config,
65
+ url,
66
+ };
67
+
68
+ // Store config in app global properties for access during service creation
69
+ app.config.globalProperties.$aiAgentConfig = finalConfig;
70
+ app.provide("aiAgentConfig", finalConfig);
71
+ app.provide("aiAgentAddGlobalToolbarButton", addGlobalToolbarButton);
72
+
73
+ logger.info(`AI Agent plugin installed. URL: ${url}, addGlobalToolbarButton: ${addGlobalToolbarButton}`);
74
+ },
75
+ };
76
+
77
+ // Re-export all types
78
+ export * from "./types";
79
+ export * from "./constants";
80
+
81
+ // Re-export composables
82
+ export { useAiAgent, provideAiAgentService, createAiAgentToolbarButton } from "./composables/useAiAgent";
83
+ export type { UseAiAgentReturn, ProvideAiAgentServiceOptions } from "./composables/useAiAgent";
84
+
85
+ export { useAiAgentContext, clearPreviewState } from "./composables/useAiAgentContext";
86
+
87
+ // Re-export components
88
+ export { VcAiAgentPanel } from "./components";
89
+
90
+ // Re-export service types
91
+ export type { IAiAgentServiceInternal, CreateAiAgentServiceOptions } from "./services/ai-agent-service";