@decido/shell 1.0.0 โ†’ 4.0.2

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 (209) hide show
  1. package/README.md +31 -0
  2. package/package.json +27 -18
  3. package/.turbo/turbo-build.log +0 -13
  4. package/src/AgentPlayer.tsx +0 -105
  5. package/src/DecidoPlayer.tsx +0 -117
  6. package/src/bridge/BridgeAgent.ts +0 -443
  7. package/src/components/DecidoIcon.tsx +0 -56
  8. package/src/components/JsonTreeEditor.tsx +0 -117
  9. package/src/components/PanelSplitter.tsx +0 -71
  10. package/src/components/PluginErrorBoundary.tsx +0 -69
  11. package/src/components/SafeLiquidUI.tsx +0 -114
  12. package/src/components/TransientLayer.tsx +0 -92
  13. package/src/components/agent/AgentChat.tsx +0 -134
  14. package/src/components/chat-extensions/IntentCatalogPanel.tsx +0 -81
  15. package/src/components/chat-extensions/chatSlashCommands.ts +0 -101
  16. package/src/components/controls/CreatorInputBar.tsx +0 -144
  17. package/src/components/controls/OSToolbar.tsx +0 -90
  18. package/src/components/controls/TimelineTape.tsx +0 -43
  19. package/src/components/debug/ActionTimelineTab.tsx +0 -111
  20. package/src/components/debug/CSSInspectorTab.tsx +0 -436
  21. package/src/components/debug/ExportTab.tsx +0 -192
  22. package/src/components/debug/FlowHealthTab.tsx +0 -86
  23. package/src/components/debug/LogsTab.tsx +0 -110
  24. package/src/components/debug/MorphStackTab.tsx +0 -241
  25. package/src/components/debug/NetworkTab.tsx +0 -173
  26. package/src/components/debug/PerformanceTab.tsx +0 -171
  27. package/src/components/debug/ProfilesTab.tsx +0 -238
  28. package/src/components/debug/ReplayTab.tsx +0 -70
  29. package/src/components/debug/StoresTab.tsx +0 -255
  30. package/src/components/debug/TopologyTab.tsx +0 -59
  31. package/src/components/debug/debugConfig.tsx +0 -66
  32. package/src/components/playground/DebugPanel.tsx +0 -112
  33. package/src/components/playground/HeaderCenterControls.tsx +0 -92
  34. package/src/components/playground/KeyframeListItem.tsx +0 -70
  35. package/src/components/playground/PlaygroundAppSidebar.tsx +0 -171
  36. package/src/components/playground/PlaygroundBottomControls.tsx +0 -132
  37. package/src/components/playground/PlaygroundCanvas.tsx +0 -87
  38. package/src/components/playground/PlaygroundChat.tsx +0 -236
  39. package/src/components/playground/PlaygroundErrorBoundary.tsx +0 -63
  40. package/src/components/playground/PlaygroundFloatingInput.tsx +0 -352
  41. package/src/components/playground/PlaygroundHeader.tsx +0 -222
  42. package/src/components/playground/PlaygroundSidebar.tsx +0 -136
  43. package/src/components/playground/PlaygroundTerminal.tsx +0 -44
  44. package/src/components/playground/SuggestionCards.tsx +0 -29
  45. package/src/components/playground/demos/ClinicaAINode.tsx +0 -221
  46. package/src/components/playground/demos/FinanceAINode.tsx +0 -226
  47. package/src/components/playground/demos/KiaAcademyNode.tsx +0 -250
  48. package/src/components/playground/demos/KiaBotNode.tsx +0 -207
  49. package/src/components/playground/demos/KiaCampaignNode.tsx +0 -191
  50. package/src/components/playground/demos/KiaComplianceNode.tsx +0 -140
  51. package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +0 -220
  52. package/src/components/playground/demos/KiaCyberNode.tsx +0 -203
  53. package/src/components/playground/demos/KiaDashboardNode.tsx +0 -399
  54. package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +0 -168
  55. package/src/components/playground/demos/KiaExecutiveNode.tsx +0 -169
  56. package/src/components/playground/demos/KiaGamificationNode.tsx +0 -229
  57. package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +0 -165
  58. package/src/components/playground/demos/KiaInventoryNode.tsx +0 -183
  59. package/src/components/playground/demos/KiaLeadScoringNode.tsx +0 -226
  60. package/src/components/playground/demos/KiaLiveSimulationNode.tsx +0 -177
  61. package/src/components/playground/demos/KiaMultiDealerNode.tsx +0 -223
  62. package/src/components/playground/demos/KiaNPSVoiceNode.tsx +0 -214
  63. package/src/components/playground/demos/KiaOmnichannelNode.tsx +0 -162
  64. package/src/components/playground/demos/KiaPBIBudgetNode.tsx +0 -152
  65. package/src/components/playground/demos/KiaPBIConversionNode.tsx +0 -206
  66. package/src/components/playground/demos/KiaPBIFunnelNode.tsx +0 -184
  67. package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +0 -113
  68. package/src/components/playground/demos/KiaPBIPartnerNode.tsx +0 -143
  69. package/src/components/playground/demos/KiaPBIPreciosNode.tsx +0 -120
  70. package/src/components/playground/demos/KiaPBIRuntNode.tsx +0 -205
  71. package/src/components/playground/demos/KiaPartnerScoreNode.tsx +0 -206
  72. package/src/components/playground/demos/KiaPredictiveNode.tsx +0 -226
  73. package/src/components/playground/demos/KiaShowroomNode.tsx +0 -194
  74. package/src/components/playground/demos/KiaStoreNode.tsx +0 -215
  75. package/src/components/playground/demos/KiaSustainabilityNode.tsx +0 -173
  76. package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +0 -163
  77. package/src/components/playground/demos/KiaWorkshopNode.tsx +0 -221
  78. package/src/components/playground/demos/SmartCityNode.tsx +0 -205
  79. package/src/components/playground/demos/kia_campaign_manifest.json +0 -112
  80. package/src/components/playground/input-parts/AIModelSelector.tsx +0 -156
  81. package/src/components/playground/input-parts/InputActions.tsx +0 -80
  82. package/src/components/playground/input-parts/InputToolbar.tsx +0 -245
  83. package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +0 -287
  84. package/src/components/playground/sidebarDsdIO.ts +0 -82
  85. package/src/components/settings/SettingsPanel.tsx +0 -267
  86. package/src/components/shell/AppHeader.tsx +0 -9
  87. package/src/components/shell/AppShell.tsx +0 -139
  88. package/src/components/shell/ArtifactBar.tsx +0 -97
  89. package/src/components/shell/BootScreen.tsx +0 -19
  90. package/src/components/shell/CenterComposite.tsx +0 -87
  91. package/src/components/shell/CodeEditorPanel.tsx +0 -88
  92. package/src/components/shell/GlobalOverlays.tsx +0 -228
  93. package/src/components/shell/LayoutConfigurator.tsx +0 -209
  94. package/src/components/shell/LayoutGrid.tsx +0 -178
  95. package/src/components/shell/MorphShell.tsx +0 -368
  96. package/src/components/shell/PluginViewer.tsx +0 -147
  97. package/src/components/shell/ShellNexusPreview.tsx +0 -458
  98. package/src/components/shell/SlotRenderer.tsx +0 -115
  99. package/src/components/shell/TabBar.tsx +0 -94
  100. package/src/components/shell/TemplateLibrary.tsx +0 -195
  101. package/src/components/shell/layoutConstants.ts +0 -35
  102. package/src/components/shell/morphStageMeta.ts +0 -15
  103. package/src/components/shell/shells/BuiltInShells.tsx +0 -443
  104. package/src/components/shell/shells/DatawayChatShell.tsx +0 -42
  105. package/src/components/shell/shells/TokenPreview.tsx +0 -339
  106. package/src/components/shell/shells/bootShells.ts +0 -31
  107. package/src/components/shells/CreatorShell.tsx +0 -37
  108. package/src/components/shells/DecidoShell.tsx +0 -447
  109. package/src/components/shells/ExperimentalChatShell.tsx +0 -245
  110. package/src/components/shells/UserCanvas.tsx +0 -44
  111. package/src/components/studio/BlueprintManagerPanel.tsx +0 -137
  112. package/src/components/studio/DependencyTreePanel.tsx +0 -192
  113. package/src/components/studio/NodePalette.tsx +0 -92
  114. package/src/components/studio/NodePropertiesPanel.tsx +0 -81
  115. package/src/components/studio/ReactFlowEditor.tsx +0 -242
  116. package/src/components/studio/TimelineEditor.tsx +0 -122
  117. package/src/components/studio/TimelineKeyframeCard.tsx +0 -99
  118. package/src/components/studio/VariablePanel.tsx +0 -181
  119. package/src/components/studio/blueprint/BlueprintCard.tsx +0 -82
  120. package/src/components/studio/editor/CanvasContextMenu.tsx +0 -107
  121. package/src/components/studio/editor/EditorToolbar.tsx +0 -80
  122. package/src/components/studio/editor/StageContentRenderer.tsx +0 -134
  123. package/src/components/studio/editor/TrackPropertyEditors.tsx +0 -133
  124. package/src/components/studio/editor/TreeNodeItem.tsx +0 -91
  125. package/src/components/studio/editor/edgeStyles.ts +0 -43
  126. package/src/components/studio/editor/editorKeyHandler.ts +0 -95
  127. package/src/components/studio/editor/nodeTypeRegistry.ts +0 -137
  128. package/src/components/studio/editor/paletteCatalog.tsx +0 -84
  129. package/src/components/studio/nodes/shell/InteractionNodes.tsx +0 -82
  130. package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +0 -69
  131. package/src/components/studio/nodes/shell/RegisterActionNode.tsx +0 -20
  132. package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +0 -22
  133. package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +0 -19
  134. package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +0 -19
  135. package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +0 -22
  136. package/src/components/studio/nodes/shell/RegisterTabNode.tsx +0 -21
  137. package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +0 -22
  138. package/src/components/studio/nodes/shell/ShellConfigNode.tsx +0 -51
  139. package/src/components/studio/nodes/shell/ShellNodeBase.tsx +0 -100
  140. package/src/components/studio/nodes/shell/ThemeNodes.tsx +0 -51
  141. package/src/components/studio/nodes/shell/index.ts +0 -12
  142. package/src/components/widgets/BroadcastWidget.tsx +0 -93
  143. package/src/components/widgets/MarketplaceWidget.tsx +0 -298
  144. package/src/components/widgets/McpToolsWidget.tsx +0 -231
  145. package/src/components/widgets/OpsDashboard.tsx +0 -59
  146. package/src/components/widgets/QuickActionsWidget.tsx +0 -60
  147. package/src/components/widgets/UsageWidget.tsx +0 -112
  148. package/src/components/widgets/WidgetRenderer.tsx +0 -892
  149. package/src/components/widgets/WidgetSlotPanel.tsx +0 -213
  150. package/src/config/IconRegistry.ts +0 -126
  151. package/src/contexts/NetworkProvider.tsx +0 -162
  152. package/src/core/AIDirector.ts +0 -71
  153. package/src/core/EventBus.ts +0 -37
  154. package/src/core/PluginContext.tsx +0 -141
  155. package/src/hooks/listeners/useUIStateListener.ts +0 -59
  156. package/src/hooks/listeners/useWhatsAppListener.ts +0 -110
  157. package/src/hooks/morphBridge.ts +0 -82
  158. package/src/hooks/useAIModelSelector.ts +0 -144
  159. package/src/hooks/useAgentStream.ts +0 -220
  160. package/src/hooks/useAutoUpdater.ts +0 -89
  161. package/src/hooks/useBootSequence.ts +0 -20
  162. package/src/hooks/useExportDSD.ts +0 -53
  163. package/src/hooks/useFullscreen.ts +0 -35
  164. package/src/hooks/useGeminiStream.ts +0 -282
  165. package/src/hooks/useIntentLens.ts +0 -224
  166. package/src/hooks/useKeyboardShortcuts.ts +0 -69
  167. package/src/hooks/useLoggerBridge.ts +0 -32
  168. package/src/hooks/useMcpClient.ts +0 -112
  169. package/src/hooks/useNexusaiDeploy.ts +0 -118
  170. package/src/hooks/usePlaybackEngine.ts +0 -21
  171. package/src/hooks/usePlaygroundCommander.ts +0 -475
  172. package/src/hooks/usePluginEngine.ts +0 -165
  173. package/src/hooks/useScreenRecorder.ts +0 -73
  174. package/src/hooks/useShellKeyboard.ts +0 -40
  175. package/src/hooks/useShellShortcuts.ts +0 -118
  176. package/src/hooks/useSoundEffects.ts +0 -35
  177. package/src/hooks/useStudioConfig.ts +0 -72
  178. package/src/hooks/useSystemBoot.ts +0 -84
  179. package/src/hooks/useSystemTelemetry.ts +0 -62
  180. package/src/index.ts +0 -97
  181. package/src/lib/debugLogger.ts +0 -80
  182. package/src/lib/networkInterceptor.ts +0 -100
  183. package/src/mocks/decido.tsx +0 -41
  184. package/src/plugins/pluginAPI.ts +0 -190
  185. package/src/store/McpStore.ts +0 -69
  186. package/src/store/UpdaterStore.ts +0 -60
  187. package/src/store/engine.ts +0 -392
  188. package/src/store/index.ts +0 -4
  189. package/src/store/layoutPresets.ts +0 -66
  190. package/src/store/playgroundTypes.ts +0 -98
  191. package/src/store/useActionTimelineStore.ts +0 -48
  192. package/src/store/useDebugPanelStore.ts +0 -98
  193. package/src/store/useDebugProfileStore.ts +0 -130
  194. package/src/store/useLayoutStore.ts +0 -205
  195. package/src/store/useMorphInstanceStore.ts +0 -289
  196. package/src/store/useMorphologyStore.ts +0 -103
  197. package/src/store/usePlaygroundStore.ts +0 -236
  198. package/src/store/useShellRegistry.ts +0 -123
  199. package/src/store/useSuggestionsStore.ts +0 -57
  200. package/src/store/useThemeStore.ts +0 -399
  201. package/src/store/useUIComponentStore.ts +0 -179
  202. package/src/types/DecidoStoryDefinition.ts +0 -43
  203. package/src/utils/ai/ai-architect.ts +0 -92
  204. package/src/utils/ai/ai-code.ts +0 -187
  205. package/src/utils/ai/ai-core.ts +0 -50
  206. package/src/utils/ai/ai-media.ts +0 -292
  207. package/src/utils/layoutGraph.ts +0 -67
  208. package/tsconfig.json +0 -17
  209. package/tsconfig.tsbuildinfo +0 -1
