@decido/shell 1.0.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 (208) hide show
  1. package/.turbo/turbo-build.log +13 -0
  2. package/package.json +65 -0
  3. package/src/AgentPlayer.tsx +105 -0
  4. package/src/DecidoPlayer.tsx +117 -0
  5. package/src/bridge/BridgeAgent.ts +443 -0
  6. package/src/components/DecidoIcon.tsx +56 -0
  7. package/src/components/JsonTreeEditor.tsx +117 -0
  8. package/src/components/PanelSplitter.tsx +71 -0
  9. package/src/components/PluginErrorBoundary.tsx +69 -0
  10. package/src/components/SafeLiquidUI.tsx +114 -0
  11. package/src/components/TransientLayer.tsx +92 -0
  12. package/src/components/agent/AgentChat.tsx +134 -0
  13. package/src/components/chat-extensions/IntentCatalogPanel.tsx +81 -0
  14. package/src/components/chat-extensions/chatSlashCommands.ts +101 -0
  15. package/src/components/controls/CreatorInputBar.tsx +144 -0
  16. package/src/components/controls/OSToolbar.tsx +90 -0
  17. package/src/components/controls/TimelineTape.tsx +43 -0
  18. package/src/components/debug/ActionTimelineTab.tsx +111 -0
  19. package/src/components/debug/CSSInspectorTab.tsx +436 -0
  20. package/src/components/debug/ExportTab.tsx +192 -0
  21. package/src/components/debug/FlowHealthTab.tsx +86 -0
  22. package/src/components/debug/LogsTab.tsx +110 -0
  23. package/src/components/debug/MorphStackTab.tsx +241 -0
  24. package/src/components/debug/NetworkTab.tsx +173 -0
  25. package/src/components/debug/PerformanceTab.tsx +171 -0
  26. package/src/components/debug/ProfilesTab.tsx +238 -0
  27. package/src/components/debug/ReplayTab.tsx +70 -0
  28. package/src/components/debug/StoresTab.tsx +255 -0
  29. package/src/components/debug/TopologyTab.tsx +59 -0
  30. package/src/components/debug/debugConfig.tsx +66 -0
  31. package/src/components/playground/DebugPanel.tsx +112 -0
  32. package/src/components/playground/HeaderCenterControls.tsx +92 -0
  33. package/src/components/playground/KeyframeListItem.tsx +70 -0
  34. package/src/components/playground/PlaygroundAppSidebar.tsx +171 -0
  35. package/src/components/playground/PlaygroundBottomControls.tsx +132 -0
  36. package/src/components/playground/PlaygroundCanvas.tsx +87 -0
  37. package/src/components/playground/PlaygroundChat.tsx +236 -0
  38. package/src/components/playground/PlaygroundErrorBoundary.tsx +63 -0
  39. package/src/components/playground/PlaygroundFloatingInput.tsx +352 -0
  40. package/src/components/playground/PlaygroundHeader.tsx +222 -0
  41. package/src/components/playground/PlaygroundSidebar.tsx +136 -0
  42. package/src/components/playground/PlaygroundTerminal.tsx +44 -0
  43. package/src/components/playground/SuggestionCards.tsx +29 -0
  44. package/src/components/playground/demos/ClinicaAINode.tsx +221 -0
  45. package/src/components/playground/demos/FinanceAINode.tsx +226 -0
  46. package/src/components/playground/demos/KiaAcademyNode.tsx +250 -0
  47. package/src/components/playground/demos/KiaBotNode.tsx +207 -0
  48. package/src/components/playground/demos/KiaCampaignNode.tsx +191 -0
  49. package/src/components/playground/demos/KiaComplianceNode.tsx +140 -0
  50. package/src/components/playground/demos/KiaCustomerJourneyNode.tsx +220 -0
  51. package/src/components/playground/demos/KiaCyberNode.tsx +203 -0
  52. package/src/components/playground/demos/KiaDashboardNode.tsx +399 -0
  53. package/src/components/playground/demos/KiaEmbudoOverviewNode.tsx +168 -0
  54. package/src/components/playground/demos/KiaExecutiveNode.tsx +169 -0
  55. package/src/components/playground/demos/KiaGamificationNode.tsx +229 -0
  56. package/src/components/playground/demos/KiaIntelligenceHubNode.tsx +165 -0
  57. package/src/components/playground/demos/KiaInventoryNode.tsx +183 -0
  58. package/src/components/playground/demos/KiaLeadScoringNode.tsx +226 -0
  59. package/src/components/playground/demos/KiaLiveSimulationNode.tsx +177 -0
  60. package/src/components/playground/demos/KiaMultiDealerNode.tsx +223 -0
  61. package/src/components/playground/demos/KiaNPSVoiceNode.tsx +214 -0
  62. package/src/components/playground/demos/KiaOmnichannelNode.tsx +162 -0
  63. package/src/components/playground/demos/KiaPBIBudgetNode.tsx +152 -0
  64. package/src/components/playground/demos/KiaPBIConversionNode.tsx +206 -0
  65. package/src/components/playground/demos/KiaPBIFunnelNode.tsx +184 -0
  66. package/src/components/playground/demos/KiaPBIOwnershipNode.tsx +113 -0
  67. package/src/components/playground/demos/KiaPBIPartnerNode.tsx +143 -0
  68. package/src/components/playground/demos/KiaPBIPreciosNode.tsx +120 -0
  69. package/src/components/playground/demos/KiaPBIRuntNode.tsx +205 -0
  70. package/src/components/playground/demos/KiaPartnerScoreNode.tsx +206 -0
  71. package/src/components/playground/demos/KiaPredictiveNode.tsx +226 -0
  72. package/src/components/playground/demos/KiaShowroomNode.tsx +194 -0
  73. package/src/components/playground/demos/KiaStoreNode.tsx +215 -0
  74. package/src/components/playground/demos/KiaSustainabilityNode.tsx +173 -0
  75. package/src/components/playground/demos/KiaUsedVehiclesNode.tsx +163 -0
  76. package/src/components/playground/demos/KiaWorkshopNode.tsx +221 -0
  77. package/src/components/playground/demos/SmartCityNode.tsx +205 -0
  78. package/src/components/playground/demos/kia_campaign_manifest.json +112 -0
  79. package/src/components/playground/input-parts/AIModelSelector.tsx +156 -0
  80. package/src/components/playground/input-parts/InputActions.tsx +80 -0
  81. package/src/components/playground/input-parts/InputToolbar.tsx +245 -0
  82. package/src/components/playground/input-parts/ResourceLibraryPanel.tsx +287 -0
  83. package/src/components/playground/sidebarDsdIO.ts +82 -0
  84. package/src/components/settings/SettingsPanel.tsx +267 -0
  85. package/src/components/shell/AppHeader.tsx +9 -0
  86. package/src/components/shell/AppShell.tsx +139 -0
  87. package/src/components/shell/ArtifactBar.tsx +97 -0
  88. package/src/components/shell/BootScreen.tsx +19 -0
  89. package/src/components/shell/CenterComposite.tsx +87 -0
  90. package/src/components/shell/CodeEditorPanel.tsx +88 -0
  91. package/src/components/shell/GlobalOverlays.tsx +228 -0
  92. package/src/components/shell/LayoutConfigurator.tsx +209 -0
  93. package/src/components/shell/LayoutGrid.tsx +178 -0
  94. package/src/components/shell/MorphShell.tsx +368 -0
  95. package/src/components/shell/PluginViewer.tsx +147 -0
  96. package/src/components/shell/ShellNexusPreview.tsx +458 -0
  97. package/src/components/shell/SlotRenderer.tsx +115 -0
  98. package/src/components/shell/TabBar.tsx +94 -0
  99. package/src/components/shell/TemplateLibrary.tsx +195 -0
  100. package/src/components/shell/layoutConstants.ts +35 -0
  101. package/src/components/shell/morphStageMeta.ts +15 -0
  102. package/src/components/shell/shells/BuiltInShells.tsx +443 -0
  103. package/src/components/shell/shells/DatawayChatShell.tsx +42 -0
  104. package/src/components/shell/shells/TokenPreview.tsx +339 -0
  105. package/src/components/shell/shells/bootShells.ts +31 -0
  106. package/src/components/shells/CreatorShell.tsx +37 -0
  107. package/src/components/shells/DecidoShell.tsx +447 -0
  108. package/src/components/shells/ExperimentalChatShell.tsx +245 -0
  109. package/src/components/shells/UserCanvas.tsx +44 -0
  110. package/src/components/studio/BlueprintManagerPanel.tsx +137 -0
  111. package/src/components/studio/DependencyTreePanel.tsx +192 -0
  112. package/src/components/studio/NodePalette.tsx +92 -0
  113. package/src/components/studio/NodePropertiesPanel.tsx +81 -0
  114. package/src/components/studio/ReactFlowEditor.tsx +242 -0
  115. package/src/components/studio/TimelineEditor.tsx +122 -0
  116. package/src/components/studio/TimelineKeyframeCard.tsx +99 -0
  117. package/src/components/studio/VariablePanel.tsx +181 -0
  118. package/src/components/studio/blueprint/BlueprintCard.tsx +82 -0
  119. package/src/components/studio/editor/CanvasContextMenu.tsx +107 -0
  120. package/src/components/studio/editor/EditorToolbar.tsx +80 -0
  121. package/src/components/studio/editor/StageContentRenderer.tsx +134 -0
  122. package/src/components/studio/editor/TrackPropertyEditors.tsx +133 -0
  123. package/src/components/studio/editor/TreeNodeItem.tsx +91 -0
  124. package/src/components/studio/editor/edgeStyles.ts +43 -0
  125. package/src/components/studio/editor/editorKeyHandler.ts +95 -0
  126. package/src/components/studio/editor/nodeTypeRegistry.ts +137 -0
  127. package/src/components/studio/editor/paletteCatalog.tsx +84 -0
  128. package/src/components/studio/nodes/shell/InteractionNodes.tsx +82 -0
  129. package/src/components/studio/nodes/shell/LayoutControlNodes.tsx +69 -0
  130. package/src/components/studio/nodes/shell/RegisterActionNode.tsx +20 -0
  131. package/src/components/studio/nodes/shell/RegisterButtonNode.tsx +22 -0
  132. package/src/components/studio/nodes/shell/RegisterPanelNode.tsx +19 -0
  133. package/src/components/studio/nodes/shell/RegisterSidebarNode.tsx +19 -0
  134. package/src/components/studio/nodes/shell/RegisterStatusBarNode.tsx +22 -0
  135. package/src/components/studio/nodes/shell/RegisterTabNode.tsx +21 -0
  136. package/src/components/studio/nodes/shell/RegisterTopBarNode.tsx +22 -0
  137. package/src/components/studio/nodes/shell/ShellConfigNode.tsx +51 -0
  138. package/src/components/studio/nodes/shell/ShellNodeBase.tsx +100 -0
  139. package/src/components/studio/nodes/shell/ThemeNodes.tsx +51 -0
  140. package/src/components/studio/nodes/shell/index.ts +12 -0
  141. package/src/components/widgets/BroadcastWidget.tsx +93 -0
  142. package/src/components/widgets/MarketplaceWidget.tsx +298 -0
  143. package/src/components/widgets/McpToolsWidget.tsx +231 -0
  144. package/src/components/widgets/OpsDashboard.tsx +59 -0
  145. package/src/components/widgets/QuickActionsWidget.tsx +60 -0
  146. package/src/components/widgets/UsageWidget.tsx +112 -0
  147. package/src/components/widgets/WidgetRenderer.tsx +892 -0
  148. package/src/components/widgets/WidgetSlotPanel.tsx +213 -0
  149. package/src/config/IconRegistry.ts +126 -0
  150. package/src/contexts/NetworkProvider.tsx +162 -0
  151. package/src/core/AIDirector.ts +71 -0
  152. package/src/core/EventBus.ts +37 -0
  153. package/src/core/PluginContext.tsx +141 -0
  154. package/src/hooks/listeners/useUIStateListener.ts +59 -0
  155. package/src/hooks/listeners/useWhatsAppListener.ts +110 -0
  156. package/src/hooks/morphBridge.ts +82 -0
  157. package/src/hooks/useAIModelSelector.ts +144 -0
  158. package/src/hooks/useAgentStream.ts +220 -0
  159. package/src/hooks/useAutoUpdater.ts +89 -0
  160. package/src/hooks/useBootSequence.ts +20 -0
  161. package/src/hooks/useExportDSD.ts +53 -0
  162. package/src/hooks/useFullscreen.ts +35 -0
  163. package/src/hooks/useGeminiStream.ts +282 -0
  164. package/src/hooks/useIntentLens.ts +224 -0
  165. package/src/hooks/useKeyboardShortcuts.ts +69 -0
  166. package/src/hooks/useLoggerBridge.ts +32 -0
  167. package/src/hooks/useMcpClient.ts +112 -0
  168. package/src/hooks/useNexusaiDeploy.ts +118 -0
  169. package/src/hooks/usePlaybackEngine.ts +21 -0
  170. package/src/hooks/usePlaygroundCommander.ts +475 -0
  171. package/src/hooks/usePluginEngine.ts +165 -0
  172. package/src/hooks/useScreenRecorder.ts +73 -0
  173. package/src/hooks/useShellKeyboard.ts +40 -0
  174. package/src/hooks/useShellShortcuts.ts +118 -0
  175. package/src/hooks/useSoundEffects.ts +35 -0
  176. package/src/hooks/useStudioConfig.ts +72 -0
  177. package/src/hooks/useSystemBoot.ts +84 -0
  178. package/src/hooks/useSystemTelemetry.ts +62 -0
  179. package/src/index.ts +97 -0
  180. package/src/lib/debugLogger.ts +80 -0
  181. package/src/lib/networkInterceptor.ts +100 -0
  182. package/src/mocks/decido.tsx +41 -0
  183. package/src/plugins/pluginAPI.ts +190 -0
  184. package/src/store/McpStore.ts +69 -0
  185. package/src/store/UpdaterStore.ts +60 -0
  186. package/src/store/engine.ts +392 -0
  187. package/src/store/index.ts +4 -0
  188. package/src/store/layoutPresets.ts +66 -0
  189. package/src/store/playgroundTypes.ts +98 -0
  190. package/src/store/useActionTimelineStore.ts +48 -0
  191. package/src/store/useDebugPanelStore.ts +98 -0
  192. package/src/store/useDebugProfileStore.ts +130 -0
  193. package/src/store/useLayoutStore.ts +205 -0
  194. package/src/store/useMorphInstanceStore.ts +289 -0
  195. package/src/store/useMorphologyStore.ts +103 -0
  196. package/src/store/usePlaygroundStore.ts +236 -0
  197. package/src/store/useShellRegistry.ts +123 -0
  198. package/src/store/useSuggestionsStore.ts +57 -0
  199. package/src/store/useThemeStore.ts +399 -0
  200. package/src/store/useUIComponentStore.ts +179 -0
  201. package/src/types/DecidoStoryDefinition.ts +43 -0
  202. package/src/utils/ai/ai-architect.ts +92 -0
  203. package/src/utils/ai/ai-code.ts +187 -0
  204. package/src/utils/ai/ai-core.ts +50 -0
  205. package/src/utils/ai/ai-media.ts +292 -0
  206. package/src/utils/layoutGraph.ts +67 -0
  207. package/tsconfig.json +17 -0
  208. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,220 @@
