@decido/shell 4.0.2 → 4.0.3

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 (37) hide show
  1. package/dist/CenterComposite-RPEGBKQU.mjs +1697 -0
  2. package/dist/DebugPanel-KEKDMHDN.mjs +14 -0
  3. package/dist/MorphShell-FKDBB7E5.mjs +14 -0
  4. package/dist/PlaygroundAppSidebar-ALYJJGAO.mjs +9 -0
  5. package/dist/PlaygroundChat-MI2KXMK6.mjs +15 -0
  6. package/dist/PlaygroundTerminal-5AV4BJAI.mjs +7 -0
  7. package/dist/PluginSandbox-WMNAUQOJ.mjs +188 -0
  8. package/dist/ReactFlowEditor-RTF2652X.mjs +3574 -0
  9. package/dist/ReactFlowEditor-ZW5MCN5Y.css +561 -0
  10. package/dist/TimelineEditor-N4HRMHTB.mjs +226 -0
  11. package/dist/WidgetSlotPanel-KJI4CHHD.mjs +11 -0
  12. package/dist/chunk-2YMI4N5I.mjs +2004 -0
  13. package/dist/chunk-3BZX7LF2.mjs +139 -0
  14. package/dist/chunk-3P4P3M54.mjs +136 -0
  15. package/dist/chunk-F3OTFHNO.mjs +40 -0
  16. package/dist/chunk-IMHORBTL.mjs +48 -0
  17. package/dist/chunk-JF5QSJYT.mjs +295 -0
  18. package/dist/chunk-LWMMFTJC.mjs +382 -0
  19. package/dist/chunk-MSVEFEXE.mjs +179 -0
  20. package/dist/chunk-OCHGY2MN.mjs +1662 -0
  21. package/dist/chunk-PMYAM764.mjs +813 -0
  22. package/dist/chunk-Q64KZXPK.mjs +43 -0
  23. package/dist/chunk-QHQW2HMU.mjs +155 -0
  24. package/dist/chunk-RWZ4BOIN.mjs +385 -0
  25. package/dist/chunk-UHT6FIYF.mjs +195 -0
  26. package/dist/chunk-UJCSKKID.mjs +30 -0
  27. package/dist/chunk-V3CYNPGL.mjs +8758 -0
  28. package/dist/chunk-VBPGEFNM.mjs +2381 -0
  29. package/dist/chunk-XMSU6UWD.mjs +158 -0
  30. package/dist/chunk-ZCCCBHE6.mjs +55 -0
  31. package/dist/index.css +561 -0
  32. package/dist/index.js +65130 -0
  33. package/dist/index.mjs +40248 -0
  34. package/dist/useIntentLens-LEQCAXCK.mjs +13 -0
  35. package/dist/useSuggestionsStore-4L2AIZ2D.mjs +7 -0
  36. package/dist/wasm-QFXGEYGP.mjs +81 -0
  37. package/package.json +17 -18