@@ -1,447 +0,0 @@
1
- import React, { useEffect, useMemo, useCallback } from 'react';
2
- import { PlaygroundHeader } from '../playground/PlaygroundHeader';
3
- import { useTriggerRouter } from '@decido/engine';
4
- import { McpLifecycleManager } from '../../hooks/useMcpClient';
5
- import { PlaygroundAppSidebar, SidebarMenuSection } from '../playground/PlaygroundAppSidebar';
6
- import { usePlaygroundStore } from '../../store/usePlaygroundStore';
7
- import { LayoutGrid } from '../shell/LayoutGrid';
8
- import { useLayoutStore } from '../../store/useLayoutStore';
9
- import { DecidoStudioProps } from '@decido/engine';
10
- import { BootScreen } from '../shell/BootScreen';
11
- import { useLoggerBridge } from '../../hooks/useLoggerBridge';
12
- import { useBootSequence } from '../../hooks/useBootSequence';
13
- import { MorphShell } from '../shell/MorphShell';
14
- import { useStudioConfig } from '../../hooks/useStudioConfig';
15
- import { useUIStateListener } from '../../hooks/listeners/useUIStateListener';
16
- import { useWhatsAppListener } from '../../hooks/listeners/useWhatsAppListener';
17
- import { pluginWidgetStore } from '../widgets/WidgetSlotPanel';
18
- import type { ServerDrivenNode } from '../widgets/WidgetRenderer';
19
- import { useManifestRegistry, registerManifestLoader } from '@decido/plugin-engine';
20
- import { SentinelUiManifest, SENTINEL_IFRAME_URLS } from '../../../../../plugins/engineering/sentinel-ui/manifest';
21
- import { ChameleonPlugin } from '../../../../../plugins/official/chameleon/src';
22
- // โ”€โ”€ Register well-known manifest loaders (dev mode) โ”€โ”€
23
- // In production, manifests are loaded via Module Federation from the plugin's URL.
24
- // In dev, we import them directly and register as well-known loaders.
25
- registerManifestLoader('sentinel-ui', async () => ({
26
- manifest: {
27
- ...SentinelUiManifest,
28
- baseUrl: 'http://localhost:3333',
29
- iframeUrls: {
30
- 'sentinel-telemetry': '/',
31
- 'sentinel-errors': '/errors',
32
- 'sentinel-replays': '/replays',
33
- },
34
- } as any,
35
- iframeUrls: SENTINEL_IFRAME_URLS,
36
- }));
37
-
38
- registerManifestLoader('macia-chameleon-agent', async () => ({
39
- manifest: ChameleonPlugin.manifest as any,
40
- }));
41
-
42
- /**
43
- * PlaygroundDecidoChannel โ€” Thin Orchestrator.
44
- *
45
- * Post-refactor responsibilities:
46
- * 1. Boot gate (BootScreen)
47
- * 2. Global side-effects (logger, triggers, MCP)
48
- * 3. Layout slot sync (creator/player mode โ†’ R3 slot)
49
- * 4. Sidebar desktop (push layout via flex)
50
- * 5. Header + Immersive mode controls
51
- * 6. Delegates center content to CenterComposite
52
- *
53
- * NetworkProvider is provided by AppShell (parent).
54
- */
55
- export default function PlaygroundDecidoChannel({ aiProvider, VoiceWidget, config }: DecidoStudioProps = {}) {
56
- // 1. State selectors
57
- const isBooting = usePlaygroundStore((s) => s.isBooting);
58
- const isSidebarOpen = usePlaygroundStore((s) => s.isSidebarOpen);
59
- const setIsSidebarOpen = usePlaygroundStore((s) => s.setIsSidebarOpen);
60
- const isCreatorMode = usePlaygroundStore((s) => s.isCreatorMode);
61
- const creatorViewMode = usePlaygroundStore((s) => s.creatorViewMode);
62
- const prototypeBrand = usePlaygroundStore((s) => s.prototypeBrand);
63
- const isImmersive = useLayoutStore((s) => s.isImmersive);
64
- const setIsImmersive = useLayoutStore((s) => s.setIsImmersive);
65
-
66
- // 2. Global side-effects
67
- useLoggerBridge();
68
- useBootSequence();
69
- useTriggerRouter();
70
-
71
- // 3. Config (Header modelLabel only)
72
- const { activeConfig } = useStudioConfig(config, prototypeBrand);
73
- const { showCanvas } = useUIStateListener();
74
- useWhatsAppListener();
75
-
76
- // โ”€โ”€ 4b. Registry-driven multi-manifest plugin system โ”€โ”€
77
- // PluginManifestRegistry auto-loads manifests when plugins are installed
78
- // from the Hub and unloads them when removed. Supports Module Federation.
79
-
80
- const allManifests = useManifestRegistry(s => s.manifests);
81
- const manifestLoading = useManifestRegistry(s => s.loading);
82
- const syncWithRegistry = useManifestRegistry(s => s.syncWithRegistry);
83
- const getManifest = useManifestRegistry(s => s.getManifest);
84
-
85
- // โ”€โ”€ Persistence: restore widgets on mount (from any loaded manifest) โ”€โ”€
86
- React.useEffect(() => {
87
- const manifests = Object.values(allManifests);
88
- if (manifests.length === 0) return;
89
-
90
- const restored = pluginWidgetStore.restoreFromPersistence((widgetId: string) => {
91
- // Resolve SDUI schema from ANY loaded manifest
92
- if (widgetId.startsWith('sdui-')) {
93
- const manifestWidgetId = widgetId.replace('sdui-', '');
94
- for (const m of manifests) {
95
- const mw = m.widgets?.find((w: any) => w.id === manifestWidgetId);
96
- if (mw?.schema) return mw.schema as ServerDrivenNode;
97
- }
98
- }
99
- return undefined;
100
- });
101
- if (restored && pluginWidgetStore.size > 0) {
102
- useLayoutStore.getState().setSlot('R3', 'widget-panel');
103
- }
104
- }, [allManifests]);
105
-
106
- /** Open a widget from sidebar click โ€” registry-driven */
107
- const openPluginView = useCallback((pluginId: string, widgetId: string, label: string) => {
108
- const manifest = getManifest(pluginId);
109
- if (!manifest) {
110
- console.warn(`[Plugin] No manifest loaded for ${pluginId}`);
111
- return;
112
- }
113
- console.log(`[Plugin] Opening widgets for ${pluginId}:${widgetId}`);
114
-
115
- // Find widget schema from manifest
116
- const manifestWidget = manifest.widgets?.find((w: any) => w.id === widgetId);
117
-
118
- // Option A: SDUI native widget (from manifest schema)
119
- if (manifestWidget?.schema) {
120
- pluginWidgetStore.register({
121
- id: `sdui-${widgetId}`,
122
- pluginId,
123
- title: `${label} (SDUI)`,
124
- icon: '๐ŸŸข',
125
- slot: 'tab',
126
- schema: manifestWidget.schema as ServerDrivenNode,
127
- order: 1,
128
- });
129
- }
130
-
131
- // Option B: iframe widget (from manifest iframeUrls or baseUrl)
132
- const iframeUrl = manifest.iframeUrls?.[widgetId];
133
- if (iframeUrl !== undefined) {
134
- const fullUrl = iframeUrl.startsWith('http')
135
- ? iframeUrl
136
- : `${manifest.baseUrl || ''}${iframeUrl}`;
137
- pluginWidgetStore.register({
138
- id: `iframe-${widgetId}`,
139
- pluginId,
140
- title: `${label} (iframe)`,
141
- icon: '๐Ÿ”ต',
142
- slot: 'tab',
143
- url: fullUrl,
144
- order: 2,
145
- });
146
- }
147
-
148
- // Option C/D: Native React component
149
- if (manifestWidget?.component) {
150
- pluginWidgetStore.register({
151
- id: `react-${widgetId}`,
152
- pluginId,
153
- title: `${label}`,
154
- icon: 'โšก',
155
- slot: 'tab',
156
- component: manifestWidget.component,
157
- order: 3,
158
- });
159
- }
160
-
161
- if (manifestWidget?.schema) {
162
- pluginWidgetStore.setActive(`sdui-${widgetId}`);
163
- } else if (manifestWidget?.component) {
164
- pluginWidgetStore.setActive(`react-${widgetId}`);
165
- } else {
166
- pluginWidgetStore.setActive(`iframe-${widgetId}`);
167
- }
168
-
169
- useLayoutStore.getState().setSlot('R3', 'widget-panel');
170
- }, [getManifest]);
171
-
172
- // โ”€โ”€ Global Command Listener for SDUI/Chat Intents โ”€โ”€
173
- useEffect(() => {
174
- const handleOpenPlugin = (e: any) => {
175
- const pid = e.detail?.pluginId;
176
- const view = e.detail?.view;
177
- if (pid === 'chameleon') {
178
- // Open the Live Studio plugin widget
179
- // If a specific view was requested, we override the default widget
180
- let targetViewId = e.detail?.viewId;
181
-
182
- if (!targetViewId) {
183
- if (view === 'discovery_admin' || view === 'whatsapp_studio') targetViewId = 'chameleon-discovery-view';
184
- else if (view === 'enterprise_kanban') targetViewId = 'chameleon-kanban-view';
185
- else targetViewId = 'chameleon-discovery-view'; // Fallback
186
- }
187
-
188
- openPluginView('macia-chameleon-agent', targetViewId, view || 'WhatsApp Studio');
189
-
190
- // Keep backwards compatibility for inner chameleon events if needed
191
- if (view) {
192
- setTimeout(() => window.dispatchEvent(new CustomEvent('chameleon:set-view', { detail: { view } })), 100);
193
- }
194
- }
195
- };
196
-
197
- const handleChangeView = (e: any) => {
198
- const view = e.detail?.view?.toLowerCase();
199
- if (!view) return;
200
-
201
- if (view.includes('kanban') || view.includes('producciรณn') || view.includes('produccion')) {
202
- openPluginView('macia-chameleon-agent', 'chameleon-kanban-view', 'Kanban de Producciรณn');
203
- } else if (view.includes('excel') || view.includes('ventas') || view.includes('datos')) {
204
- openPluginView('macia-chameleon-agent', 'chameleon-sheet-view', 'Google Sheets');
205
- } else if (view.includes('chat') || view.includes('whatsapp') || view.includes('studio') || view.includes('discovery')) {
206
- openPluginView('macia-chameleon-agent', 'chameleon-discovery-view', 'WhatsApp Studio');
207
- }
208
- };
209
-
210
- window.addEventListener('studio:open-plugin', handleOpenPlugin);
211
- window.addEventListener('studio:change-view', handleChangeView);
212
-
213
- return () => {
214
- window.removeEventListener('studio:open-plugin', handleOpenPlugin);
215
- window.removeEventListener('studio:change-view', handleChangeView);
216
- };
217
- }, [openPluginView]);
218
-
219
- const readInstalledPlugins = React.useCallback((): { name: string; url: string }[] => {
220
- try {
221
- const v10 = localStorage.getItem('decido-plugin-registry-v10');
222
- const v9 = localStorage.getItem('decido-plugin-registry-v9');
223
- const stored = v10 || v9;
224
- let registry = [];
225
- if (stored) {
226
- const parsed = JSON.parse(stored);
227
- registry = parsed?.state?.registry || [];
228
- }
229
-
230
- const active = registry
231
- .filter((e: any) => e.enabled)
232
- .map((e: any) => ({ name: e.name, url: e.url || '' }));
233
-
234
- // Force inject Chameleon as a pre-installed built-in
235
- if (!active.some((a: any) => a.name === 'macia-chameleon-agent')) {
236
- active.push({ name: 'macia-chameleon-agent', url: '' });
237
- }
238
-
239
- return active;
240
- } catch (err) { console.error('[ManifestRegistry] Error reading plugin registry:', err); }
241
- return [{ name: 'macia-chameleon-agent', url: '' }];
242
- }, []);
243
-
244
- const [installedEntries, setInstalledEntries] = React.useState<{ name: string; url: string }[]>(readInstalledPlugins);
245
-
246
- // Poll for changes in installed plugins
247
- useEffect(() => {
248
- setInstalledEntries(readInstalledPlugins());
249
- const onStorage = () => {
250
- const newEntries = readInstalledPlugins();
251
- setInstalledEntries(prev => {
252
- // Prevent deep re-renders (800ms UI blocks) by bailing out early
253
- // if the active installations array hasn't functionally changed.
254
- if (JSON.stringify(prev) === JSON.stringify(newEntries)) return prev;
255
- return newEntries;
256
- });
257
- };
258
- window.addEventListener('storage', onStorage);
259
- window.addEventListener('focus', onStorage);
260
- const interval = setInterval(onStorage, 5000);
261
- return () => {
262
- window.removeEventListener('storage', onStorage);
263
- window.removeEventListener('focus', onStorage);
264
- clearInterval(interval);
265
- };
266
- }, [readInstalledPlugins]);
267
-
268
- // Sync: when installed plugins change, load/unload manifests
269
- useEffect(() => {
270
- if (installedEntries.length > 0) {
271
- syncWithRegistry(installedEntries);
272
- }
273
- }, [installedEntries, syncWithRegistry]);
274
-
275
- // Build sidebar sections from ALL loaded manifests
276
- const pluginSidebarSections: SidebarMenuSection[] = useMemo(() => {
277
- const sections: SidebarMenuSection[] = [];
278
- const manifests = Object.values(allManifests);
279
-
280
- for (const manifest of manifests) {
281
- // Check if this manifest's plugin is still installed
282
- const isInstalled = installedEntries.some(e =>
283
- e.name === manifest.id || e.name.includes(manifest.id) || manifest.id.includes(e.name)
284
- );
285
- if (!isInstalled) continue;
286
-
287
- if (manifest.sidebarItems?.length) {
288
- // Group by section
289
- const sectionMap = new Map<string, { title: string; items: typeof manifest.sidebarItems }>();
290
- for (const item of manifest.sidebarItems!) {
291
- const key = item.section || 'default';
292
- if (!sectionMap.has(key)) {
293
- sectionMap.set(key, { title: item.sectionTitle || manifest.name, items: [] });
294
- }
295
- sectionMap.get(key)!.items.push(item);
296
- }
297
-
298
- for (const [sectionKey, group] of sectionMap) {
299
- sections.push({
300
- id: `plugin-${manifest.id}-${sectionKey}`,
301
- title: group.title,
302
- collapsible: true,
303
- items: group.items.map(item => ({
304
- id: `${manifest.id}-${item.id}`,
305
- label: item.label,
306
- onClick: () => {
307
- openPluginView(
308
- manifest.id,
309
- item.targetWidget || '',
310
- item.label,
311
- );
312
- },
313
- })),
314
- });
315
- }
316
- } else {
317
- // Plugin with no sidebar items โ€” show a minimal entry
318
- sections.push({
319
- id: `plugin-${manifest.id}`,
320
- title: `๐Ÿงฉ ${manifest.name}`,
321
- collapsible: true,
322
- items: manifest.widgets.map(w => ({
323
- id: `${manifest.id}-${w.id}`,
324
- label: w.name,
325
- onClick: () => openPluginView(manifest.id, w.id, w.name),
326
- })),
327
- });
328
- }
329
- }
330
-
331
- // Loading indicators
332
- for (const loadingId of manifestLoading) {
333
- sections.push({
334
- id: `loading-${loadingId}`,
335
- title: 'โณ Loading...',
336
- collapsible: false,
337
- items: [{ id: 'loading', label: loadingId, onClick: () => {} }],
338
- });
339
- }
340
-
341
- // โ”€โ”€ WASM Plugins Section โ”€โ”€
342
- // Detect Tauri environment and offer WASM plugin controls
343
- if (typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window) {
344
- sections.push({
345
- id: 'wasm-plugins',
346
- title: 'โšก WASM Plugins',
347
- collapsible: true,
348
- items: [
349
- {
350
- id: 'wasm-demo-math',
351
- label: 'demo-math-plugin',
352
- onClick: () => {
353
- // Register a headless widget for the WASM plugin
354
- pluginWidgetStore.register({
355
- id: 'wasm-demo-math',
356
- pluginId: 'wasm-native',
357
- title: 'Demo Math (WASM)',
358
- icon: 'โšก',
359
- slot: 'tab',
360
- scriptUrl: 'wasm://demo-math-plugin/run',
361
- order: 10,
362
- });
363
- pluginWidgetStore.setActive('wasm-demo-math');
364
- useLayoutStore.getState().setSlot('R3', 'widget-panel');
365
- },
366
- },
367
- ],
368
- });
369
- }
370
-
371
- // Fallback for installed plugins with no loaded manifest and no URL
372
- if (sections.length === 0 && installedEntries.length > 0) {
373
- for (const entry of installedEntries) {
374
- if (!entry.url && !allManifests[entry.name]) {
375
- sections.push({
376
- id: `plugin-${entry.name}`,
377
- title: '๐Ÿ”Œ Plugin Instalado',
378
- collapsible: true,
379
- items: [{ id: 'info', label: entry.name.substring(0, 24), onClick: () => {} }],
380
- });
381
- }
382
- }
383
- }
384
-
385
- console.log('[ManifestRegistry] Sidebar sections:', sections.length, sections.map(s => s.title));
386
- return sections;
387
- }, [allManifests, installedEntries, openPluginView, manifestLoading]);
388
-
389
- // 4. Slot sync: mode/canvas โ†’ LayoutGrid R3
390
- // widget-panel is the proper slot for plugins; shell modes take precedence
391
- useEffect(() => {
392
- const layout = useLayoutStore.getState();
393
- const currentSlot = layout.slots?.R3;
394
-
395
- // If widget-panel is active and user opened a plugin, don't overwrite
396
- if (currentSlot === 'widget-panel') return;
397
-
398
- if (isCreatorMode) {
399
- layout.setSlot('R3', creatorViewMode === 'timeline' ? 'timeline-editor' : 'graph-editor');
400
- } else {
401
- layout.setSlot('R3', null);
402
- }
403
- }, [isCreatorMode, creatorViewMode]);
404
-
405
- // โ”€โ”€ Boot Gate โ”€โ”€
406
- if (isBooting) return <BootScreen />;
407
-
408
- return (
409
- <>
410
- <McpLifecycleManager />
411
- <div className="h-full w-full bg-surface-primary flex font-sans relative overflow-hidden text-text-primary">
412
- <div className="absolute inset-0 bg-[url('data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E')] opacity-[0.15] mix-blend-overlay pointer-events-none z-0" />
413
-
414
- {/* Mobile Sidebar Drawer */}
415
- <div className="md:hidden">
416
- <PlaygroundAppSidebar isOpen={isSidebarOpen} onClose={() => setIsSidebarOpen(false)} menuSections={pluginSidebarSections} />
417
- </div>
418
-
419
- <div className="flex-1 flex h-full relative z-20">
420
- {/* Desktop Sidebar (push layout) */}
421
- <div className={`hidden md:flex shrink-0 h-full transition-all duration-300 ease-in-out overflow-hidden bg-surface-secondary ${isSidebarOpen && !isImmersive ? 'w-[280px] min-w-[280px]' : 'w-0 min-w-0'}`}>
422
- <PlaygroundAppSidebar isOpen={isSidebarOpen && !isImmersive} onClose={() => setIsSidebarOpen(false)} menuSections={pluginSidebarSections} />
423
- </div>
424
-
425
- {/* Main Content */}
426
- <div className="flex-1 flex flex-col h-full min-w-0 overflow-hidden relative">
427
- {!isImmersive && <PlaygroundHeader modelLabel={activeConfig?.greetingText || 'yo.decido'} />}
428
-
429
- {isImmersive && (
430
- <button
431
- onClick={() => setIsImmersive(false)}
432
- className="fixed top-3 right-3 z-900 px-3 py-1.5 rounded-full bg-surface-overlay backdrop-blur-md border border-border-default text-[10px] text-text-secondary hover:text-text-primary hover:bg-surface-overlay transition-all opacity-0 hover:opacity-100 focus:opacity-100"
433
- title="Salir de modo inmersivo (โŒ˜โ‡งF)"
434
- >
435
- ESC ยท Salir inmersivo
436
- </button>
437
- )}
438
-
439
- <LayoutGrid slotProps={{ aiProvider, VoiceWidget, config }}>
440
- <MorphShell />
441
- </LayoutGrid>
442
- </div>
443
- </div>
444
- </div>
445
- </>
446
- );
447
- }