1
+ /**
2
+ * useAgentStream — Typed event consumer for Decido Agent cognitive loop.
3
+ *
4
+ * 📚 Inspired by Gemini CLI's Turn event system:
5
+ * - Each event is typed (StatusChanged, Thought, ToolCallRequest, etc.)
6
+ * - Events map to specific UI components (ThinkingBlock, ToolCallBlock, etc.)
7
+ * - Supports multiple subscribers (broadcast pattern)
8
+ *
9
+ * This hook listens to Tauri IPC events from the Rust core-rust agent's
10
+ * broadcast channel (AgentStreamEvent) and maps them to ExecutionSteps
11
+ * for the chat timeline.
12
+ *
13
+ * Usage:
14
+ * const { events, isActive, lastThought } = useAgentStream(agentId);
15
+ */
16
+ import { useState, useEffect, useCallback, useRef } from 'react';
17
+ import { usePlaygroundStore } from '../store/usePlaygroundStore';
18
+ import type { ExecutionStep } from '../store/playgroundTypes';
19
+
20
+ // Mirror of Rust AgentStreamEvent (from stream_events.rs)
21
+ export interface AgentStreamEvent {
22
+ type: string;
23
+ // StatusChanged
24
+ status?: string;
25
+ agent_id?: string;
26
+ // Thought
27
+ summary?: string;
28
+ trace_id?: string;
29
+ // ToolCallRequest / ToolCallResponse
30
+ call_id?: string;
31
+ name?: string;
32
+ args?: Record<string, unknown>;
33
+ result?: unknown;
34
+ error?: string;
35
+ duration_ms?: number;
36
+ // ToolCallConfirmation
37
+ tool_name?: string;
38
+ details?: { kind: string; message?: string; command?: string; path?: string };
39
+ // Retry
40
+ attempt?: number;
41
+ max_attempts?: number;
42
+ delay_ms?: number;
43
+ reason?: string;
44
+ // Error
45
+ message?: string;
46
+ recoverable?: boolean;
47
+ // Finished
48
+ usage?: { input_tokens: number; output_tokens: number; total_tokens: number };
49
+ // GasUpdate
50
+ remaining?: number;
51
+ max?: number;
52
+ consumed?: number;
53
+ // LoopDetected
54
+ repeated_tool?: string;
55
+ count?: number;
56
+ }
57
+
58
+ interface UseAgentStreamOptions {
59
+ /** Whether to auto-create ExecutionSteps from events */
60
+ autoTimeline?: boolean;
61
+ }
62
+
63
+ export function useAgentStream(agentId: string | null, options: UseAgentStreamOptions = {}) {
64
+ const { autoTimeline = true } = options;
65
+
66
+ const [events, setEvents] = useState<AgentStreamEvent[]>([]);
67
+ const [isActive, setIsActive] = useState(false);
68
+ const [lastThought, setLastThought] = useState<string | null>(null);
69
+ const [lastStatus, setLastStatus] = useState<string>('idle');
70
+ const executionStepsRef = useRef<ExecutionStep[]>([]);
71
+
72
+ const addChatMessage = usePlaygroundStore(s => s.addChatMessage);
73
+
74
+ const handleEvent = useCallback((event: AgentStreamEvent) => {
75
+ setEvents(prev => [...prev, event]);
76
+
77
+ switch (event.type) {
78
+ case 'status_changed':
79
+ setLastStatus(event.status || 'unknown');
80
+ setIsActive(event.status !== 'idle' && event.status !== 'terminated');
81
+ if (autoTimeline) {
82
+ executionStepsRef.current.push({
83
+ type: event.status === 'thinking' ? 'thinking' : 'text_delta',
84
+ label: event.status || 'Unknown',
85
+ startTime: Date.now(),
86
+ });
87
+ }
88
+ break;
89
+
90
+ case 'thought':
91
+ setLastThought(event.summary || null);
92
+ if (autoTimeline) {
93
+ executionStepsRef.current.push({
94
+ type: 'thinking',
95
+ label: event.summary?.slice(0, 80) || 'Thinking...',
96
+ startTime: Date.now(),
97
+ endTime: Date.now(),
98
+ });
99
+ }
100
+ break;
101
+
102
+ case 'tool_call_request':
103
+ if (autoTimeline) {
104
+ executionStepsRef.current.push({
105
+ type: 'tool_call' as any,
106
+ label: `🔧 ${event.name}`,
107
+ startTime: Date.now(),
108
+ });
109
+ }
110
+ break;
111
+
112
+ case 'tool_call_response':
113
+ if (autoTimeline) {
114
+ const last = executionStepsRef.current[executionStepsRef.current.length - 1];
115
+ if (last) last.endTime = Date.now();
116
+ executionStepsRef.current.push({
117
+ type: 'text_complete',
118
+ label: event.error
119
+ ? `❌ ${event.name}: ${event.error}`
120
+ : `✅ ${event.name} (${event.duration_ms}ms)`,
121
+ startTime: Date.now(),
122
+ endTime: Date.now(),
123
+ });
124
+ }
125
+ break;
126
+
127
+ case 'tool_call_confirmation':
128
+ addChatMessage({
129
+ type: 'alert',
130
+ sender: 'system',
131
+ text: `⚠️ Agent requests approval: ${event.tool_name} — ${event.details?.message || ''}`,
132
+ });
133
+ break;
134
+
135
+ case 'retry':
136
+ if (autoTimeline) {
137
+ executionStepsRef.current.push({
138
+ type: 'retry' as any,
139
+ label: `🔄 Retry ${event.attempt}/${event.max_attempts}: ${event.reason}`,
140
+ startTime: Date.now(),
141
+ });
142
+ }
143
+ break;
144
+
145
+ case 'error':
146
+ addChatMessage({
147
+ type: 'error',
148
+ sender: 'system',
149
+ text: `❌ ${event.message}${event.recoverable ? ' (recoverable)' : ''}`,
150
+ });
151
+ break;
152
+
153
+ case 'finished':
154
+ setIsActive(false);
155
+ if (autoTimeline) {
156
+ executionStepsRef.current.push({
157
+ type: 'text_complete',
158
+ label: 'Complete',
159
+ startTime: Date.now(),
160
+ endTime: Date.now(),
161
+ });
162
+ }
163
+ break;
164
+
165
+ case 'gas_update':
166
+ // Gas info is available via event properties (remaining, max, consumed)
167
+ break;
168
+
169
+ case 'loop_detected':
170
+ addChatMessage({
171
+ type: 'alert',
172
+ sender: 'system',
173
+ text: `🔁 Loop detected: ${event.repeated_tool} called ${event.count} times`,
174
+ });
175
+ break;
176
+ }
177
+ }, [autoTimeline, addChatMessage]);
178
+
179
+ // Listen to Tauri IPC events from the Rust kernel
180
+ useEffect(() => {
181
+ if (!agentId) return;
182
+
183
+ let unlisten: (() => void) | null = null;
184
+
185
+ const setup = async () => {
186
+ try {
187
+ // Dynamic import to avoid build failures when not in Tauri context
188
+ const { listen } = await import('@tauri-apps/api/event');
189
+ const cleanup = await listen<AgentStreamEvent>(
190
+ `agent-stream:${agentId}`,
191
+ (e) => handleEvent(e.payload),
192
+ );
193
+ unlisten = cleanup;
194
+ } catch {
195
+ // Not in Tauri context (dev mode) — use mock EventSource fallback
196
+ console.debug('[useAgentStream] Not in Tauri context, using event bus fallback');
197
+ }
198
+ };
199
+
200
+ setup();
201
+
202
+ return () => {
203
+ unlisten?.();
204
+ };
205
+ }, [agentId, handleEvent]);
206
+
207
+ const clearEvents = useCallback(() => {
208
+ setEvents([]);
209
+ executionStepsRef.current = [];
210
+ }, []);
211
+
212
+ return {
213
+ events,
214
+ isActive,
215
+ lastThought,
216
+ lastStatus,
217
+ executionSteps: executionStepsRef.current,
218
+ clearEvents,
219
+ };
220
+ }
@@ -0,0 +1,89 @@
1
+ import { useEffect } from 'react';
2
+ import { kernel } from '@decido/kernel-bridge';
3
+ import { useUpdaterStore } from '../store/UpdaterStore';
4
+ export interface UseAutoUpdaterOptions {
5
+ appName?: string;
6
+ onUpdateAvailable?: (version: string, date?: string) => void;
7
+ onUpdateFinished?: () => void;
8
+ delayMs?: number;
9
+ }
10
+
11
+ export const useAutoUpdater = ({
12
+ appName = "Decido OS",
13
+ onUpdateAvailable,
14
+ onUpdateFinished,
15
+ delayMs = 4000
16
+ }: UseAutoUpdaterOptions = {}) => {
17
+ const updaterStore = useUpdaterStore();
18
+
19
+ useEffect(() => {
20
+ const checkForUpdates = async () => {
21
+ if (!('__TAURI_INTERNALS__' in window)) {
22
+ console.info('[Updater] Ejecución en navegador detectada. Saltando buscar OTA de Tauri.');
23
+ return;
24
+ }
25
+ try {
26
+ updaterStore.setChecking();
27
+
28
+ const updater = await import('@tauri-apps/plugin-updater');
29
+ const update = await updater.check();
30
+
31
+ if (update) {
32
+ console.info(`[Updater] Nueva versión encontrada: ${update.version} (${update.date})`);
33
+
34
+ if (onUpdateAvailable) {
35
+ onUpdateAvailable(update.version, update.date);
36
+ } else {
37
+ kernel.notify('🚀 Actualización Disponible', `Descargando silenciósamente la versión ${update.version}...`);
38
+ }
39
+
40
+ let downloaded = 0;
41
+ let contentLength = 0;
42
+
43
+ await update.downloadAndInstall((event) => {
44
+ switch (event.event) {
45
+ case 'Started':
46
+ contentLength = event.data.contentLength as number;
47
+ updaterStore.setDownloading(update.version, contentLength);
48
+ break;
49
+ case 'Progress':
50
+ updaterStore.updateProgress(event.data.chunkLength);
51
+ break;
52
+ case 'Finished':
53
+ console.info('[Updater] Descarga completada. Preparando reinicio.');
54
+ updaterStore.setInstalling();
55
+ break;
56
+ }
57
+ });
58
+
59
+ if (onUpdateFinished) {
60
+ onUpdateFinished();
61
+ } else {
62
+ updaterStore.setRebooting();
63
+ setTimeout(async () => {
64
+ const process = await import('@tauri-apps/plugin-process');
65
+ process.relaunch();
66
+ }, 3000);
67
+ }
68
+
69
+ } else {
70
+ updaterStore.reset();
71
+ }
72
+ } catch (error: any) {
73
+ const msg = error?.toString() || '';
74
+ // Treat ANY network/fetch failure as "offline mode" — don't show intrusive error UI
75
+ if (msg.includes('url') || msg.includes('404') || msg.includes('offline')
76
+ || msg.includes('Could not fetch') || msg.includes('fetch')
77
+ || msg.includes('network') || msg.includes('ECONNREFUSED')) {
78
+ console.info('[Updater] OTA no disponible — modo local/offline.');
79
+ updaterStore.reset();
80
+ } else {
81
+ console.error('[Updater] Falló el escaneo de actualizaciones:', error);
82
+ updaterStore.setError(msg);
83
+ }
84
+ }
85
+ };
86
+
87
+ setTimeout(checkForUpdates, delayMs);
88
+ }, [appName, onUpdateAvailable, onUpdateFinished, delayMs]);
89
+ };
@@ -0,0 +1,20 @@
1
+ import { useEffect } from 'react';
2
+ import { usePlaygroundStore } from '../store/usePlaygroundStore';
3
+ import { playSound } from './useSoundEffects';
4
+
5
+ /**
6
+ * useBootSequence — Handles the initial boot animation timer.
7
+ * After 2.5s, sets isBooting=false and plays a success sound.
8
+ */
9
+ export function useBootSequence() {
10
+ const setIsBooting = usePlaygroundStore((s) => s.setIsBooting);
11
+ const isMuted = usePlaygroundStore((s) => s.isMuted);
12
+
13
+ useEffect(() => {
14
+ const timer = setTimeout(() => {
15
+ setIsBooting(false);
16
+ playSound('success', isMuted);
17
+ }, 2500);
18
+ return () => clearTimeout(timer);
19
+ }, [isMuted, setIsBooting]);
20
+ }
@@ -0,0 +1,53 @@
1
+ import { usePlaygroundStore } from '../store/usePlaygroundStore';
2
+ import { useTimelineStore } from '@decido/engine';
3
+
4
+ /**
5
+ * useExportDSD — Handles exporting the current blueprint as a
6
+ * Decido Standard Document (.dsd) file.
7
+ */
8
+ export function useExportDSD() {
9
+ const { prototypeBrand, addLog } = usePlaygroundStore();
10
+ const currentBlueprint = useTimelineStore(
11
+ (s) => s.timelines[prototypeBrand]
12
+ );
13
+
14
+ const handleExport = async () => {
15
+ if (!currentBlueprint) {
16
+ addLog('No hay un blueprint activo para exportar.', 'error');
17
+ return;
18
+ }
19
+
20
+ try {
21
+ const dsdPayload = {
22
+ format: 'decido-standard-document',
23
+ version: '1.0',
24
+ exportedAt: new Date().toISOString(),
25
+ brand: prototypeBrand,
26
+ blueprint: currentBlueprint,
27
+ };
28
+
29
+ const blob = new Blob([JSON.stringify(dsdPayload, null, 2)], {
30
+ type: 'application/json',
31
+ });
32
+ const url = URL.createObjectURL(blob);
33
+
34
+ const a = document.createElement('a');
35
+ a.href = url;
36
+ a.download = `${prototypeBrand}-demo.dsd`;
37
+ document.body.appendChild(a);
38
+ a.click();
39
+ document.body.removeChild(a);
40
+ URL.revokeObjectURL(url);
41
+
42
+ addLog(
43
+ `Grafo exportado exitosamente como ${prototypeBrand}-demo.dsd`,
44
+ 'success'
45
+ );
46
+ } catch (e) {
47
+ addLog(`Error exportando DSD: ${e}`, 'error');
48
+ console.error(e);
49
+ }
50
+ };
51
+
52
+ return { handleExport };
53
+ }
@@ -0,0 +1,35 @@
1
+ import { useEffect, useCallback } from 'react';
2
+ import { usePlaygroundStore } from '../store/usePlaygroundStore';
3
+
4
+ /**
5
+ * useFullscreen — Manages native fullscreen API.
6
+ * Keeps usePlaygroundStore.isFullscreen in sync with document.fullscreenElement.
7
+ *
8
+ * Returns: { isFullscreen, toggleFullscreen }
9
+ */
10
+ export function useFullscreen() {
11
+ const isFullscreen = usePlaygroundStore((s) => s.isFullscreen);
12
+ const setIsFullscreen = usePlaygroundStore((s) => s.setIsFullscreen);
13
+
14
+ const toggleFullscreen = useCallback(() => {
15
+ if (!document.fullscreenElement) {
16
+ document.documentElement
17
+ .requestFullscreen()
18
+ .catch((err) =>
19
+ console.error(`Fullscreen err: ${err.message}`)
20
+ );
21
+ } else {
22
+ if (document.exitFullscreen) document.exitFullscreen();
23
+ }
24
+ }, []);
25
+
26
+ useEffect(() => {
27
+ const handleChange = () =>
28
+ setIsFullscreen(!!document.fullscreenElement);
29
+ document.addEventListener('fullscreenchange', handleChange);
30
+ return () =>
31
+ document.removeEventListener('fullscreenchange', handleChange);
32
+ }, [setIsFullscreen]);
33
+
34
+ return { isFullscreen, toggleFullscreen };
35
+ }