@@ -0,0 +1,1662 @@
1
+ import {
2
+ getRegisteredShellTypes,
3
+ getShellMeta
4
+ } from "./chunk-IMHORBTL.mjs";
5
+ import {
6
+ useSuggestionsStore
7
+ } from "./chunk-F3OTFHNO.mjs";
8
+ import {
9
+ getIntentPatterns,
10
+ useIntentLens
11
+ } from "./chunk-QHQW2HMU.mjs";
12
+ import {
13
+ useMorphInstanceStore
14
+ } from "./chunk-UHT6FIYF.mjs";
15
+ import {
16
+ useUIComponentStore
17
+ } from "./chunk-3BZX7LF2.mjs";
18
+ import {
19
+ useLayoutStore
20
+ } from "./chunk-MSVEFEXE.mjs";
21
+ import {
22
+ usePlaygroundStore
23
+ } from "./chunk-XMSU6UWD.mjs";
24
+
25
+ // src/components/playground/PlaygroundChat.tsx
26
+ import React8 from "react";
27
+ import { motion as motion4, AnimatePresence as AnimatePresence4 } from "motion/react";
28
+ import { Building2 as Building22, BrainCircuit as BrainCircuit2, Sparkles as Sparkles3, Download } from "lucide-react";
29
+
30
+ // src/components/playground/SuggestionCards.tsx
31
+ import React from "react";
32
+
33
+ // src/config/IconRegistry.ts
34
+ import {
35
+ Search,
36
+ Workflow,
37
+ Zap,
38
+ Terminal,
39
+ BrainCircuit,
40
+ Command,
41
+ FileText,
42
+ Cpu,
43
+ ShoppingCart,
44
+ Building2,
45
+ Activity,
46
+ Thermometer,
47
+ AlertTriangle,
48
+ TrendingUp,
49
+ PackageCheck,
50
+ Network,
51
+ Home,
52
+ Settings,
53
+ MessageSquare,
54
+ Globe,
55
+ Lock,
56
+ Shield,
57
+ Database,
58
+ HardDrive,
59
+ Wifi,
60
+ Cloud,
61
+ Server,
62
+ BarChart3,
63
+ PieChart,
64
+ Gauge,
65
+ Bell,
66
+ Mail,
67
+ Users,
68
+ FolderOpen,
69
+ Code,
70
+ Layers,
71
+ Box,
72
+ Rocket,
73
+ Sparkles
74
+ } from "lucide-react";
75
+ var ICON_MAP = {
76
+ // Communication & AI
77
+ "Search": Search,
78
+ "MessageSquare": MessageSquare,
79
+ "BrainCircuit": BrainCircuit,
80
+ "Sparkles": Sparkles,
81
+ "Command": Command,
82
+ "Terminal": Terminal,
83
+ // Actions & Flow
84
+ "Workflow": Workflow,
85
+ "Zap": Zap,
86
+ "Rocket": Rocket,
87
+ "Network": Network,
88
+ // Data & Files
89
+ "FileText": FileText,
90
+ "FolderOpen": FolderOpen,
91
+ "Code": Code,
92
+ "Database": Database,
93
+ // Business & Commerce
94
+ "ShoppingCart": ShoppingCart,
95
+ "Building2": Building2,
96
+ "Users": Users,
97
+ // Monitoring & Metrics
98
+ "Activity": Activity,
99
+ "Thermometer": Thermometer,
100
+ "AlertTriangle": AlertTriangle,
101
+ "TrendingUp": TrendingUp,
102
+ "BarChart3": BarChart3,
103
+ "PieChart": PieChart,
104
+ "Gauge": Gauge,
105
+ "Bell": Bell,
106
+ // Infrastructure
107
+ "Cpu": Cpu,
108
+ "HardDrive": HardDrive,
109
+ "Server": Server,
110
+ "Cloud": Cloud,
111
+ "Wifi": Wifi,
112
+ "PackageCheck": PackageCheck,
113
+ // Security & Settings
114
+ "Lock": Lock,
115
+ "Shield": Shield,
116
+ "Settings": Settings,
117
+ // Misc
118
+ "Globe": Globe,
119
+ "Mail": Mail,
120
+ "Home": Home,
121
+ "Layers": Layers,
122
+ "Box": Box
123
+ };
124
+ function resolveIcon(name) {
125
+ return ICON_MAP[name] || Command;
126
+ }
127
+ var COLOR_MAP = {
128
+ "emerald": "text-emerald-400",
129
+ "cyan": "text-cyan-400",
130
+ "purple": "text-purple-400",
131
+ "orange": "text-orange-400",
132
+ "yellow": "text-yellow-400",
133
+ "rose": "text-rose-400",
134
+ "red": "text-red-400",
135
+ "blue": "text-blue-400",
136
+ "indigo": "text-indigo-400",
137
+ "pink": "text-pink-400",
138
+ "amber": "text-amber-400",
139
+ "teal": "text-teal-400",
140
+ "lime": "text-lime-400",
141
+ "sky": "text-sky-400",
142
+ "violet": "text-violet-400",
143
+ "fuchsia": "text-fuchsia-400",
144
+ "white": "text-white"
145
+ };
146
+ function resolveColor(name) {
147
+ return COLOR_MAP[name] || "text-white";
148
+ }
149
+ function resolveColorClasses(color) {
150
+ return {
151
+ text: COLOR_MAP[color] || "text-white",
152
+ bg: `bg-${color}-500/10`,
153
+ border: `border-${color}-500/20`
154
+ };
155
+ }
156
+
157
+ // src/components/playground/SuggestionCards.tsx
158
+ import { jsx, jsxs } from "react/jsx-runtime";
159
+ var SuggestionCards = React.memo(function SuggestionCards2({ suggestions, onSelect }) {
160
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2.5 sm:gap-3 w-full min-w-0 max-w-full mt-3 sm:mt-4", children: suggestions.map((sug, i) => {
161
+ const IconComponent = resolveIcon(sug.icon);
162
+ const colorClass = resolveColor(sug.color);
163
+ return /* @__PURE__ */ jsx("div", { className: "group relative flex flex-col p-3 sm:p-4 bg-surface-tertiary hover:bg-surface-elevated border border-border-subtle hover:border-border-default rounded-xl sm:rounded-2xl text-left transition-all overflow-hidden h-auto min-h-[6rem] sm:h-32 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex-1 cursor-pointer flex flex-col min-w-0", onClick: () => onSelect(sug.command), children: [
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5 sm:mb-2", children: [
165
+ /* @__PURE__ */ jsx("div", { className: `p-1 sm:p-1.5 rounded-full bg-surface-glass shrink-0 ${colorClass}`, children: /* @__PURE__ */ jsx(IconComponent, { size: 12, className: "sm:w-3.5 sm:h-3.5" }) }),
166
+ /* @__PURE__ */ jsx("span", { className: `text-[11px] sm:text-xs font-bold truncate ${colorClass}`, children: sug.title })
167
+ ] }),
168
+ /* @__PURE__ */ jsxs("p", { className: "text-xs sm:text-sm text-text-secondary flex-1 leading-snug line-clamp-2 sm:line-clamp-3 overflow-hidden break-words", children: [
169
+ '"',
170
+ sug.command,
171
+ '"'
172
+ ] })
173
+ ] }) }, i);
174
+ }) });
175
+ });
176
+
177
+ // src/components/playground/PlaygroundFloatingInput.tsx
178
+ import { useState as useState6, useRef as useRef3, useEffect as useEffect4, useMemo as useMemo4, useCallback as useCallback3 } from "react";
179
+ import { motion as motion3, AnimatePresence as AnimatePresence3 } from "motion/react";
180
+ import { Paperclip, FolderOpen as FolderOpen3 } from "lucide-react";
181
+ import { useTimelineStore } from "@decido/engine";
182
+ import { SlashCommandMenu, VoiceLiveMode } from "@decido/chat";
183
+
184
+ // src/hooks/useAIModelSelector.ts
185
+ import { useState, useEffect, useMemo, useCallback } from "react";
186
+ import {
187
+ getProviderStatuses
188
+ } from "@decido/kernel-bridge";
189
+ var KNOWN_MODELS = {
190
+ ollama: [
191
+ { id: "qwen2.5:7b", label: "Qwen 2.5 7B", provider: "ollama", tag: "local", isLocal: true },
192
+ { id: "llama3.1:8b", label: "Llama 3.1 8B", provider: "ollama", tag: "local", isLocal: true },
193
+ { id: "codellama:7b", label: "CodeLlama 7B", provider: "ollama", tag: "code", isLocal: true },
194
+ { id: "mistral:7b", label: "Mistral 7B", provider: "ollama", tag: "local", isLocal: true }
195
+ ],
196
+ gemini: [
197
+ { id: "gemini-3-flash-preview", label: "3.0 Flash", provider: "gemini", tag: "fast", isLocal: false },
198
+ { id: "gemini-3.1-pro-preview", label: "3.1 Pro", provider: "gemini", tag: "smart", isLocal: false },
199
+ { id: "gemini-3.1-flash-lite-preview", label: "3.1 Flash Lite", provider: "gemini", tag: "stable", isLocal: false }
200
+ ],
201
+ anthropic: [
202
+ { id: "claude-sonnet-4-20250514", label: "Sonnet 4", provider: "anthropic", tag: "balanced", isLocal: false },
203
+ { id: "claude-3-5-haiku-20241022", label: "3.5 Haiku", provider: "anthropic", tag: "fast", isLocal: false }
204
+ ],
205
+ openai: [
206
+ { id: "gpt-4o", label: "GPT-4o", provider: "openai", tag: "smart", isLocal: false },
207
+ { id: "gpt-4o-mini", label: "GPT-4o Mini", provider: "openai", tag: "fast", isLocal: false }
208
+ ]
209
+ };
210
+ var PROVIDER_META = {
211
+ ollama: { label: "Ollama", icon: "\u{1F999}", color: "#10b981", isLocal: true },
212
+ gemini: { label: "Gemini", icon: "\u2728", color: "#3b82f6", isLocal: false },
213
+ anthropic: { label: "Claude", icon: "\u{1F9E0}", color: "#a855f7", isLocal: false },
214
+ openai: { label: "OpenAI", icon: "\u26A1", color: "#06b6d4", isLocal: false },
215
+ mlx: { label: "MLX", icon: "\u{1F34E}", color: "#f59e0b", isLocal: true }
216
+ };
217
+ var STORAGE_KEY = "decido_ai_model";
218
+ function useAIModelSelector() {
219
+ const [selectedModelId, setSelectedModelId] = useState(
220
+ () => localStorage.getItem(STORAGE_KEY) || "gemini-3-flash-preview"
221
+ );
222
+ const [providerStatuses, setProviderStatuses] = useState({});
223
+ useEffect(() => {
224
+ let mounted = true;
225
+ const check = async () => {
226
+ try {
227
+ const statuses = await getProviderStatuses();
228
+ if (!mounted) return;
229
+ const map = {};
230
+ for (const [id, status] of Object.entries(statuses)) {
231
+ map[id] = status === "available" ? "online" : "offline";
232
+ }
233
+ setProviderStatuses(map);
234
+ } catch {
235
+ }
236
+ };
237
+ check();
238
+ const timer = setInterval(check, 3e4);
239
+ return () => {
240
+ mounted = false;
241
+ clearInterval(timer);
242
+ };
243
+ }, []);
244
+ const providerGroups = useMemo(() => {
245
+ return Object.entries(KNOWN_MODELS).map(([id, models]) => {
246
+ const meta = PROVIDER_META[id] || { label: id, icon: "\u{1F916}", color: "#888", isLocal: false };
247
+ return {
248
+ provider: id,
249
+ label: meta.label,
250
+ icon: meta.icon,
251
+ color: meta.color,
252
+ isLocal: meta.isLocal,
253
+ models,
254
+ status: providerStatuses[id] || "unknown"
255
+ };
256
+ });
257
+ }, [providerStatuses]);
258
+ const selectedModel = useMemo(() => {
259
+ for (const group of providerGroups) {
260
+ const found = group.models.find((m) => m.id === selectedModelId);
261
+ if (found) return { model: found, group };
262
+ }
263
+ return {
264
+ model: { id: selectedModelId, label: selectedModelId, provider: "unknown", tag: "", isLocal: false },
265
+ group: providerGroups[0] || null
266
+ };
267
+ }, [selectedModelId, providerGroups]);
268
+ const selectModel = useCallback((modelId) => {
269
+ setSelectedModelId(modelId);
270
+ localStorage.setItem(STORAGE_KEY, modelId);
271
+ if (typeof window !== "undefined" && window.__DECIDO__) {
272
+ window.__DECIDO__.selectedModel = modelId;
273
+ }
274
+ }, []);
275
+ return {
276
+ selectedModelId,
277
+ selectedModel: selectedModel.model,
278
+ selectedProvider: selectedModel.group,
279
+ providerGroups,
280
+ selectModel,
281
+ providerStatuses
282
+ };
283
+ }
284
+
285
+ // src/components/chat-extensions/IntentCatalogPanel.tsx
286
+ import React2, { useState as useState2 } from "react";
287
+ import { motion, AnimatePresence } from "motion/react";
288
+ import { ChevronDown, Zap as Zap2 } from "lucide-react";
289
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
290
+ var IntentCatalogPanel = React2.memo(function IntentCatalogPanel2({ onSelect }) {
291
+ const patterns = getIntentPatterns();
292
+ const [expanded, setExpanded] = useState2(null);
293
+ return /* @__PURE__ */ jsxs2("div", { className: "w-full bg-surface-tertiary border border-border-default rounded-xl overflow-hidden shadow-2xl", children: [
294
+ /* @__PURE__ */ jsxs2("div", { className: "px-3 py-2 flex items-center gap-2 border-b border-border-subtle", children: [
295
+ /* @__PURE__ */ jsx2(Zap2, { size: 12, className: "text-cyan-400" }),
296
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-text-muted font-mono uppercase tracking-wider", children: "Intenciones Disponibles" })
297
+ ] }),
298
+ /* @__PURE__ */ jsxs2("div", { className: "max-h-[240px] overflow-y-auto custom-scrollbar", children: [
299
+ patterns.map((p) => /* @__PURE__ */ jsxs2("div", { className: "border-b border-border-subtle last:border-0", children: [
300
+ /* @__PURE__ */ jsxs2(
301
+ "button",
302
+ {
303
+ onClick: () => setExpanded(expanded === p.type ? null : p.type),
304
+ className: "w-full flex items-center gap-2 px-3 py-2 text-xs hover:bg-surface-glass transition-colors",
305
+ children: [
306
+ /* @__PURE__ */ jsx2("span", { className: "text-base leading-none", children: p.icon }),
307
+ /* @__PURE__ */ jsx2("span", { className: "font-semibold text-text-primary flex-1 text-left", children: p.label }),
308
+ /* @__PURE__ */ jsx2(
309
+ "span",
310
+ {
311
+ className: "w-2 h-2 rounded-full shrink-0",
312
+ style: { background: p.color }
313
+ }
314
+ ),
315
+ /* @__PURE__ */ jsx2(
316
+ ChevronDown,
317
+ {
318
+ size: 12,
319
+ className: `text-text-muted transition-transform ${expanded === p.type ? "rotate-180" : ""}`
320
+ }
321
+ )
322
+ ]
323
+ }
324
+ ),
325
+ /* @__PURE__ */ jsx2(AnimatePresence, { children: expanded === p.type && /* @__PURE__ */ jsx2(
326
+ motion.div,
327
+ {
328
+ initial: { height: 0, opacity: 0 },
329
+ animate: { height: "auto", opacity: 1 },
330
+ exit: { height: 0, opacity: 0 },
331
+ transition: { duration: 0.15 },
332
+ className: "overflow-hidden",
333
+ children: /* @__PURE__ */ jsx2("div", { className: "px-3 pb-2 space-y-1", children: p.examples.map((ex, i) => /* @__PURE__ */ jsxs2(
334
+ "button",
335
+ {
336
+ onClick: () => onSelect(ex),
337
+ className: "w-full text-left px-2.5 py-1.5 rounded-lg text-[11px] text-text-secondary hover:text-text-primary hover:bg-surface-glass transition-colors font-mono leading-snug flex items-center gap-2 group",
338
+ children: [
339
+ /* @__PURE__ */ jsx2(
340
+ "span",
341
+ {
342
+ className: "w-1 h-1 rounded-full shrink-0 opacity-40 group-hover:opacity-100 transition-opacity",
343
+ style: { background: p.color }
344
+ }
345
+ ),
346
+ /* @__PURE__ */ jsx2("span", { className: "flex-1", children: ex }),
347
+ /* @__PURE__ */ jsx2("span", { className: "text-[9px] text-text-muted opacity-0 group-hover:opacity-100 transition-opacity", children: "\u21B5" })
348
+ ]
349
+ },
350
+ i
351
+ )) })
352
+ }
353
+ ) })
354
+ ] }, p.type)),
355
+ patterns.length === 0 && /* @__PURE__ */ jsx2("div", { className: "px-3 py-4 text-xs text-text-muted italic text-center", children: "Sin intenciones registradas" })
356
+ ] })
357
+ ] });
358
+ });
359
+
360
+ // src/components/playground/input-parts/InputToolbar.tsx
361
+ import React4, { useState as useState4, useMemo as useMemo2, useRef as useRef2, useEffect as useEffect3 } from "react";
362
+ import { MonitorPlay, Code2, ChevronDown as ChevronDown3, Zap as Zap3, Brain, Settings2 } from "lucide-react";
363
+
364
+ // src/components/playground/input-parts/AIModelSelector.tsx
365
+ import React3, { useState as useState3, useRef, useEffect as useEffect2 } from "react";
366
+ import { ChevronDown as ChevronDown2, Cpu as Cpu2 } from "lucide-react";
367
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
368
+ var TAG_STYLES = {
369
+ fast: "bg-cyan-500/20 text-cyan-400",
370
+ smart: "bg-purple-500/20 text-purple-400",
371
+ stable: "bg-emerald-500/20 text-emerald-400",
372
+ new: "bg-emerald-500/20 text-emerald-400",
373
+ code: "bg-amber-500/20 text-amber-400",
374
+ local: "bg-emerald-500/15 text-emerald-400",
375
+ balanced: "bg-purple-500/15 text-purple-400",
376
+ vision: "bg-pink-500/20 text-pink-400",
377
+ audio: "bg-amber-500/20 text-amber-400",
378
+ lite: "bg-surface-glass text-text-secondary"
379
+ };
380
+ var STATUS_DOT = {
381
+ online: "bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.5)]",
382
+ offline: "bg-red-400/60",
383
+ unknown: "bg-surface-tertiary"
384
+ };
385
+ var AIModelSelector = React3.memo(function AIModelSelector2({
386
+ selectedModelId,
387
+ selectedModel,
388
+ providerGroups,
389
+ onSelect
390
+ }) {
391
+ const [isOpen, setIsOpen] = useState3(false);
392
+ const containerRef = useRef(null);
393
+ useEffect2(() => {
394
+ if (!isOpen) return;
395
+ const handler = (e) => {
396
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
397
+ setIsOpen(false);
398
+ }
399
+ };
400
+ document.addEventListener("mousedown", handler);
401
+ return () => document.removeEventListener("mousedown", handler);
402
+ }, [isOpen]);
403
+ const localGroups = providerGroups.filter((g) => g.isLocal);
404
+ const cloudGroups = providerGroups.filter((g) => !g.isLocal);
405
+ return /* @__PURE__ */ jsxs3("div", { ref: containerRef, className: "relative", children: [
406
+ /* @__PURE__ */ jsxs3(
407
+ "button",
408
+ {
409
+ type: "button",
410
+ onClick: (e) => {
411
+ e.stopPropagation();
412
+ setIsOpen(!isOpen);
413
+ },
414
+ className: "flex items-center gap-1.5 px-2 py-1.5 rounded-xl text-text-muted\n hover:text-text-primary hover:bg-surface-glass transition-all text-[10px] font-mono",
415
+ title: `Modelo AI: ${selectedModel.label}`,
416
+ children: [
417
+ /* @__PURE__ */ jsx3(Cpu2, { size: 14 }),
418
+ /* @__PURE__ */ jsx3(ChevronDown2, { size: 10 })
419
+ ]
420
+ }
421
+ ),
422
+ isOpen && /* @__PURE__ */ jsxs3(
423
+ "div",
424
+ {
425
+ className: "absolute left-0 w-64 bg-white/90 dark:bg-surface-tertiary border border-black/[0.06] dark:border-border-default\n rounded-xl shadow-xl dark:shadow-2xl z-50 max-h-[360px] overflow-y-auto custom-scrollbar",
426
+ style: { bottom: "100%", marginBottom: "0.5rem" },
427
+ children: [
428
+ localGroups.length > 0 && /* @__PURE__ */ jsxs3(Fragment, { children: [
429
+ /* @__PURE__ */ jsxs3("div", { className: "px-3 py-1.5 text-[9px] text-text-muted font-mono uppercase tracking-wider\n border-b border-border-subtle flex items-center gap-1.5", children: [
430
+ /* @__PURE__ */ jsx3("span", { className: "text-emerald-400", children: "\u25CF" }),
431
+ " Local"
432
+ ] }),
433
+ localGroups.map((group) => /* @__PURE__ */ jsx3(
434
+ ProviderSection,
435
+ {
436
+ group,
437
+ selectedModelId,
438
+ onSelect: (id) => {
439
+ onSelect(id);
440
+ setIsOpen(false);
441
+ }
442
+ },
443
+ group.provider
444
+ ))
445
+ ] }),
446
+ cloudGroups.length > 0 && /* @__PURE__ */ jsxs3(Fragment, { children: [
447
+ /* @__PURE__ */ jsxs3("div", { className: "px-3 py-1.5 text-[9px] text-text-muted font-mono uppercase tracking-wider\n border-b border-border-subtle flex items-center gap-1.5", children: [
448
+ /* @__PURE__ */ jsx3("span", { className: "text-cyan-400", children: "\u2601" }),
449
+ " Cloud (BYOK)"
450
+ ] }),
451
+ cloudGroups.map((group) => /* @__PURE__ */ jsx3(
452
+ ProviderSection,
453
+ {
454
+ group,
455
+ selectedModelId,
456
+ onSelect: (id) => {
457
+ onSelect(id);
458
+ setIsOpen(false);
459
+ }
460
+ },
461
+ group.provider
462
+ ))
463
+ ] })
464
+ ]
465
+ }
466
+ )
467
+ ] });
468
+ });
469
+ function ProviderSection({
470
+ group,
471
+ selectedModelId,
472
+ onSelect
473
+ }) {
474
+ return /* @__PURE__ */ jsxs3("div", { children: [
475
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-1.5 text-[10px] font-semibold text-text-secondary", children: [
476
+ /* @__PURE__ */ jsx3("span", { children: group.icon }),
477
+ /* @__PURE__ */ jsx3("span", { children: group.label }),
478
+ /* @__PURE__ */ jsx3("span", { className: `w-1.5 h-1.5 rounded-full ml-auto ${STATUS_DOT[group.status]}` })
479
+ ] }),
480
+ group.models.map((m) => /* @__PURE__ */ jsxs3(
481
+ "button",
482
+ {
483
+ type: "button",
484
+ onClick: (e) => {
485
+ e.stopPropagation();
486
+ onSelect(m.id);
487
+ },
488
+ className: `w-full text-left px-3 py-2 text-xs flex items-center justify-between transition-colors
489
+ ${selectedModelId === m.id ? "text-text-primary" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`,
490
+ style: selectedModelId === m.id ? { background: `${group.color}20` } : void 0,
491
+ children: [
492
+ /* @__PURE__ */ jsx3("span", { className: "font-mono truncate", children: m.label }),
493
+ m.tag && /* @__PURE__ */ jsx3("span", { className: `text-[9px] px-1.5 py-0.5 rounded-full font-semibold shrink-0 ${TAG_STYLES[m.tag] || "bg-surface-glass text-text-muted"}`, children: m.tag })
494
+ ]
495
+ },
496
+ m.id
497
+ ))
498
+ ] });
499
+ }
500
+
501
+ // src/components/playground/input-parts/InputToolbar.tsx
502
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
503
+ var InputToolbar = React4.memo(function InputToolbar2({
504
+ selectedModelId,
505
+ selectedModel,
506
+ providerGroups,
507
+ onModelSelect,
508
+ selectedShell,
509
+ onShellSelect,
510
+ showCanvas,
511
+ setShowCanvas,
512
+ prototypeBrand = "decido",
513
+ setPrototypeBrand,
514
+ intentEnabled,
515
+ onIntentToggle,
516
+ showIntentPanel,
517
+ onIntentPanelToggle
518
+ }) {
519
+ const [showOptionsMenu, setShowOptionsMenu] = useState4(false);
520
+ const [showShellMenu, setShowShellMenu] = useState4(false);
521
+ const optionsRef = useRef2(null);
522
+ const shellRef = useRef2(null);
523
+ const shellTypes = useMemo2(() => {
524
+ try {
525
+ return getRegisteredShellTypes();
526
+ } catch {
527
+ return [];
528
+ }
529
+ }, []);
530
+ const cycleBrand = () => {
531
+ if (!setPrototypeBrand) return;
532
+ const brands = ["startup_demo", "enterprise_demo", "industrial_demo"];
533
+ setPrototypeBrand(brands[(brands.indexOf(prototypeBrand) + 1) % brands.length]);
534
+ };
535
+ useEffect3(() => {
536
+ if (!showOptionsMenu) return;
537
+ const handler = (e) => {
538
+ if (optionsRef.current && !optionsRef.current.contains(e.target)) {
539
+ setShowOptionsMenu(false);
540
+ }
541
+ };
542
+ document.addEventListener("mousedown", handler);
543
+ return () => document.removeEventListener("mousedown", handler);
544
+ }, [showOptionsMenu]);
545
+ useEffect3(() => {
546
+ if (!showShellMenu) return;
547
+ const handler = (e) => {
548
+ if (shellRef.current && !shellRef.current.contains(e.target)) {
549
+ setShowShellMenu(false);
550
+ }
551
+ };
552
+ document.addEventListener("mousedown", handler);
553
+ return () => document.removeEventListener("mousedown", handler);
554
+ }, [showShellMenu]);
555
+ const shellMeta = selectedShell ? getShellMeta(selectedShell) : null;
556
+ const hasActiveTool = showCanvas || intentEnabled || showIntentPanel;
557
+ return /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center justify-center gap-0.5 sm:gap-1 xl:gap-2 relative flex-1 min-w-0", children: [
558
+ /* @__PURE__ */ jsx4(
559
+ AIModelSelector,
560
+ {
561
+ selectedModelId,
562
+ selectedModel,
563
+ providerGroups,
564
+ onSelect: onModelSelect
565
+ }
566
+ ),
567
+ /* @__PURE__ */ jsx4("div", { className: "w-px h-4 bg-surface-glass/80 mx-1" }),
568
+ /* @__PURE__ */ jsxs4("div", { ref: shellRef, className: "relative", children: [
569
+ /* @__PURE__ */ jsxs4(
570
+ "button",
571
+ {
572
+ type: "button",
573
+ onClick: (e) => {
574
+ e.stopPropagation();
575
+ setShowShellMenu(!showShellMenu);
576
+ setShowOptionsMenu(false);
577
+ },
578
+ className: `flex items-center gap-1 px-2 py-1.5 rounded-xl hover:bg-surface-glass transition-all text-[10px] font-mono
579
+ ${selectedShell ? "" : "text-text-muted hover:text-cyan-400"}`,
580
+ style: selectedShell && shellMeta ? { color: shellMeta.color } : void 0,
581
+ title: `Destino de salida: ${shellMeta?.label || selectedShell || "Ninguna (chat)"}`,
582
+ children: [
583
+ /* @__PURE__ */ jsx4("span", { className: "text-sm", children: shellMeta?.icon || "\u{1F4AC}" }),
584
+ /* @__PURE__ */ jsx4(ChevronDown3, { size: 10 })
585
+ ]
586
+ }
587
+ ),
588
+ showShellMenu && /* @__PURE__ */ jsxs4(
589
+ "div",
590
+ {
591
+ className: "absolute left-1/2 -translate-x-1/2 sm:left-auto sm:translate-x-0 w-[220px] bg-white/95 dark:bg-surface-tertiary border border-black/[0.06] dark:border-border-default\n rounded-2xl shadow-xl dark:shadow-2xl z-[100] max-h-[300px] overflow-y-auto custom-scrollbar flex flex-col backdrop-blur-xl",
592
+ style: { bottom: "100%", marginBottom: "0.6rem" },
593
+ children: [
594
+ /* @__PURE__ */ jsx4("div", { className: "px-3 py-2 text-[10px] text-text-muted font-mono uppercase tracking-wider bg-surface-base/50", children: "Destino de Salida" }),
595
+ /* @__PURE__ */ jsxs4("div", { className: "p-1 pb-2", children: [
596
+ /* @__PURE__ */ jsxs4(
597
+ "button",
598
+ {
599
+ type: "button",
600
+ onClick: (e) => {
601
+ e.stopPropagation();
602
+ onShellSelect(null);
603
+ setShowShellMenu(false);
604
+ },
605
+ className: `w-full text-left px-3 py-2.5 rounded-xl text-xs transition-colors font-mono flex items-center gap-2.5
606
+ ${!selectedShell ? "bg-cyan-500/10 text-cyan-400 font-semibold" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`,
607
+ children: [
608
+ /* @__PURE__ */ jsx4("span", { className: "text-base leading-none w-4 text-center", children: "\u{1F4AC}" }),
609
+ /* @__PURE__ */ jsx4("span", { children: "Ninguna (Chat)" })
610
+ ]
611
+ }
612
+ ),
613
+ /* @__PURE__ */ jsx4("div", { className: "h-px bg-border-subtle my-1 mx-1" }),
614
+ shellTypes.map((st) => {
615
+ const meta = getShellMeta(st);
616
+ return /* @__PURE__ */ jsxs4(
617
+ "button",
618
+ {
619
+ type: "button",
620
+ onClick: (e) => {
621
+ e.stopPropagation();
622
+ onShellSelect(st);
623
+ setShowShellMenu(false);
624
+ },
625
+ className: `w-full text-left px-3 py-2.5 mt-0.5 rounded-xl text-xs transition-colors font-mono flex items-center gap-2.5
626
+ ${selectedShell === st ? "text-text-primary font-semibold" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`,
627
+ style: selectedShell === st ? { background: `${meta.color}20` } : void 0,
628
+ children: [
629
+ /* @__PURE__ */ jsx4("span", { className: "text-base leading-none w-4 text-center", children: meta.icon }),
630
+ /* @__PURE__ */ jsx4("span", { className: "flex-1 truncate", children: meta.label }),
631
+ /* @__PURE__ */ jsx4("span", { className: "w-1.5 h-1.5 rounded-full shrink-0", style: { background: meta.color } })
632
+ ]
633
+ },
634
+ st
635
+ );
636
+ })
637
+ ] })
638
+ ]
639
+ }
640
+ )
641
+ ] }),
642
+ /* @__PURE__ */ jsx4("div", { className: "w-px h-4 bg-surface-glass/80 mx-1" }),
643
+ /* @__PURE__ */ jsxs4("div", { ref: optionsRef, className: "relative", children: [
644
+ /* @__PURE__ */ jsxs4(
645
+ "button",
646
+ {
647
+ type: "button",
648
+ onClick: (e) => {
649
+ e.stopPropagation();
650
+ setShowOptionsMenu(!showOptionsMenu);
651
+ setShowShellMenu(false);
652
+ },
653
+ className: `w-8 h-8 rounded-xl flex items-center justify-center transition-all relative
654
+ ${showOptionsMenu || hasActiveTool ? "text-text-primary bg-surface-glass" : "text-text-secondary hover:text-text-primary hover:bg-surface-glass"}`,
655
+ title: "Opciones del Agente",
656
+ children: [
657
+ /* @__PURE__ */ jsx4(Settings2, { size: 16 }),
658
+ hasActiveTool && /* @__PURE__ */ jsx4("div", { className: "absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-cyan-400" })
659
+ ]
660
+ }
661
+ ),
662
+ showOptionsMenu && /* @__PURE__ */ jsxs4(
663
+ "div",
664
+ {
665
+ className: "absolute left-1/2 -translate-x-1/2 sm:left-auto sm:translate-x-0 sm:-right-2 w-[240px] sm:w-[260px] bg-white/95 dark:bg-surface-tertiary border border-black/[0.06] dark:border-border-default\n rounded-2xl shadow-xl dark:shadow-2xl z-[100] max-h-[380px] overflow-y-auto custom-scrollbar flex flex-col backdrop-blur-xl",
666
+ style: { bottom: "100%", marginBottom: "0.6rem" },
667
+ children: [
668
+ /* @__PURE__ */ jsx4("div", { className: "px-3 py-2 text-[10px] text-text-muted font-mono uppercase tracking-wider bg-surface-base/50", children: "Agente y Contexto" }),
669
+ /* @__PURE__ */ jsxs4("div", { className: "p-1", children: [
670
+ /* @__PURE__ */ jsxs4(
671
+ "button",
672
+ {
673
+ type: "button",
674
+ onClick: (e) => {
675
+ e.stopPropagation();
676
+ onIntentToggle();
677
+ },
678
+ className: `w-full text-left px-3 py-2.5 rounded-xl text-xs transition-colors font-mono flex items-center justify-between group
679
+ ${intentEnabled ? "text-emerald-500 bg-emerald-500/10" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`,
680
+ children: [
681
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2.5", children: [
682
+ /* @__PURE__ */ jsx4(Brain, { size: 15 }),
683
+ /* @__PURE__ */ jsx4("span", { children: "Interpretar intenciones" })
684
+ ] }),
685
+ /* @__PURE__ */ jsx4("div", { className: `w-7 h-4 rounded-full flex items-center p-0.5 transition-colors border ${intentEnabled ? "bg-emerald-500 border-emerald-500/0" : "bg-surface-glass border-border-default group-hover:bg-border-subtle"}`, children: /* @__PURE__ */ jsx4("div", { className: `w-3 h-3 rounded-full bg-white transition-transform ${intentEnabled ? "translate-x-[12px]" : "translate-x-0"}` }) })
686
+ ]
687
+ }
688
+ ),
689
+ /* @__PURE__ */ jsxs4(
690
+ "button",
691
+ {
692
+ type: "button",
693
+ onClick: (e) => {
694
+ e.stopPropagation();
695
+ onIntentPanelToggle();
696
+ setShowOptionsMenu(false);
697
+ },
698
+ className: "w-full text-left px-3 py-2.5 mt-0.5 rounded-xl text-xs text-text-secondary hover:bg-surface-glass hover:text-cyan-500 transition-colors font-mono flex items-center gap-2.5",
699
+ children: [
700
+ /* @__PURE__ */ jsx4(Zap3, { size: 15 }),
701
+ /* @__PURE__ */ jsx4("span", { children: "Explorar cat\xE1logo" })
702
+ ]
703
+ }
704
+ )
705
+ ] }),
706
+ /* @__PURE__ */ jsx4("div", { className: "h-px bg-border-subtle" }),
707
+ /* @__PURE__ */ jsx4("div", { className: "px-3 py-2 text-[10px] text-text-muted font-mono uppercase tracking-wider bg-surface-base/50", children: "Entorno Visual" }),
708
+ /* @__PURE__ */ jsxs4("div", { className: "p-1 pb-2", children: [
709
+ setShowCanvas && /* @__PURE__ */ jsxs4(
710
+ "button",
711
+ {
712
+ type: "button",
713
+ onClick: (e) => {
714
+ e.stopPropagation();
715
+ setShowCanvas(!showCanvas);
716
+ setShowOptionsMenu(false);
717
+ },
718
+ className: `w-full text-left px-3 py-2.5 rounded-xl text-xs transition-colors font-mono flex items-center justify-between
719
+ ${showCanvas ? "text-primary bg-primary/10" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`,
720
+ children: [
721
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2.5", children: [
722
+ /* @__PURE__ */ jsx4(MonitorPlay, { size: 15 }),
723
+ /* @__PURE__ */ jsx4("span", { children: "Lienzo (Canvas)" })
724
+ ] }),
725
+ showCanvas && /* @__PURE__ */ jsx4("div", { className: "w-2 h-2 rounded-full bg-primary" })
726
+ ]
727
+ }
728
+ ),
729
+ setPrototypeBrand && /* @__PURE__ */ jsx4(
730
+ "button",
731
+ {
732
+ type: "button",
733
+ onClick: (e) => {
734
+ e.stopPropagation();
735
+ cycleBrand();
736
+ },
737
+ className: "w-full mt-0.5 text-left px-3 py-2.5 rounded-xl text-xs text-amber-500 hover:bg-surface-glass transition-colors font-mono flex items-center justify-between",
738
+ children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2.5", children: [
739
+ /* @__PURE__ */ jsx4(Code2, { size: 15 }),
740
+ /* @__PURE__ */ jsxs4("span", { children: [
741
+ "UI: ",
742
+ prototypeBrand
743
+ ] })
744
+ ] })
745
+ }
746
+ )
747
+ ] })
748
+ ]
749
+ }
750
+ )
751
+ ] })
752
+ ] });
753
+ });
754
+
755
+ // src/components/playground/input-parts/InputActions.tsx
756
+ import React5 from "react";
757
+ import { Send, Mic, Square, Sparkles as Sparkles2 } from "lucide-react";
758
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
759
+ var InputActions = React5.memo(function InputActions2({
760
+ inputHasText,
761
+ isGenerating,
762
+ isTranscribing,
763
+ onToggleTranscribing,
764
+ onSend,
765
+ setIsVoiceActive
766
+ }) {
767
+ if (isGenerating) {
768
+ return /* @__PURE__ */ jsx5("div", { className: "flex items-center gap-2 min-w-[100px] justify-end", children: /* @__PURE__ */ jsx5(
769
+ "button",
770
+ {
771
+ type: "button",
772
+ onClick: (e) => e.stopPropagation(),
773
+ className: "w-12 h-12 rounded-full text-text-primary bg-red-500/80 hover:bg-red-500 flex items-center justify-center\n transition-colors shadow-[0_0_15px_rgba(239,68,68,0.3)]",
774
+ title: "Detener generaci\xF3n",
775
+ children: /* @__PURE__ */ jsx5(Square, { size: 18 })
776
+ }
777
+ ) });
778
+ }
779
+ return /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 min-w-[100px] justify-end", children: [
780
+ /* @__PURE__ */ jsx5(
781
+ "button",
782
+ {
783
+ type: "button",
784
+ onClick: (e) => {
785
+ e.stopPropagation();
786
+ onToggleTranscribing();
787
+ },
788
+ className: `w-10 h-10 rounded-full flex items-center justify-center transition-all
789
+ ${isTranscribing ? "text-red-400 bg-red-400/10 animate-pulse" : "text-text-secondary hover:text-text-primary hover:bg-surface-glass"}`,
790
+ title: "Reconocimiento de voz (STT)",
791
+ children: /* @__PURE__ */ jsx5(Mic, { size: 20 })
792
+ }
793
+ ),
794
+ inputHasText ? /* @__PURE__ */ jsx5(
795
+ "button",
796
+ {
797
+ type: "button",
798
+ onClick: (e) => {
799
+ e.stopPropagation();
800
+ onSend();
801
+ },
802
+ className: "w-12 h-12 rounded-full text-text-inverse bg-cyan-400 hover:bg-cyan-300 flex items-center justify-center\n transition-colors shadow-[0_0_15px_rgba(34,211,238,0.3)]",
803
+ title: "Enviar",
804
+ children: /* @__PURE__ */ jsx5(Send, { size: 20, className: "ml-1" })
805
+ }
806
+ ) : setIsVoiceActive ? /* @__PURE__ */ jsxs5(
807
+ "button",
808
+ {
809
+ type: "button",
810
+ onClick: (e) => {
811
+ e.stopPropagation();
812
+ setIsVoiceActive(true);
813
+ },
814
+ className: "w-12 h-12 rounded-full text-cyan-400 bg-cyan-500/10 hover:bg-cyan-500/20 flex items-center justify-center\n border border-cyan-500/20 transition-all shadow-[0_0_15px_rgba(6,182,212,0.15)]\n hover:shadow-[0_0_20px_rgba(6,182,212,0.3)] group relative overflow-hidden",
815
+ title: "Hablar con la IA (Live)",
816
+ children: [
817
+ /* @__PURE__ */ jsx5(Sparkles2, { size: 22, className: "relative z-10 transition-transform group-hover:scale-110" }),
818
+ /* @__PURE__ */ jsx5("div", { className: "absolute inset-0 bg-linear-to-r from-cyan-400 to-purple-500 rounded-full opacity-0 group-hover:opacity-20 transition-opacity" })
819
+ ]
820
+ }
821
+ ) : null
822
+ ] });
823
+ });
824
+
825
+ // src/components/playground/input-parts/ResourceLibraryPanel.tsx
826
+ import React6, { useState as useState5, useMemo as useMemo3, useCallback as useCallback2 } from "react";
827
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "motion/react";
828
+ import { FolderOpen as FolderOpen2, Palette, Search as Search2, Tag, Clock, Trash2, X } from "lucide-react";
829
+ import { useShallow } from "zustand/react/shallow";
830
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
831
+ var TEMPLATES = [
832
+ {
833
+ id: "landing-saas",
834
+ title: "Landing SaaS",
835
+ category: "Marketing",
836
+ emoji: "\u{1F680}",
837
+ color: "#7c3aed",
838
+ description: "Hero, CTA, features",
839
+ html: '<section class="min-h-screen bg-linear-to-br from-violet-950 via-indigo-950 to-black text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Landing SaaS</h1></section>'
840
+ },
841
+ {
842
+ id: "dashboard",
843
+ title: "Dashboard",
844
+ category: "App",
845
+ emoji: "\u{1F4CA}",
846
+ color: "#06b6d4",
847
+ description: "M\xE9tricas, sidebar, cards",
848
+ html: '<div class="min-h-screen bg-gray-950 text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Dashboard</h1></div>'
849
+ },
850
+ {
851
+ id: "portfolio",
852
+ title: "Portfolio",
853
+ category: "Personal",
854
+ emoji: "\u{1F3A8}",
855
+ color: "#ec4899",
856
+ description: "Bio, proyectos, contacto",
857
+ html: '<div class="min-h-screen bg-gray-950 text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Portfolio</h1></div>'
858
+ },
859
+ {
860
+ id: "pricing",
861
+ title: "Pricing",
862
+ category: "Marketing",
863
+ emoji: "\u{1F4B3}",
864
+ color: "#10b981",
865
+ description: "3 planes, toggle anual",
866
+ html: '<section class="min-h-screen bg-gray-950 text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Pricing</h1></section>'
867
+ },
868
+ {
869
+ id: "login",
870
+ title: "Login",
871
+ category: "Auth",
872
+ emoji: "\u{1F510}",
873
+ color: "#f59e0b",
874
+ description: "Form, social, glassmorphism",
875
+ html: '<div class="min-h-screen bg-gray-950 text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Login</h1></div>'
876
+ },
877
+ {
878
+ id: "blog",
879
+ title: "Blog",
880
+ category: "Content",
881
+ emoji: "\u{1F4DD}",
882
+ color: "#3b82f6",
883
+ description: "Lista de art\xEDculos",
884
+ html: '<div class="min-h-screen bg-gray-950 text-white flex items-center justify-center"><h1 class="text-5xl font-bold">Blog</h1></div>'
885
+ }
886
+ ];
887
+ var ALL_CATEGORIES = ["All", "Marketing", "App", "Personal", "Auth", "Content", "Generated"];
888
+ var ResourceLibraryPanel = React6.memo(function ResourceLibraryPanel2({
889
+ isOpen,
890
+ onClose,
891
+ onLoadTemplate,
892
+ onOpenInstance
893
+ }) {
894
+ const [tab, setTab] = useState5("creations");
895
+ const [searchQuery, setSearchQuery] = useState5("");
896
+ const [selectedCategory, setSelectedCategory] = useState5("All");
897
+ const instances = useMorphInstanceStore(
898
+ useShallow((s) => Array.from(s.instances.values()))
899
+ );
900
+ const setActiveInstance = useMorphInstanceStore((s) => s.setActiveInstance);
901
+ const removeInstance = useMorphInstanceStore((s) => s.removeInstance);
902
+ const htmlInstances = useMemo3(
903
+ () => instances.filter((inst) => inst.data?.html || inst.shellType === "iframe").sort((a, b) => b.createdAt - a.createdAt),
904
+ [instances]
905
+ );
906
+ const filteredTemplates = useMemo3(() => {
907
+ return TEMPLATES.filter((t) => {
908
+ const matchSearch = !searchQuery || t.title.toLowerCase().includes(searchQuery.toLowerCase()) || t.description.toLowerCase().includes(searchQuery.toLowerCase());
909
+ const matchCat = selectedCategory === "All" || t.category === selectedCategory;
910
+ return matchSearch && matchCat;
911
+ });
912
+ }, [searchQuery, selectedCategory]);
913
+ const filteredCreations = useMemo3(() => {
914
+ if (!searchQuery) return htmlInstances;
915
+ const q = searchQuery.toLowerCase();
916
+ return htmlInstances.filter(
917
+ (inst) => inst.label.toLowerCase().includes(q) || inst.shellType.toLowerCase().includes(q)
918
+ );
919
+ }, [htmlInstances, searchQuery]);
920
+ const handleLoadInstance = useCallback2((inst) => {
921
+ setActiveInstance(inst.id);
922
+ useLayoutStore.getState().setActiveTab(`morph-${inst.id}`);
923
+ onOpenInstance(inst.id);
924
+ onClose();
925
+ }, [setActiveInstance, onOpenInstance, onClose]);
926
+ const handleLoadTemplate = useCallback2((t) => {
927
+ onLoadTemplate(t.html);
928
+ onClose();
929
+ }, [onLoadTemplate, onClose]);
930
+ const timeAgo = (ts) => {
931
+ const diff = Date.now() - ts;
932
+ const mins = Math.floor(diff / 6e4);
933
+ if (mins < 1) return "ahora";
934
+ if (mins < 60) return `${mins}m`;
935
+ const hrs = Math.floor(mins / 60);
936
+ if (hrs < 24) return `${hrs}h`;
937
+ return `${Math.floor(hrs / 24)}d`;
938
+ };
939
+ return /* @__PURE__ */ jsx6(AnimatePresence2, { children: isOpen && /* @__PURE__ */ jsx6(
940
+ motion2.div,
941
+ {
942
+ initial: { opacity: 0, y: 8 },
943
+ animate: { opacity: 1, y: 0 },
944
+ exit: { opacity: 0, y: 8 },
945
+ className: "absolute bottom-full left-0 right-0 z-50 mb-2",
946
+ children: /* @__PURE__ */ jsxs6("div", { className: "bg-white/95 dark:bg-[#1a1a2e] border border-black/[0.08] dark:border-border-default\n rounded-2xl shadow-xl dark:shadow-2xl overflow-hidden max-h-[420px] flex flex-col backdrop-blur-xl", children: [
947
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-4 py-3 border-b border-black/[0.06] dark:border-border-subtle shrink-0", children: [
948
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
949
+ /* @__PURE__ */ jsx6("h3", { className: "text-sm font-bold text-text-primary", children: "Librer\xEDa" }),
950
+ /* @__PURE__ */ jsxs6("div", { className: "flex bg-black/[0.04] dark:bg-surface-glass rounded-lg p-0.5", children: [
951
+ /* @__PURE__ */ jsxs6(
952
+ "button",
953
+ {
954
+ onClick: () => setTab("creations"),
955
+ className: `px-3 py-1.5 text-[11px] font-semibold rounded-md transition-all flex items-center gap-1.5
956
+ ${tab === "creations" ? "bg-white dark:bg-surface-tertiary text-text-primary shadow-sm" : "text-text-muted hover:text-text-secondary"}`,
957
+ children: [
958
+ /* @__PURE__ */ jsx6(FolderOpen2, { size: 12 }),
959
+ " Mis Creaciones",
960
+ htmlInstances.length > 0 && /* @__PURE__ */ jsx6("span", { className: "text-[9px] bg-cyan-500/20 text-cyan-600 dark:text-cyan-400 px-1.5 py-0.5 rounded-full font-bold", children: htmlInstances.length })
961
+ ]
962
+ }
963
+ ),
964
+ /* @__PURE__ */ jsxs6(
965
+ "button",
966
+ {
967
+ onClick: () => setTab("templates"),
968
+ className: `px-3 py-1.5 text-[11px] font-semibold rounded-md transition-all flex items-center gap-1.5
969
+ ${tab === "templates" ? "bg-white dark:bg-surface-tertiary text-text-primary shadow-sm" : "text-text-muted hover:text-text-secondary"}`,
970
+ children: [
971
+ /* @__PURE__ */ jsx6(Palette, { size: 12 }),
972
+ " Templates"
973
+ ]
974
+ }
975
+ )
976
+ ] })
977
+ ] }),
978
+ /* @__PURE__ */ jsx6("button", { onClick: onClose, className: "w-7 h-7 rounded-lg text-text-muted hover:text-text-primary hover:bg-black/[0.04] dark:hover:bg-surface-glass flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx6(X, { size: 14 }) })
979
+ ] }),
980
+ /* @__PURE__ */ jsxs6("div", { className: "px-4 py-2 border-b border-black/[0.04] dark:border-border-subtle shrink-0 flex items-center gap-2", children: [
981
+ /* @__PURE__ */ jsxs6("div", { className: "flex-1 relative", children: [
982
+ /* @__PURE__ */ jsx6(Search2, { size: 13, className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-text-muted" }),
983
+ /* @__PURE__ */ jsx6(
984
+ "input",
985
+ {
986
+ type: "text",
987
+ placeholder: "Buscar...",
988
+ value: searchQuery,
989
+ onChange: (e) => setSearchQuery(e.target.value),
990
+ className: "w-full pl-8 pr-3 py-1.5 bg-black/[0.03] dark:bg-surface-glass border border-transparent focus:border-cyan-500/30\n rounded-lg text-xs text-text-primary placeholder-text-muted outline-hidden transition"
991
+ }
992
+ )
993
+ ] }),
994
+ tab === "templates" && /* @__PURE__ */ jsx6("div", { className: "flex gap-1 overflow-x-auto no-scrollbar", children: ALL_CATEGORIES.filter((c) => c !== "Generated").map((cat) => /* @__PURE__ */ jsx6(
995
+ "button",
996
+ {
997
+ onClick: () => setSelectedCategory(cat),
998
+ className: `px-2 py-1 text-[10px] font-semibold rounded-md whitespace-nowrap transition-all
999
+ ${selectedCategory === cat ? "bg-cyan-500/15 text-cyan-600 dark:text-cyan-400" : "text-text-muted hover:text-text-secondary hover:bg-black/[0.04] dark:hover:bg-surface-glass"}`,
1000
+ children: cat
1001
+ },
1002
+ cat
1003
+ )) })
1004
+ ] }),
1005
+ /* @__PURE__ */ jsx6("div", { className: "flex-1 overflow-y-auto px-3 py-3 custom-scrollbar", children: /* @__PURE__ */ jsx6(AnimatePresence2, { mode: "wait", children: tab === "creations" ? /* @__PURE__ */ jsx6(motion2.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: filteredCreations.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
1006
+ /* @__PURE__ */ jsx6(FolderOpen2, { size: 32, className: "text-text-muted/30 mb-3" }),
1007
+ /* @__PURE__ */ jsx6("p", { className: "text-sm text-text-muted", children: "Sin creaciones a\xFAn" }),
1008
+ /* @__PURE__ */ jsx6("p", { className: "text-[10px] text-text-muted/60 mt-1", children: "Genera una p\xE1gina desde el chat para verla aqu\xED" })
1009
+ ] }) : /* @__PURE__ */ jsx6("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-2", children: filteredCreations.map((inst, i) => /* @__PURE__ */ jsxs6(
1010
+ motion2.button,
1011
+ {
1012
+ initial: { opacity: 0, y: 6 },
1013
+ animate: { opacity: 1, y: 0 },
1014
+ transition: { delay: i * 0.03 },
1015
+ onClick: () => handleLoadInstance(inst),
1016
+ className: "group relative bg-black/[0.02] dark:bg-surface-glass border border-black/[0.06] dark:border-border-subtle\n hover:border-cyan-500/30 rounded-xl p-3 text-left transition-all hover:shadow-md overflow-hidden",
1017
+ children: [
1018
+ /* @__PURE__ */ jsx6("div", { className: "h-16 rounded-lg bg-gradient-to-br from-cyan-500/10 to-purple-500/10 dark:from-cyan-500/5 dark:to-purple-500/5\n mb-2 flex items-center justify-center overflow-hidden border border-black/[0.04] dark:border-border-subtle", children: /* @__PURE__ */ jsx6("span", { className: "text-lg opacity-50", children: "\u{1F310}" }) }),
1019
+ /* @__PURE__ */ jsx6("h4", { className: "text-[11px] font-semibold text-text-primary truncate", children: inst.label }),
1020
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5 mt-1", children: [
1021
+ /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1 text-[9px] text-text-muted", children: [
1022
+ /* @__PURE__ */ jsx6(Clock, { size: 9 }),
1023
+ " ",
1024
+ timeAgo(inst.createdAt)
1025
+ ] }),
1026
+ /* @__PURE__ */ jsxs6("span", { className: "flex items-center gap-1 text-[9px] px-1.5 py-0.5 rounded bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 font-semibold", children: [
1027
+ /* @__PURE__ */ jsx6(Tag, { size: 8 }),
1028
+ " ",
1029
+ inst.shellType
1030
+ ] })
1031
+ ] }),
1032
+ /* @__PURE__ */ jsx6("div", { className: "absolute top-1.5 right-1.5 opacity-0 group-hover:opacity-100 transition-opacity flex gap-1", children: /* @__PURE__ */ jsx6(
1033
+ "button",
1034
+ {
1035
+ onClick: (e) => {
1036
+ e.stopPropagation();
1037
+ removeInstance(inst.id);
1038
+ },
1039
+ className: "w-5 h-5 rounded bg-red-500/10 hover:bg-red-500/20 text-red-400 flex items-center justify-center",
1040
+ title: "Eliminar",
1041
+ children: /* @__PURE__ */ jsx6(Trash2, { size: 10 })
1042
+ }
1043
+ ) })
1044
+ ]
1045
+ },
1046
+ inst.id
1047
+ )) }) }, "creations") : /* @__PURE__ */ jsx6(motion2.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx6("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-2", children: filteredTemplates.map((t, i) => /* @__PURE__ */ jsxs6(
1048
+ motion2.button,
1049
+ {
1050
+ initial: { opacity: 0, y: 6 },
1051
+ animate: { opacity: 1, y: 0 },
1052
+ transition: { delay: i * 0.03 },
1053
+ onClick: () => handleLoadTemplate(t),
1054
+ className: "group bg-black/[0.02] dark:bg-surface-glass border border-black/[0.06] dark:border-border-subtle\n hover:border-opacity-50 rounded-xl p-3 text-left transition-all hover:shadow-md overflow-hidden",
1055
+ style: { "--hover-color": t.color },
1056
+ children: [
1057
+ /* @__PURE__ */ jsx6(
1058
+ "div",
1059
+ {
1060
+ className: "h-14 rounded-lg mb-2 flex items-center justify-center transition-all group-hover:scale-[1.02]",
1061
+ style: { background: `linear-gradient(135deg, ${t.color}20, ${t.color}08)` },
1062
+ children: /* @__PURE__ */ jsx6("span", { className: "text-2xl", children: t.emoji })
1063
+ }
1064
+ ),
1065
+ /* @__PURE__ */ jsx6("h4", { className: "text-[11px] font-semibold text-text-primary", children: t.title }),
1066
+ /* @__PURE__ */ jsx6("p", { className: "text-[9px] text-text-muted mt-0.5", children: t.description }),
1067
+ /* @__PURE__ */ jsx6(
1068
+ "span",
1069
+ {
1070
+ className: "inline-block mt-1.5 text-[9px] font-semibold px-1.5 py-0.5 rounded",
1071
+ style: { background: `${t.color}15`, color: t.color },
1072
+ children: t.category
1073
+ }
1074
+ )
1075
+ ]
1076
+ },
1077
+ t.id
1078
+ )) }) }, "templates") }) })
1079
+ ] })
1080
+ }
1081
+ ) });
1082
+ });
1083
+
1084
+ // src/components/playground/PlaygroundFloatingInput.tsx
1085
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1086
+ var PlaygroundFloatingInput = ({
1087
+ onSend,
1088
+ isGenerating,
1089
+ isVoiceActive = false,
1090
+ setIsVoiceActive,
1091
+ VoiceWidget,
1092
+ dynamicPersona,
1093
+ setSuggestions,
1094
+ selectedVoice,
1095
+ showCanvas,
1096
+ setShowCanvas,
1097
+ prototypeBrand = "decido",
1098
+ setPrototypeBrand
1099
+ }) => {
1100
+ const [inputValue, setInputValue] = useState6("");
1101
+ const [isTranscribing, setIsTranscribing] = useState6(false);
1102
+ const [slashMenuOpen, setSlashMenuOpen] = useState6(false);
1103
+ const [slashMenuIndex, setSlashMenuIndex] = useState6(0);
1104
+ const [showIntentPanel, setShowIntentPanel] = useState6(false);
1105
+ const [showLibrary, setShowLibrary] = useState6(false);
1106
+ const [intentEnabled, setIntentEnabled] = useState6(true);
1107
+ const [selectedShell, setSelectedShell] = useState6(
1108
+ () => localStorage.getItem("decido_selected_shell")
1109
+ );
1110
+ const inputRef = useRef3(null);
1111
+ const { selectedModelId, selectedModel, providerGroups, selectModel } = useAIModelSelector();
1112
+ useEffect4(() => {
1113
+ if (typeof window !== "undefined" && window.__DECIDO__) {
1114
+ window.__DECIDO__.intentEnabled = intentEnabled;
1115
+ }
1116
+ }, [intentEnabled]);
1117
+ const activeChatId = usePlaygroundStore((s) => s.activeChatId);
1118
+ useEffect4(() => {
1119
+ if (!activeChatId) return;
1120
+ usePlaygroundStore.setState((s) => ({
1121
+ chatInstances: s.chatInstances.map(
1122
+ (c) => c.id === activeChatId ? { ...c, model: selectedModelId } : c
1123
+ )
1124
+ }));
1125
+ }, [selectedModelId, activeChatId]);
1126
+ useEffect4(() => {
1127
+ if (selectedShell) localStorage.setItem("decido_selected_shell", selectedShell);
1128
+ else localStorage.removeItem("decido_selected_shell");
1129
+ if (typeof window !== "undefined" && window.__DECIDO__) {
1130
+ window.__DECIDO__.selectedShell = selectedShell;
1131
+ }
1132
+ if (!activeChatId) return;
1133
+ usePlaygroundStore.setState((s) => ({
1134
+ chatInstances: s.chatInstances.map(
1135
+ (c) => c.id === activeChatId ? { ...c, shellType: selectedShell || void 0 } : c
1136
+ )
1137
+ }));
1138
+ if (selectedShell) {
1139
+ const meta = getShellMeta(selectedShell);
1140
+ useMorphInstanceStore.getState().upsertInstance({
1141
+ id: activeChatId,
1142
+ sourceChatId: activeChatId,
1143
+ shellType: selectedShell,
1144
+ label: meta.label || selectedShell,
1145
+ data: {}
1146
+ });
1147
+ } else {
1148
+ useMorphInstanceStore.getState().removeInstance(activeChatId);
1149
+ }
1150
+ }, [selectedShell, activeChatId]);
1151
+ const activeInstance = usePlaygroundStore((s) => s.chatInstances.find((c) => c.id === s.activeChatId));
1152
+ useEffect4(() => {
1153
+ if (!activeInstance) return;
1154
+ if (activeInstance.model && activeInstance.model !== selectedModelId) {
1155
+ selectModel(activeInstance.model);
1156
+ }
1157
+ const instanceShell = activeInstance.shellType || null;
1158
+ if (instanceShell !== selectedShell) {
1159
+ setSelectedShell(instanceShell);
1160
+ }
1161
+ }, [activeChatId]);
1162
+ const { primaryIntent } = useIntentLens(intentEnabled ? inputValue : "");
1163
+ const seeds = useSuggestionsStore((s) => s.seeds);
1164
+ const generated = useSuggestionsStore((s) => s.generated);
1165
+ const pluginSuggestions = useSuggestionsStore((s) => s.pluginSuggestions);
1166
+ const allSuggestions = useMemo4(() => {
1167
+ const plugin = Object.values(pluginSuggestions).flat();
1168
+ return [...generated, ...seeds, ...plugin];
1169
+ }, [generated, seeds, pluginSuggestions]);
1170
+ const [placeholderIndex, setPlaceholderIndex] = useState6(0);
1171
+ useEffect4(() => {
1172
+ if (allSuggestions.length <= 1) return;
1173
+ const timer = setInterval(() => setPlaceholderIndex((i) => (i + 1) % allSuggestions.length), 4e3);
1174
+ return () => clearInterval(timer);
1175
+ }, [allSuggestions.length]);
1176
+ const rotatingPlaceholder = allSuggestions.length > 0 ? allSuggestions[placeholderIndex % allSuggestions.length] : "Escribe / para comandos... (Shift+Enter nueva l\xEDnea)";
1177
+ useEffect4(() => {
1178
+ const ta = inputRef.current;
1179
+ if (ta) {
1180
+ ta.style.height = "auto";
1181
+ ta.style.height = `${Math.min(ta.scrollHeight, 200)}px`;
1182
+ }
1183
+ }, [inputValue]);
1184
+ const timelines = useTimelineStore((s) => s.timelines);
1185
+ const blueprintLibrary = useTimelineStore((s) => s.blueprintLibrary);
1186
+ const uiComponents = useUIComponentStore((s) => s.components);
1187
+ const slashCommands = useMemo4(() => {
1188
+ const flowList = Object.keys(timelines).map((id) => ({ id, label: id, description: timelines[id]?.name || id }));
1189
+ const bpList = Object.entries(blueprintLibrary).map(([id, bp]) => ({ id, label: bp.name || id, description: `v${bp.metadata?.version || "?"} \xB7 ${bp.metadata?.tags?.join(", ") || ""}` }));
1190
+ const uiList = Object.values(uiComponents).map((c) => ({ id: c.id, label: c.name, description: c.category }));
1191
+ return [
1192
+ { command: "/run", label: "Run Flow", description: "Ejecutar un flujo", icon: "\u25B6", subCommands: flowList },
1193
+ { command: "/flows", label: "List Flows", description: "Ver todos los flujos", icon: "\u{1F4CB}" },
1194
+ { command: "/blueprints", label: "Blueprints", description: "Subflujos disponibles", icon: "\u{1F517}", subCommands: bpList },
1195
+ { command: "/ui", label: "UI Components", description: "Biblioteca de componentes", icon: "\u{1F3A8}", subCommands: uiList },
1196
+ { command: "/reset", label: "Reset Engine", description: "Reiniciar el motor", icon: "\u{1F504}" },
1197
+ { command: "/tts", label: "Voice Synthesis", description: "Generar audio TTS con Kokoro", icon: "\u{1F399}\uFE0F" }
1198
+ ];
1199
+ }, [timelines, blueprintLibrary, uiComponents]);
1200
+ const filteredCommands = useMemo4(() => {
1201
+ if (!inputValue.startsWith("/")) return [];
1202
+ const parts = inputValue.split(" ");
1203
+ const cmd = parts[0].toLowerCase();
1204
+ const arg = parts.slice(1).join(" ").toLowerCase();
1205
+ const matched = slashCommands.find((c) => c.command === cmd);
1206
+ if (matched?.subCommands) {
1207
+ return matched.subCommands.filter((sc) => !arg || sc.id.toLowerCase().includes(arg) || sc.label.toLowerCase().includes(arg)).map((sc) => ({ ...sc, type: "sub", parentCommand: cmd }));
1208
+ }
1209
+ return slashCommands.filter((c) => c.command.startsWith(cmd)).map((c) => ({ id: c.command, label: c.label, description: c.description, icon: c.icon, type: "command", subCommands: c.subCommands }));
1210
+ }, [inputValue, slashCommands]);
1211
+ useEffect4(() => {
1212
+ setSlashMenuOpen(inputValue.startsWith("/") && filteredCommands.length > 0);
1213
+ setSlashMenuIndex(0);
1214
+ }, [inputValue, filteredCommands.length]);
1215
+ const handleSlashSelect = (item) => {
1216
+ if (item.type === "command") {
1217
+ if (item.subCommands) {
1218
+ setInputValue(item.id + " ");
1219
+ inputRef.current?.focus();
1220
+ } else {
1221
+ onSend(item.id);
1222
+ setInputValue("");
1223
+ setSlashMenuOpen(false);
1224
+ }
1225
+ } else if (item.type === "sub") {
1226
+ onSend(`${item.parentCommand} ${item.id}`);
1227
+ setInputValue("");
1228
+ setSlashMenuOpen(false);
1229
+ }
1230
+ };
1231
+ const handleKeyDown = (e) => {
1232
+ if (slashMenuOpen) {
1233
+ if (e.key === "ArrowDown") {
1234
+ e.preventDefault();
1235
+ setSlashMenuIndex((i) => Math.min(i + 1, filteredCommands.length - 1));
1236
+ } else if (e.key === "ArrowUp") {
1237
+ e.preventDefault();
1238
+ setSlashMenuIndex((i) => Math.max(i - 1, 0));
1239
+ } else if (e.key === "Enter" && filteredCommands[slashMenuIndex]) {
1240
+ e.preventDefault();
1241
+ handleSlashSelect(filteredCommands[slashMenuIndex]);
1242
+ } else if (e.key === "Escape") setSlashMenuOpen(false);
1243
+ return;
1244
+ }
1245
+ if (e.key === "Enter" && !e.shiftKey) {
1246
+ e.preventDefault();
1247
+ if (inputValue.trim() && !isGenerating) {
1248
+ onSend(inputValue.trim());
1249
+ setInputValue("");
1250
+ }
1251
+ }
1252
+ };
1253
+ const handleSubmit = (e) => {
1254
+ e.preventDefault();
1255
+ if (inputValue.trim() && !isGenerating) {
1256
+ onSend(inputValue.trim());
1257
+ setInputValue("");
1258
+ }
1259
+ };
1260
+ const handleSendClick = useCallback3(() => {
1261
+ if (inputValue.trim() && !isGenerating) {
1262
+ onSend(inputValue.trim());
1263
+ setInputValue("");
1264
+ }
1265
+ }, [inputValue, isGenerating, onSend]);
1266
+ return /* @__PURE__ */ jsxs7(motion3.div, { layout: true, className: `w-full relative ${isVoiceActive ? "h-64" : ""}`, children: [
1267
+ /* @__PURE__ */ jsx7(SlashCommandMenu, { isOpen: slashMenuOpen, items: filteredCommands, activeIndex: slashMenuIndex, onSelect: handleSlashSelect, onHover: setSlashMenuIndex }),
1268
+ /* @__PURE__ */ jsx7(AnimatePresence3, { children: showIntentPanel && /* @__PURE__ */ jsx7(motion3.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 10 }, className: "absolute bottom-full left-0 right-0 mb-2 z-50", children: /* @__PURE__ */ jsx7(IntentCatalogPanel, { onSelect: (text) => {
1269
+ setInputValue(text);
1270
+ setShowIntentPanel(false);
1271
+ inputRef.current?.focus();
1272
+ } }) }) }),
1273
+ /* @__PURE__ */ jsx7(
1274
+ ResourceLibraryPanel,
1275
+ {
1276
+ isOpen: showLibrary,
1277
+ onClose: () => setShowLibrary(false),
1278
+ onLoadTemplate: (html) => {
1279
+ onSend(`/template ${html.slice(0, 100)}`);
1280
+ },
1281
+ onOpenInstance: (id) => {
1282
+ useMorphInstanceStore.getState().setActiveInstance(id);
1283
+ if (setShowCanvas) setShowCanvas(true);
1284
+ }
1285
+ }
1286
+ ),
1287
+ /* @__PURE__ */ jsx7("div", { className: `bg-white/80 dark:bg-surface-tertiary border border-black/[0.08] dark:border-border-default rounded-4xl flex flex-col p-2 shadow-sm dark:shadow-2xl transition-all duration-300
1288
+ ${isVoiceActive ? "h-full border-cyan-500/30" : "focus-within:border-black/[0.12] dark:focus-within:border-border-strong focus-within:shadow-md dark:focus-within:shadow-lg"}`, children: /* @__PURE__ */ jsx7(AnimatePresence3, { mode: "wait", children: !isVoiceActive ? /* @__PURE__ */ jsxs7(
1289
+ motion3.div,
1290
+ {
1291
+ initial: { opacity: 0 },
1292
+ animate: { opacity: 1 },
1293
+ exit: { opacity: 0 },
1294
+ className: "flex flex-col w-full h-full cursor-text",
1295
+ onClick: (e) => {
1296
+ const ta = e.currentTarget.querySelector("textarea");
1297
+ if (ta && e.target === e.currentTarget) ta.focus();
1298
+ },
1299
+ children: [
1300
+ /* @__PURE__ */ jsxs7("form", { onSubmit: handleSubmit, className: "relative flex items-center px-3 sm:px-4 py-2 sm:py-3 min-h-[48px] sm:min-h-[60px]", children: [
1301
+ /* @__PURE__ */ jsx7(
1302
+ "textarea",
1303
+ {
1304
+ ref: inputRef,
1305
+ placeholder: isTranscribing ? "Escuchando..." : rotatingPlaceholder,
1306
+ value: inputValue,
1307
+ onChange: (e) => setInputValue(e.target.value),
1308
+ onKeyDown: handleKeyDown,
1309
+ rows: 1,
1310
+ className: "w-full bg-transparent text-text-primary placeholder-text-muted outline-hidden text-sm sm:text-[15px] leading-relaxed resize-none",
1311
+ disabled: isGenerating,
1312
+ style: { maxHeight: "200px" }
1313
+ }
1314
+ ),
1315
+ primaryIntent && !slashMenuOpen && /* @__PURE__ */ jsxs7(
1316
+ "div",
1317
+ {
1318
+ className: "absolute right-4 top-1/2 -translate-y-1/2 flex items-center gap-1 px-2 py-1 rounded-full text-[10px] font-semibold border",
1319
+ style: { background: `${primaryIntent.color}15`, borderColor: `${primaryIntent.color}30`, color: primaryIntent.color },
1320
+ children: [
1321
+ /* @__PURE__ */ jsx7("span", { children: primaryIntent.icon }),
1322
+ /* @__PURE__ */ jsx7("span", { children: primaryIntent.label })
1323
+ ]
1324
+ }
1325
+ )
1326
+ ] }),
1327
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center justify-between px-2 pb-1 relative z-10 w-full gap-y-2", children: [
1328
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1 shrink-0", children: [
1329
+ /* @__PURE__ */ jsx7(
1330
+ "button",
1331
+ {
1332
+ type: "button",
1333
+ onClick: () => {
1334
+ setShowLibrary(!showLibrary);
1335
+ setShowIntentPanel(false);
1336
+ },
1337
+ className: `w-10 h-10 rounded-full flex items-center justify-center transition-colors
1338
+ ${showLibrary ? "text-cyan-400 bg-cyan-500/10" : "text-text-secondary hover:text-text-primary hover:bg-surface-glass"}`,
1339
+ title: "Librer\xEDa de recursos",
1340
+ children: /* @__PURE__ */ jsx7(FolderOpen3, { size: 20 })
1341
+ }
1342
+ ),
1343
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "w-10 h-10 rounded-full text-text-secondary hover:text-text-primary hover:bg-surface-glass flex items-center justify-center transition-colors", title: "Adjuntar", children: /* @__PURE__ */ jsx7(Paperclip, { size: 20 }) })
1344
+ ] }),
1345
+ /* @__PURE__ */ jsx7(
1346
+ InputToolbar,
1347
+ {
1348
+ selectedModelId,
1349
+ selectedModel,
1350
+ providerGroups,
1351
+ onModelSelect: selectModel,
1352
+ selectedShell,
1353
+ onShellSelect: setSelectedShell,
1354
+ showCanvas,
1355
+ setShowCanvas,
1356
+ prototypeBrand,
1357
+ setPrototypeBrand,
1358
+ intentEnabled,
1359
+ onIntentToggle: () => setIntentEnabled(!intentEnabled),
1360
+ showIntentPanel,
1361
+ onIntentPanelToggle: () => setShowIntentPanel(!showIntentPanel)
1362
+ }
1363
+ ),
1364
+ /* @__PURE__ */ jsx7(
1365
+ InputActions,
1366
+ {
1367
+ inputHasText: !!inputValue.trim(),
1368
+ isGenerating,
1369
+ isTranscribing,
1370
+ onToggleTranscribing: () => setIsTranscribing(!isTranscribing),
1371
+ onSend: handleSendClick,
1372
+ setIsVoiceActive
1373
+ }
1374
+ )
1375
+ ] })
1376
+ ]
1377
+ },
1378
+ "text-mode"
1379
+ ) : /* @__PURE__ */ jsx7(VoiceLiveMode, { VoiceWidget, dynamicPersona, setSuggestions, selectedVoice, onClose: () => setIsVoiceActive?.(false) }) }) }),
1380
+ /* @__PURE__ */ jsx7("div", { className: "text-center mt-3", children: /* @__PURE__ */ jsx7("p", { className: "text-[10px] md:text-[11px] text-text-muted font-medium tracking-wide", children: "Decido puede equivocarse. Considera revisar la informaci\xF3n importante." }) })
1381
+ ] });
1382
+ };
1383
+
1384
+ // src/components/playground/PlaygroundChat.tsx
1385
+ import { ChatProvider, ChatMessageRow, ChatExportMenu } from "@decido/chat";
1386
+
1387
+ // src/components/chat-extensions/chatSlashCommands.ts
1388
+ import { useTimelineStore as useTimelineStore2 } from "@decido/engine";
1389
+ import { useEngineStore } from "@decido/engine";
1390
+ function handleSlashCommand(input, ctx) {
1391
+ if (!input.startsWith("/")) return false;
1392
+ const parts = input.split(" ");
1393
+ const cmd = parts[0].toLowerCase();
1394
+ const arg = parts.slice(1).join(" ");
1395
+ switch (cmd) {
1396
+ case "/run": {
1397
+ if (!arg) return false;
1398
+ const timelines = useTimelineStore2.getState().timelines;
1399
+ if (timelines[arg]) {
1400
+ ctx.setPrototypeBrand(arg);
1401
+ useEngineStore.getState().resetEngine();
1402
+ ctx.addChatMessage({ type: "text", sender: "system", text: `\u25B6\uFE0F Ejecutando flujo: **${arg}**`, actorId: "system" });
1403
+ setTimeout(() => {
1404
+ useEngineStore.getState().dispatchEvent({ type: "SYSTEM_START" });
1405
+ }, 100);
1406
+ } else {
1407
+ ctx.addChatMessage({ type: "alert", sender: "system", text: `Flujo "${arg}" no encontrado. Usa /flows para ver los disponibles.`, actorId: "system" });
1408
+ }
1409
+ return true;
1410
+ }
1411
+ case "/flows": {
1412
+ const flowIds = Object.keys(useTimelineStore2.getState().timelines);
1413
+ ctx.addChatMessage({ type: "text", sender: "system", text: `\u{1F4CB} Flujos disponibles:
1414
+ ${flowIds.map((id) => `\u2022 ${id}`).join("\n")}
1415
+
1416
+ Usa /run [nombre] para ejecutar.`, actorId: "system" });
1417
+ return true;
1418
+ }
1419
+ case "/blueprints": {
1420
+ const bps = Object.entries(useTimelineStore2.getState().blueprintLibrary);
1421
+ ctx.addChatMessage({ type: "text", sender: "system", text: `\u{1F4E6} Blueprints:
1422
+ ${bps.map(([id, bp]) => `\u2022 ${id} \u2014 ${bp.name || "?"}`).join("\n") || "Ninguno registrado."}`, actorId: "system" });
1423
+ return true;
1424
+ }
1425
+ case "/ui": {
1426
+ if (arg) {
1427
+ const comp = useUIComponentStore.getState().components[arg];
1428
+ if (comp) ctx.addChatMessage({ type: "ui-artifact", sender: "agent", text: `\u{1F3A8} ${comp.name}`, actorId: "system", uiSchema: JSON.stringify(comp.schema) });
1429
+ else ctx.addChatMessage({ type: "alert", sender: "system", text: `Componente "${arg}" no encontrado.`, actorId: "system" });
1430
+ } else {
1431
+ const uiComps = Object.values(useUIComponentStore.getState().components);
1432
+ ctx.addChatMessage({ type: "text", sender: "system", text: `\u{1F3A8} UI Components:
1433
+ ${uiComps.map((c) => `\u2022 ${c.name} (${c.category}) \u2014 ${c.source}`).join("\n") || "Ninguno."}
1434
+
1435
+ Usa /ui [id] para renderizar.`, actorId: "system" });
1436
+ }
1437
+ return true;
1438
+ }
1439
+ case "/tts": {
1440
+ if (!arg) {
1441
+ ctx.addChatMessage({ type: "alert", sender: "system", text: `Debes indicar el texto a leer. Ejemplo:
1442
+ /tts Hola mundo`, actorId: "system" });
1443
+ return true;
1444
+ }
1445
+ ctx.addChatMessage({ type: "text", sender: "system", text: `\u{1F399}\uFE0F Generando audio neuronal para:
1446
+ "${arg}"...`, actorId: "system" });
1447
+ import("@decido/kernel-bridge").then(({ kernel }) => {
1448
+ kernel.execute("call_mcp_tool", {
1449
+ server_name: "Kokoro TTS",
1450
+ tool_name: "generate_tts",
1451
+ arguments: { text: arg, voice: "em_alex", speed: 1, lang: "es", return_base64: true }
1452
+ }).then((res) => {
1453
+ const messageText = typeof res === "string" ? res : JSON.stringify(res);
1454
+ if (messageText.includes("DATA_URI:")) {
1455
+ const dataUri = messageText.split("DATA_URI:")[1].trim();
1456
+ ctx.addChatMessage({
1457
+ type: "audio",
1458
+ sender: "system",
1459
+ text: `\u2705 Emisi\xF3n de voz generada con \xE9xito`,
1460
+ audioSrc: dataUri,
1461
+ actorId: "system"
1462
+ });
1463
+ } else {
1464
+ ctx.addChatMessage({ type: "alert", sender: "system", text: `La respuesta no incluy\xF3 un URI v\xE1lido:
1465
+ ${messageText}`, actorId: "system" });
1466
+ }
1467
+ }).catch((err) => {
1468
+ ctx.addChatMessage({ type: "alert", sender: "system", text: `\u274C Error de TTS: ${String(err)}`, actorId: "system" });
1469
+ });
1470
+ });
1471
+ return true;
1472
+ }
1473
+ case "/reset": {
1474
+ useEngineStore.getState().resetEngine();
1475
+ ctx.addChatMessage({ type: "text", sender: "system", text: "\u23F9 Motor reiniciado.", actorId: "system" });
1476
+ return true;
1477
+ }
1478
+ default:
1479
+ ctx.addChatMessage({ type: "alert", sender: "system", text: `Comando desconocido: ${cmd}`, actorId: "system" });
1480
+ return true;
1481
+ }
1482
+ }
1483
+
1484
+ // src/components/playground/PlaygroundChat.tsx
1485
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1486
+ var PlaygroundChat = React8.memo(function PlaygroundChat2({
1487
+ step,
1488
+ selectedProfile,
1489
+ authAvailableLicenses,
1490
+ handleProfileSelect,
1491
+ activeConfig,
1492
+ demoState,
1493
+ suggestions,
1494
+ setInputValue,
1495
+ isGenerating,
1496
+ config,
1497
+ handleGeneratePlayground,
1498
+ isCreatorMode = true,
1499
+ isVoiceActive = false,
1500
+ setIsVoiceActive,
1501
+ VoiceWidget,
1502
+ dynamicPersona,
1503
+ setSuggestions: setSuggestionsFromParent,
1504
+ selectedVoice,
1505
+ showCanvas,
1506
+ setShowCanvas
1507
+ }) {
1508
+ const activeChatId = usePlaygroundStore((state) => state.activeChatId);
1509
+ const chatMessages = usePlaygroundStore((state) => state.chatMessagesByInstance[state.activeChatId || "_default"] || []);
1510
+ const addChatMessage = usePlaygroundStore((state) => state.addChatMessage);
1511
+ const prototypeBrand = usePlaygroundStore((state) => state.prototypeBrand);
1512
+ const setPrototypeBrand = usePlaygroundStore((state) => state.setPrototypeBrand);
1513
+ const scrollRef = React8.useRef(null);
1514
+ const [isAtBottom, setIsAtBottom] = React8.useState(true);
1515
+ const [showExportMenu, setShowExportMenu] = React8.useState(false);
1516
+ const isAtBottomRef = React8.useRef(true);
1517
+ const handleScroll = () => {
1518
+ if (!scrollRef.current) return;
1519
+ const { scrollTop, scrollHeight, clientHeight } = scrollRef.current;
1520
+ const atBottom = scrollHeight - scrollTop - clientHeight < 100;
1521
+ setIsAtBottom(atBottom);
1522
+ isAtBottomRef.current = atBottom;
1523
+ };
1524
+ const lastMsg = chatMessages[chatMessages.length - 1];
1525
+ const scrollKey = `${chatMessages.length}-${lastMsg?.text?.length || 0}`;
1526
+ React8.useEffect(() => {
1527
+ if (isAtBottomRef.current && scrollRef.current) {
1528
+ scrollRef.current.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" });
1529
+ }
1530
+ }, [scrollKey]);
1531
+ const runStressTest = () => {
1532
+ let count = 0;
1533
+ const interval = setInterval(() => {
1534
+ if (count > 200) {
1535
+ clearInterval(interval);
1536
+ return;
1537
+ }
1538
+ addChatMessage({ type: count % 3 === 0 ? "alert" : count % 5 === 0 ? "card" : "text", sender: count % 2 === 0 ? "agent" : "system", text: `Stresstesting message ${count} para medir rendimiento en el sistema.` });
1539
+ count++;
1540
+ }, 10);
1541
+ };
1542
+ const handleThemeSwitch = () => {
1543
+ const brands = activeConfig && typeof activeConfig === "object" && config?.environments ? Object.keys(config.environments) : ["brand-a", "brand-b", "brand-c"];
1544
+ const nextIndex = (brands.indexOf(prototypeBrand) + 1) % brands.length;
1545
+ setPrototypeBrand(brands[nextIndex]);
1546
+ };
1547
+ const chatContextValue = React8.useMemo(() => ({
1548
+ activeConfig,
1549
+ onMorphInstanceSelect: (instanceId) => {
1550
+ useMorphInstanceStore.getState().setActiveInstance(instanceId);
1551
+ useLayoutStore.getState().setActiveTab(`morph-${instanceId}`);
1552
+ if (setShowCanvas) setShowCanvas(true);
1553
+ },
1554
+ extensions: {
1555
+ getPreviewHTML: () => useMorphInstanceStore.getState().getActiveInstance?.()?.data?.html || null,
1556
+ onSendMessage: (text) => addChatMessage({ type: "text", sender: "user", text }),
1557
+ renderMessageActions: (msgId) => null
1558
+ }
1559
+ }), [activeConfig, setShowCanvas, addChatMessage]);
1560
+ return /* @__PURE__ */ jsx8(AnimatePresence4, { mode: "wait", children: step === "action" ? /* @__PURE__ */ jsxs8(motion4.div, { initial: { opacity: 0, scale: 0.9 }, animate: { opacity: 1, scale: 1 }, className: "flex flex-col items-center justify-center h-full text-center", children: [
1561
+ /* @__PURE__ */ jsx8("div", { className: "w-24 h-24 mx-auto rounded-full border-[3px] border-cyan-500/30 border-t-cyan-400 animate-spin mb-8 shadow-[0_0_30px_rgba(34,211,238,0.2)]" }),
1562
+ /* @__PURE__ */ jsx8("h2", { className: "text-3xl font-bold text-text-primary mb-4", children: "Reestructurando el OS..." }),
1563
+ /* @__PURE__ */ jsxs8("p", { className: "text-cyan-400 font-mono text-sm tracking-widest uppercase bg-cyan-500/10 py-2 px-6 rounded-full inline-block border border-cyan-500/20", children: [
1564
+ "Cargando m\xF3dulos para: ",
1565
+ selectedProfile
1566
+ ] })
1567
+ ] }, "action-step") : step === "profile" ? /* @__PURE__ */ jsxs8(motion4.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, className: "flex flex-col items-center justify-center h-full w-full max-w-4xl mx-auto pb-20", children: [
1568
+ /* @__PURE__ */ jsx8("h2", { className: "text-2xl md:text-3xl font-bold text-text-primary text-center mb-8", children: "Selecciona tu Perfil" }),
1569
+ /* @__PURE__ */ jsx8("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 w-full", children: authAvailableLicenses.map((license) => /* @__PURE__ */ jsx8("button", { onClick: () => handleProfileSelect(license), className: `group relative p-6 rounded-3xl bg-surface-tertiary border border-border-subtle transition-all text-left overflow-hidden ${license.type === "enterprise" ? "hover:border-emerald-500/50" : "hover:border-cyan-500/50"}`, children: /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-4 mb-4", children: [
1570
+ /* @__PURE__ */ jsx8("div", { className: `w-12 h-12 rounded-full flex items-center justify-center shadow-inner ${license.type === "enterprise" ? "bg-emerald-500/10 text-emerald-400" : "bg-cyan-500/10 text-cyan-400"}`, children: license.type === "enterprise" ? /* @__PURE__ */ jsx8(Building22, { size: 24 }) : /* @__PURE__ */ jsx8(BrainCircuit2, { size: 24 }) }),
1571
+ /* @__PURE__ */ jsx8("h3", { className: "text-xl font-bold text-text-primary", children: license.name })
1572
+ ] }) }, license.id)) })
1573
+ ] }, "profile-step") : /* @__PURE__ */ jsxs8(motion4.div, { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0 }, className: "flex flex-col h-full overflow-hidden w-full max-w-full lg:max-w-4xl mx-auto pb-4 px-3 sm:px-6 md:px-8 lg:px-4 min-w-0 min-h-0 box-border", children: [
1574
+ /* @__PURE__ */ jsxs8("div", { ref: scrollRef, onScroll: handleScroll, className: `flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar scroll-smooth flex flex-col gap-6 md:gap-8 min-w-0 min-h-0 ${!isCreatorMode ? "justify-end pb-6" : "pb-48 md:pb-64"}`, children: [
1575
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-3 md:gap-4 transition-all mt-4 sm:mt-6 md:mt-8", children: [
1576
+ /* @__PURE__ */ jsxs8("h1", { className: "text-2xl sm:text-3xl md:text-5xl font-semibold leading-tight text-text-primary/50", children: [
1577
+ /* @__PURE__ */ jsx8("span", { className: `bg-linear-to-r ${activeConfig.gradient} text-transparent bg-clip-text transition-all duration-700`, children: activeConfig.greetingText }),
1578
+ /* @__PURE__ */ jsx8("br", {}),
1579
+ activeConfig.greetingPrompt || "\xBFEn qu\xE9 puedo ayudarte hoy?"
1580
+ ] }),
1581
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-4 flex-wrap mt-2", children: [
1582
+ /* @__PURE__ */ jsx8("p", { className: "text-sm text-text-muted font-mono transition-all duration-700", children: activeConfig.subtitle }),
1583
+ /* @__PURE__ */ jsxs8("div", { className: "hidden md:flex gap-2 items-center", children: [
1584
+ /* @__PURE__ */ jsxs8("button", { onClick: handleThemeSwitch, className: "text-[10px] text-text-secondary hover:text-text-primary uppercase tracking-wider transition-colors bg-surface-glass hover:bg-surface-glass px-3 py-1.5 rounded-full border border-border-default flex items-center gap-2", children: [
1585
+ /* @__PURE__ */ jsx8("span", { className: `w-2 h-2 rounded-full ${prototypeBrand === "brand-b" ? "bg-emerald-400" : prototypeBrand === "brand-c" ? "bg-purple-400" : "bg-cyan-400"}` }),
1586
+ "Tema: ",
1587
+ prototypeBrand
1588
+ ] }),
1589
+ /* @__PURE__ */ jsxs8("button", { onClick: runStressTest, className: "text-[10px] text-text-secondary hover:text-orange-400 uppercase tracking-wider transition-colors bg-orange-500/5 hover:bg-orange-500/10 px-3 py-1.5 rounded-full border border-orange-500/20 border-dashed flex items-center gap-2", children: [
1590
+ /* @__PURE__ */ jsx8("span", { className: "text-orange-500 font-bold", children: "\u26A0" }),
1591
+ " Estr\xE9s (200 msgs)"
1592
+ ] }),
1593
+ /* @__PURE__ */ jsxs8("div", { className: "relative", children: [
1594
+ /* @__PURE__ */ jsxs8("button", { onClick: () => setShowExportMenu(!showExportMenu), className: "text-[10px] text-text-secondary hover:text-cyan-400 uppercase tracking-wider transition-colors bg-surface-glass hover:bg-surface-glass px-3 py-1.5 rounded-full border border-border-default flex items-center gap-2", children: [
1595
+ /* @__PURE__ */ jsx8(Download, { size: 10 }),
1596
+ " Export"
1597
+ ] }),
1598
+ /* @__PURE__ */ jsx8(ChatExportMenu, { isOpen: showExportMenu, onClose: () => setShowExportMenu(false) })
1599
+ ] })
1600
+ ] })
1601
+ ] })
1602
+ ] }),
1603
+ /* @__PURE__ */ jsx8(ChatProvider, { value: chatContextValue, children: (chatMessages.length > 0 || isGenerating) && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-6 mt-6 max-w-full md:max-w-3xl min-w-0", children: [
1604
+ chatMessages.map((msg) => /* @__PURE__ */ jsx8(ChatMessageRow, { msg }, msg.id)),
1605
+ /* @__PURE__ */ jsx8(AnimatePresence4, { children: isGenerating && /* @__PURE__ */ jsxs8(motion4.div, { initial: { opacity: 0, y: 10, scale: 0.95 }, animate: { opacity: 1, y: 0, scale: 1 }, exit: { opacity: 0, scale: 0.95 }, className: "flex gap-4", children: [
1606
+ /* @__PURE__ */ jsx8("div", { className: "w-10 h-10 rounded-full flex items-center justify-center shadow-lg border shrink-0 bg-transparent border-border-strong text-text-primary", children: /* @__PURE__ */ jsx8(Sparkles3, { size: 18, className: "text-text-muted animate-pulse" }) }),
1607
+ /* @__PURE__ */ jsx8("div", { className: "flex-1 space-y-2 flex flex-col items-start justify-center", children: /* @__PURE__ */ jsxs8("div", { className: "bg-surface-tertiary border border-border-subtle rounded-2xl p-4 shadow-xl inline-flex gap-1.5 items-center justify-center", children: [
1608
+ /* @__PURE__ */ jsx8("div", { className: "w-1.5 h-1.5 rounded-full bg-surface-elevated animate-bounce", style: { animationDelay: "0ms" } }),
1609
+ /* @__PURE__ */ jsx8("div", { className: "w-1.5 h-1.5 rounded-full bg-surface-elevated animate-bounce", style: { animationDelay: "150ms" } }),
1610
+ /* @__PURE__ */ jsx8("div", { className: "w-1.5 h-1.5 rounded-full bg-surface-elevated animate-bounce", style: { animationDelay: "300ms" } })
1611
+ ] }) })
1612
+ ] }) })
1613
+ ] }) }),
1614
+ !chatMessages.length && demoState !== "idle" && /* @__PURE__ */ jsx8("div", { className: "flex flex-col gap-6 mt-6 max-w-full md:max-w-3xl opacity-50 min-w-0", children: /* @__PURE__ */ jsx8("p", { className: "text-sm text-text-muted italic", children: "Ejecutando secuencia en el simulador sin salida de chat..." }) }),
1615
+ !chatMessages.length && demoState === "idle" && /* @__PURE__ */ jsx8(SuggestionCards, { suggestions, onSelect: setInputValue })
1616
+ ] }),
1617
+ !isAtBottom && chatMessages.length > 5 && /* @__PURE__ */ jsx8(
1618
+ motion4.button,
1619
+ {
1620
+ initial: { opacity: 0, y: 10 },
1621
+ animate: { opacity: 1, y: 0 },
1622
+ exit: { opacity: 0, y: 10 },
1623
+ onClick: () => scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: "smooth" }),
1624
+ className: `absolute ${!isCreatorMode ? "bottom-20" : "bottom-[100px]"} left-1/2 transform -translate-x-1/2 bg-cyan-500 text-text-primary rounded-full px-4 py-2 text-xs font-bold shadow-[0_0_15px_rgba(34,211,238,0.5)] border border-cyan-400 flex items-center gap-2 z-50 hover:bg-cyan-400`,
1625
+ children: "\u2B07 Nuevos Mensajes"
1626
+ }
1627
+ ),
1628
+ !isCreatorMode && /* @__PURE__ */ jsx8("div", { className: "shrink-0 w-full max-w-full lg:max-w-3xl mx-auto pb-2", children: /* @__PURE__ */ jsx8(
1629
+ PlaygroundFloatingInput,
1630
+ {
1631
+ isGenerating,
1632
+ onSend: (val) => {
1633
+ if (handleSlashCommand(val, { prototypeBrand, setPrototypeBrand, addChatMessage })) return;
1634
+ setInputValue(val);
1635
+ if (handleGeneratePlayground) {
1636
+ handleGeneratePlayground(val);
1637
+ } else if (window.__DECIDO__?.geminiStream) {
1638
+ window.__DECIDO__.geminiStream(val);
1639
+ }
1640
+ },
1641
+ isVoiceActive,
1642
+ setIsVoiceActive,
1643
+ VoiceWidget,
1644
+ dynamicPersona,
1645
+ setSuggestions: setSuggestionsFromParent,
1646
+ selectedVoice,
1647
+ showCanvas,
1648
+ setShowCanvas,
1649
+ prototypeBrand,
1650
+ setPrototypeBrand
1651
+ }
1652
+ ) })
1653
+ ] }, "chat-greeting") });
1654
+ });
1655
+
1656
+ export {
1657
+ resolveIcon,
1658
+ resolveColor,
1659
+ resolveColorClasses,
1660
+ PlaygroundFloatingInput,
1661
+ PlaygroundChat
1662
+ };