@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,43 @@
1
+ // src/components/playground/PlaygroundTerminal.tsx
2
+ import React from "react";
3
+ import { motion, AnimatePresence } from "motion/react";
4
+ import { Terminal, Trash2, X } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var PlaygroundTerminal = React.memo(function PlaygroundTerminal2({ isOpen, setIsOpen, logs, setLogs, logsEndRef }) {
7
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(
8
+ motion.div,
9
+ {
10
+ initial: { opacity: 0, y: 50 },
11
+ animate: { opacity: 1, y: 0 },
12
+ exit: { opacity: 0, y: 50 },
13
+ className: "absolute right-6 bottom-40 w-80 h-64 bg-surface-overlay backdrop-blur-md border border-border-default rounded-xl flex flex-col overflow-hidden z-30 shadow-2xl",
14
+ children: [
15
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border-default bg-surface-glass", children: [
16
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
17
+ /* @__PURE__ */ jsx(Terminal, { size: 14, className: "text-text-secondary" }),
18
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-text-secondary", children: "System Log" })
19
+ ] }),
20
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
21
+ /* @__PURE__ */ jsx("button", { onClick: () => setLogs([]), className: "text-text-muted hover:text-red-400 transition-colors", title: "Limpiar logs", children: /* @__PURE__ */ jsx(Trash2, { size: 14 }) }),
22
+ /* @__PURE__ */ jsx("button", { onClick: () => setIsOpen(false), className: "text-text-muted hover:text-text-primary transition-colors", children: /* @__PURE__ */ jsx(X, { size: 14 }) })
23
+ ] })
24
+ ] }),
25
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-3 font-mono text-[10px] space-y-1 custom-scrollbar", children: [
26
+ logs.map((log, i) => /* @__PURE__ */ jsxs("div", { className: `flex gap-2 ${log.type === "error" ? "text-red-400" : log.type === "success" ? "text-emerald-400" : log.type === "system" ? "text-purple-400" : "text-text-secondary"}`, children: [
27
+ /* @__PURE__ */ jsxs("span", { className: "opacity-50 shrink-0", children: [
28
+ "[",
29
+ log.time,
30
+ "]"
31
+ ] }),
32
+ /* @__PURE__ */ jsx("span", { className: "wrap-break-word", children: log.msg })
33
+ ] }, i)),
34
+ /* @__PURE__ */ jsx("div", { ref: logsEndRef })
35
+ ] })
36
+ ]
37
+ }
38
+ ) });
39
+ });
40
+
41
+ export {
42
+ PlaygroundTerminal
43
+ };
@@ -0,0 +1,155 @@
1
+ // src/hooks/useIntentLens.ts
2
+ import { useMemo } from "react";
3
+ var INTENT_PATTERNS = [
4
+ {
5
+ type: "EDIT_GRAPH",
6
+ pattern: /\b(agrega|suma|añade|conecta|modifica|cambia|elimina|borra|parchea|actualiza|inserta|mueve)\b/gi,
7
+ label: "Editar Grafo",
8
+ icon: "\u270F\uFE0F",
9
+ color: "#f59e0b",
10
+ examples: [
11
+ "Agrega un nodo de validaci\xF3n despu\xE9s de login",
12
+ "Conecta el nodo de pago con el de confirmaci\xF3n",
13
+ "Elimina el paso de verificaci\xF3n duplicado"
14
+ ]
15
+ },
16
+ {
17
+ type: "CREATE_GRAPH",
18
+ pattern: /\b(grafo|flujo|nodos|blueprint|escenario|onboarding|proceso|workflow|pipeline|trigger|subflujo|orquest)\b|\b(crea|diseña|genera|construye)\s+(un|una|el|la|los|las)\b/gi,
19
+ label: "Crear Grafo",
20
+ icon: "\u{1F517}",
21
+ color: "#10b981",
22
+ examples: [
23
+ "Crea un flujo de onboarding para nuevos usuarios",
24
+ "Dise\xF1a un pipeline de procesamiento de datos",
25
+ "Genera un blueprint con 5 nodos de decisi\xF3n"
26
+ ]
27
+ },
28
+ {
29
+ type: "UI_ACTION",
30
+ pattern: /\b(shell|tema|theme|sidebar|panel|activity\s*bar|status\s*bar|top\s*bar|notificaci[oó]n|shortcut|atajo|layout)\b|\b(configura)\s+(el|la|los|las)\b/gi,
31
+ label: "Acci\xF3n UI",
32
+ icon: "\u{1F3A8}",
33
+ color: "#3b82f6",
34
+ examples: [
35
+ "Abre el panel de sidebar",
36
+ "Configura el tema oscuro",
37
+ "Cambia el layout a pantalla completa"
38
+ ]
39
+ },
40
+ {
41
+ type: "MCP_ACTION",
42
+ pattern: /\b(ejecuta|invoca|llama|herramienta|tool|api|endpoint)\b/gi,
43
+ label: "Acci\xF3n MCP",
44
+ icon: "\u26A1",
45
+ color: "#a855f7",
46
+ examples: [
47
+ "Ejecuta la herramienta de an\xE1lisis de c\xF3digo",
48
+ "Invoca el endpoint de validaci\xF3n",
49
+ "Llama al API de b\xFAsqueda sem\xE1ntica"
50
+ ]
51
+ },
52
+ {
53
+ type: "NAVIGATE",
54
+ pattern: /\b(landing|página\s*web|web\s*page|website|diseño\s*web|sitio|homepage|portfolio|dashboard\s*ui|ui\s*design|mockup|prototipo\s*web)\b/gi,
55
+ label: "Web Preview",
56
+ icon: "\u{1F310}",
57
+ color: "#06b6d4",
58
+ examples: [
59
+ "Crea una landing page para un SaaS de IA",
60
+ "Dise\xF1a un portfolio moderno con tema oscuro",
61
+ "Genera un dashboard UI para m\xE9tricas de ventas",
62
+ "Crea una p\xE1gina de pricing con 3 planes"
63
+ ]
64
+ }
65
+ ];
66
+ var _extraPatterns = [];
67
+ function registerIntentPattern(p) {
68
+ _extraPatterns.push(p);
69
+ }
70
+ function getIntentPatterns() {
71
+ return [...INTENT_PATTERNS, ..._extraPatterns];
72
+ }
73
+ function tokenizeWithIntents(input) {
74
+ if (!input.trim()) return [];
75
+ const matches = [];
76
+ for (const { type, pattern, color } of INTENT_PATTERNS) {
77
+ const re = new RegExp(pattern.source, pattern.flags);
78
+ let match;
79
+ while ((match = re.exec(input)) !== null) {
80
+ matches.push({
81
+ start: match.index,
82
+ end: match.index + match[0].length,
83
+ intent: type,
84
+ color
85
+ });
86
+ }
87
+ }
88
+ matches.sort((a, b) => a.start - b.start);
89
+ const tokens = [];
90
+ let cursor = 0;
91
+ for (const m of matches) {
92
+ if (m.start < cursor) continue;
93
+ if (m.start > cursor) {
94
+ tokens.push({
95
+ text: input.slice(cursor, m.start),
96
+ intent: "NONE",
97
+ color: null,
98
+ isMatch: false
99
+ });
100
+ }
101
+ tokens.push({
102
+ text: input.slice(m.start, m.end),
103
+ intent: m.intent,
104
+ color: m.color,
105
+ isMatch: true
106
+ });
107
+ cursor = m.end;
108
+ }
109
+ if (cursor < input.length) {
110
+ tokens.push({
111
+ text: input.slice(cursor),
112
+ intent: "NONE",
113
+ color: null,
114
+ isMatch: false
115
+ });
116
+ }
117
+ return tokens;
118
+ }
119
+ function useIntentLens(input) {
120
+ const result = useMemo(() => {
121
+ const tokens = tokenizeWithIntents(input);
122
+ const intentMap = /* @__PURE__ */ new Map();
123
+ for (const token of tokens) {
124
+ if (token.isMatch && token.intent !== "NONE") {
125
+ const existing = intentMap.get(token.intent);
126
+ if (existing) {
127
+ existing.matchedPhrases.push(token.text);
128
+ } else {
129
+ const pattern = INTENT_PATTERNS.find((p) => p.type === token.intent);
130
+ intentMap.set(token.intent, {
131
+ type: token.intent,
132
+ label: pattern.label,
133
+ color: pattern.color,
134
+ icon: pattern.icon,
135
+ matchedPhrases: [token.text]
136
+ });
137
+ }
138
+ }
139
+ }
140
+ return {
141
+ tokens,
142
+ detectedIntents: Array.from(intentMap.values()),
143
+ hasIntents: intentMap.size > 0,
144
+ primaryIntent: intentMap.size > 0 ? Array.from(intentMap.values())[0] : null
145
+ };
146
+ }, [input]);
147
+ return result;
148
+ }
149
+
150
+ export {
151
+ INTENT_PATTERNS,
152
+ registerIntentPattern,
153
+ getIntentPatterns,
154
+ useIntentLens
155
+ };
@@ -0,0 +1,385 @@
1
+ import {
2
+ useSuggestionsStore
3
+ } from "./chunk-F3OTFHNO.mjs";
4
+ import {
5
+ usePlaygroundStore
6
+ } from "./chunk-XMSU6UWD.mjs";
7
+
8
+ // src/components/playground/PlaygroundAppSidebar.tsx
9
+ import React2, { useState as useState2 } from "react";
10
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "motion/react";
11
+ import { Search, Plus as Plus2, X as X2, Settings, ChevronDown, Plug, Wrench, Network, PackageOpen, Paintbrush } from "lucide-react";
12
+ import { ChatHistoryList } from "@decido/chat";
13
+
14
+ // src/components/settings/SettingsPanel.tsx
15
+ import React, { useState, useCallback } from "react";
16
+ import { motion, AnimatePresence } from "motion/react";
17
+ import { X, Plus, Trash2, Sparkles, Loader2, Key, Box, BrainCircuit } from "lucide-react";
18
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
+ var AVAILABLE_MODELS = [
20
+ { id: "gemini-3-flash-preview", name: "Gemini 3 Flash", type: "Ultra-Fast" },
21
+ { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", type: "Deep-Reasoning" },
22
+ { id: "gemini-3.1-flash-lite-preview", name: "Gemini 3.1 Flash Lite", type: "Cutting-Edge" }
23
+ ];
24
+ var SettingsPanel = React.memo(function SettingsPanel2({ isOpen, onClose }) {
25
+ const { seeds, generated, addSeed, removeSeed, updateSeed, setGenerated } = useSuggestionsStore();
26
+ const [newSeed, setNewSeed] = useState("");
27
+ const [genCount, setGenCount] = useState(5);
28
+ const [isGenerating, setIsGenerating] = useState(false);
29
+ const [editingIndex, setEditingIndex] = useState(null);
30
+ const [apiKey, setApiKey] = useState(() => localStorage.getItem("google_gemini_api_key") || "");
31
+ const [showKey, setShowKey] = useState(false);
32
+ const [activeModel, setActiveModel] = useState(() => localStorage.getItem("decido_gemini_model") || "gemini-3-flash-preview");
33
+ const handleModelChange = useCallback((modelId) => {
34
+ setActiveModel(modelId);
35
+ localStorage.setItem("decido_gemini_model", modelId);
36
+ fetch("http://localhost:3100/api/models/active", {
37
+ method: "PUT",
38
+ headers: { "Content-Type": "application/json" },
39
+ body: JSON.stringify({ model_id: modelId })
40
+ }).catch(() => console.warn("Orquestador local no expone /api/models/active a\xFAn."));
41
+ }, []);
42
+ const handleAddSeed = useCallback(() => {
43
+ if (newSeed.trim()) {
44
+ addSeed(newSeed.trim());
45
+ setNewSeed("");
46
+ }
47
+ }, [newSeed, addSeed]);
48
+ const handleGenerateSuggestions = useCallback(async () => {
49
+ if (seeds.length === 0) return;
50
+ setIsGenerating(true);
51
+ try {
52
+ const key = localStorage.getItem("google_gemini_api_key") || window.__DECIDO__?._apiKey || "";
53
+ const model = localStorage.getItem("decido_gemini_model") || "gemini-3-flash-preview";
54
+ if (!key) {
55
+ console.warn("\u274C No API key for suggestions");
56
+ setIsGenerating(false);
57
+ return;
58
+ }
59
+ const prompt = `Bas\xE1ndote en estas frases semilla, genera exactamente ${genCount} sugerencias similares para un chat de IA de productividad. Solo devuelve las sugerencias, una por l\xEDnea, sin numeraci\xF3n ni bullets:
60
+
61
+ ${seeds.join("\n")}`;
62
+ const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${key}`, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] })
66
+ });
67
+ const data = await res.json();
68
+ const text = data?.candidates?.[0]?.content?.parts?.[0]?.text || "";
69
+ const lines = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 3);
70
+ setGenerated(lines.slice(0, genCount));
71
+ } catch (e) {
72
+ console.error("Error generating suggestions:", e);
73
+ } finally {
74
+ setIsGenerating(false);
75
+ }
76
+ }, [seeds, genCount, setGenerated]);
77
+ const saveApiKey = useCallback(() => {
78
+ if (apiKey.trim()) localStorage.setItem("google_gemini_api_key", apiKey.trim());
79
+ else localStorage.removeItem("google_gemini_api_key");
80
+ }, [apiKey]);
81
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
82
+ /* @__PURE__ */ jsx(
83
+ motion.div,
84
+ {
85
+ initial: { opacity: 0 },
86
+ animate: { opacity: 1 },
87
+ exit: { opacity: 0 },
88
+ className: "fixed inset-0 bg-surface-overlay backdrop-blur-xs z-200",
89
+ style: { position: "fixed", inset: 0, zIndex: 200 }
90
+ }
91
+ ),
92
+ /* @__PURE__ */ jsxs(
93
+ motion.div,
94
+ {
95
+ initial: { x: "-100%" },
96
+ animate: { x: 0 },
97
+ exit: { x: "-100%" },
98
+ transition: { type: "spring", damping: 30, stiffness: 300 },
99
+ className: "fixed inset-y-0 left-0 w-full sm:w-[360px] bg-surface-secondary border-r border-border-default z-201 flex flex-col shadow-2xl",
100
+ style: { position: "fixed", top: 0, bottom: 0, left: 0, zIndex: 201 },
101
+ children: [
102
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border-subtle", children: [
103
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-bold text-text-primary", children: "\u2699\uFE0F Configuraci\xF3n" }),
104
+ /* @__PURE__ */ jsx("button", { onClick: onClose, className: "w-7 h-7 rounded-full bg-surface-glass hover:bg-surface-glass flex items-center justify-center text-text-secondary hover:text-text-primary transition-colors", children: /* @__PURE__ */ jsx(X, { size: 14 }) })
105
+ ] }),
106
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-6", style: { scrollbarWidth: "thin", scrollbarColor: "rgba(255,255,255,0.15) transparent" }, children: [
107
+ /* @__PURE__ */ jsxs("section", { children: [
108
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
109
+ /* @__PURE__ */ jsx(Key, { size: 14, className: "text-amber-400" }),
110
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "API Key" })
111
+ ] }),
112
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
113
+ /* @__PURE__ */ jsx(
114
+ "input",
115
+ {
116
+ type: showKey ? "text" : "password",
117
+ value: apiKey,
118
+ onChange: (e) => setApiKey(e.target.value),
119
+ onBlur: saveApiKey,
120
+ placeholder: "AIzaSy...",
121
+ className: "flex-1 bg-surface-glass border border-border-default rounded-lg px-3 py-2 text-xs text-text-primary placeholder-zinc-600 outline-hidden focus:border-border-strong font-mono"
122
+ }
123
+ ),
124
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowKey(!showKey), className: "px-2 rounded-lg text-[10px] text-text-muted hover:text-text-primary bg-surface-glass hover:bg-surface-glass border border-border-default transition-colors", children: showKey ? "\u{1F648}" : "\u{1F441}\uFE0F" })
125
+ ] })
126
+ ] }),
127
+ /* @__PURE__ */ jsxs("section", { children: [
128
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
129
+ /* @__PURE__ */ jsx(BrainCircuit, { size: 14, className: "text-emerald-400" }),
130
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "Brain Router (Enjambre)" })
131
+ ] }),
132
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: AVAILABLE_MODELS.map((m) => /* @__PURE__ */ jsxs(
133
+ "button",
134
+ {
135
+ onClick: () => handleModelChange(m.id),
136
+ className: `flex items-center justify-between px-3 py-2 rounded-xl transition-all border ${activeModel === m.id ? "bg-emerald-500/10 border-emerald-500/30 shadow-[0_0_10px_rgba(16,185,129,0.2)]" : "bg-surface-glass border-border-default hover:border-border-strong"}`,
137
+ children: [
138
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-0.5", children: [
139
+ /* @__PURE__ */ jsx("span", { className: `text-xs font-bold ${activeModel === m.id ? "text-emerald-400" : "text-text-primary"}`, children: m.name }),
140
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-mono text-text-muted uppercase tracking-wider", children: m.id })
141
+ ] }),
142
+ /* @__PURE__ */ jsx("span", { className: `text-[9px] px-2 py-0.5 rounded-full font-bold uppercase tracking-widest ${activeModel === m.id ? "bg-emerald-500/20 text-emerald-300" : "bg-surface-tertiary text-text-secondary"}`, children: m.type })
143
+ ]
144
+ },
145
+ m.id
146
+ )) })
147
+ ] }),
148
+ /* @__PURE__ */ jsxs("section", { children: [
149
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
150
+ /* @__PURE__ */ jsx(Sparkles, { size: 14, className: "text-cyan-400" }),
151
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "Frases Semilla" }),
152
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-text-muted font-mono ml-auto", children: seeds.length })
153
+ ] }),
154
+ /* @__PURE__ */ jsx("div", { className: "space-y-1.5 mb-3", children: seeds.map((seed, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 group", children: [
155
+ editingIndex === i ? /* @__PURE__ */ jsx(
156
+ "input",
157
+ {
158
+ autoFocus: true,
159
+ value: seed,
160
+ onChange: (e) => updateSeed(i, e.target.value),
161
+ onBlur: () => setEditingIndex(null),
162
+ onKeyDown: (e) => e.key === "Enter" && setEditingIndex(null),
163
+ className: "flex-1 bg-surface-glass border border-cyan-500/30 rounded-lg px-2.5 py-1.5 text-xs text-text-primary outline-hidden font-mono"
164
+ }
165
+ ) : /* @__PURE__ */ jsx(
166
+ "button",
167
+ {
168
+ onClick: () => setEditingIndex(i),
169
+ className: "flex-1 text-left px-2.5 py-1.5 rounded-lg text-xs text-text-secondary hover:text-text-primary hover:bg-surface-glass transition-colors font-mono truncate",
170
+ children: seed
171
+ }
172
+ ),
173
+ /* @__PURE__ */ jsx(
174
+ "button",
175
+ {
176
+ onClick: () => removeSeed(i),
177
+ className: "w-6 h-6 rounded-md text-text-muted hover:text-red-400 hover:bg-red-500/10 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all shrink-0",
178
+ children: /* @__PURE__ */ jsx(Trash2, { size: 12 })
179
+ }
180
+ )
181
+ ] }, i)) }),
182
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
183
+ /* @__PURE__ */ jsx(
184
+ "input",
185
+ {
186
+ value: newSeed,
187
+ onChange: (e) => setNewSeed(e.target.value),
188
+ onKeyDown: (e) => e.key === "Enter" && handleAddSeed(),
189
+ placeholder: "Nueva frase semilla...",
190
+ className: "flex-1 bg-surface-glass border border-border-default rounded-lg px-2.5 py-1.5 text-xs text-text-primary placeholder-zinc-600 outline-hidden focus:border-border-strong font-mono"
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsx("button", { onClick: handleAddSeed, className: "w-8 h-8 rounded-lg bg-cyan-500/10 border border-cyan-500/20 text-cyan-400 hover:bg-cyan-500/20 flex items-center justify-center transition-colors", children: /* @__PURE__ */ jsx(Plus, { size: 14 }) })
194
+ ] })
195
+ ] }),
196
+ /* @__PURE__ */ jsxs("section", { children: [
197
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
198
+ /* @__PURE__ */ jsx(Sparkles, { size: 14, className: "text-purple-400" }),
199
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "Generar con AI" })
200
+ ] }),
201
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
202
+ /* @__PURE__ */ jsx("label", { className: "text-[10px] text-text-muted font-mono", children: "Cantidad:" }),
203
+ /* @__PURE__ */ jsx(
204
+ "input",
205
+ {
206
+ type: "number",
207
+ min: 1,
208
+ max: 20,
209
+ value: genCount,
210
+ onChange: (e) => setGenCount(Math.max(1, Math.min(20, parseInt(e.target.value) || 5))),
211
+ className: "w-14 bg-surface-glass border border-border-default rounded-lg px-2 py-1 text-xs text-text-primary outline-hidden text-center font-mono"
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsxs(
215
+ "button",
216
+ {
217
+ onClick: handleGenerateSuggestions,
218
+ disabled: isGenerating || seeds.length === 0,
219
+ className: "flex-1 flex items-center justify-center gap-2 px-3 py-1.5 rounded-lg bg-purple-500/15 border border-purple-500/20 text-purple-300 hover:bg-purple-500/25 disabled:opacity-40 disabled:cursor-not-allowed transition-colors text-xs font-semibold",
220
+ children: [
221
+ isGenerating ? /* @__PURE__ */ jsx(Loader2, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsx(Sparkles, { size: 14 }),
222
+ isGenerating ? "Generando..." : "Generar Sugerencias"
223
+ ]
224
+ }
225
+ )
226
+ ] }),
227
+ generated.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1 bg-surface-glass rounded-lg p-2 border border-border-subtle", children: [
228
+ /* @__PURE__ */ jsxs("div", { className: "text-[9px] text-text-muted font-mono uppercase mb-1", children: [
229
+ "Generadas (",
230
+ generated.length,
231
+ ")"
232
+ ] }),
233
+ generated.map((g, i) => /* @__PURE__ */ jsx("div", { className: "text-xs text-text-secondary font-mono px-2 py-1 rounded hover:bg-surface-glass transition-colors", children: g }, i))
234
+ ] })
235
+ ] }),
236
+ Object.keys(useSuggestionsStore.getState().pluginSuggestions).length > 0 && /* @__PURE__ */ jsxs("section", { children: [
237
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
238
+ /* @__PURE__ */ jsx(Box, { size: 14, className: "text-emerald-400" }),
239
+ /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-text-secondary uppercase tracking-wider", children: "Plugins" })
240
+ ] }),
241
+ Object.entries(useSuggestionsStore.getState().pluginSuggestions).map(([pluginId, items]) => /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
242
+ /* @__PURE__ */ jsxs("div", { className: "text-[10px] text-text-muted font-mono mb-1", children: [
243
+ pluginId,
244
+ " (",
245
+ items.length,
246
+ ")"
247
+ ] }),
248
+ items.map((item, i) => /* @__PURE__ */ jsx("div", { className: "text-xs text-text-secondary font-mono px-2 py-1", children: item }, i))
249
+ ] }, pluginId))
250
+ ] })
251
+ ] })
252
+ ]
253
+ }
254
+ )
255
+ ] }) });
256
+ });
257
+
258
+ // src/components/playground/PlaygroundAppSidebar.tsx
259
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
260
+ var DevToolsFAB = () => {
261
+ const [expanded, setExpanded] = useState2(false);
262
+ return /* @__PURE__ */ jsxs2("div", { className: "relative", onMouseLeave: () => setExpanded(false), children: [
263
+ /* @__PURE__ */ jsx2(
264
+ "button",
265
+ {
266
+ onClick: () => setExpanded(!expanded),
267
+ className: `w-8 h-8 rounded-lg flex items-center justify-center transition-colors shrink-0 ${expanded ? "bg-surface-elevated text-text-primary" : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`,
268
+ title: "Herramientas de Desarrollador",
269
+ children: /* @__PURE__ */ jsx2(Wrench, { size: 16 })
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsx2(AnimatePresence2, { children: expanded && /* @__PURE__ */ jsxs2(
273
+ motion2.div,
274
+ {
275
+ initial: { opacity: 0, scale: 0.9, y: 10 },
276
+ animate: { opacity: 1, scale: 1, y: 0 },
277
+ exit: { opacity: 0, scale: 0.9, y: 10 },
278
+ transition: { type: "spring", stiffness: 400, damping: 25 },
279
+ className: "absolute bottom-full right-0 mb-2 flex flex-col gap-2 p-2 rounded-2xl bg-surface-elevated border border-border-default shadow-2xl origin-bottom z-50",
280
+ children: [
281
+ /* @__PURE__ */ jsx2("button", { onClick: () => window.dispatchEvent(new CustomEvent("DECIDO_OPEN_SWARM_WIZARD")), className: "w-10 h-10 rounded-full bg-surface-secondary border border-border-default hover:border-cyan-400/50 flex items-center justify-center text-text-secondary hover:text-cyan-400 transition-all hover:shadow-[0_0_15px_rgba(6,182,212,0.3)]", title: "Configuraci\xF3n del Enjambre", children: /* @__PURE__ */ jsx2("i", { className: "fas fa-cog text-sm" }) }),
282
+ /* @__PURE__ */ jsx2("button", { onClick: () => window.dispatchEvent(new CustomEvent("DECIDO_TOGGLE_TOPOLOGY")), className: "w-10 h-10 rounded-full bg-surface-secondary border border-border-default hover:border-emerald-400/50 flex items-center justify-center text-text-secondary hover:text-emerald-400 transition-all hover:shadow-[0_0_15px_rgba(16,185,129,0.3)]", title: "Live Topology", children: /* @__PURE__ */ jsx2(Network, { size: 16 }) }),
283
+ /* @__PURE__ */ jsx2("button", { onClick: () => window.dispatchEvent(new CustomEvent("DECIDO_OPEN_MARKETPLACE")), className: "w-10 h-10 rounded-full bg-surface-secondary border border-border-default hover:border-indigo-400/50 flex items-center justify-center text-text-secondary hover:text-indigo-400 transition-all hover:shadow-[0_0_15px_rgba(99,102,241,0.3)]", title: "Plugin Marketplace", children: /* @__PURE__ */ jsx2(PackageOpen, { size: 16 }) }),
284
+ /* @__PURE__ */ jsx2("button", { onClick: () => window.dispatchEvent(new CustomEvent("DECIDO_TOGGLE_TW_EDITOR")), className: "w-10 h-10 rounded-full bg-surface-secondary border border-border-default hover:border-purple-400/50 flex items-center justify-center text-text-secondary hover:text-purple-400 transition-all hover:shadow-[0_0_15px_rgba(139,92,246,0.3)]", title: "Tailwind Editor", children: /* @__PURE__ */ jsx2(Paintbrush, { size: 16 }) })
285
+ ]
286
+ }
287
+ ) })
288
+ ] });
289
+ };
290
+ var PlaygroundAppSidebar = React2.memo(function PlaygroundAppSidebar2({
291
+ isOpen,
292
+ onClose,
293
+ menuSections = [],
294
+ onSettings,
295
+ onProfile,
296
+ profileName = "Usuario",
297
+ profileAvatar
298
+ }) {
299
+ const [searchQuery, setSearchQuery] = useState2("");
300
+ const [collapsedSections, setCollapsedSections] = useState2(/* @__PURE__ */ new Set());
301
+ const [showSettings, setShowSettings] = useState2(false);
302
+ const chatInstances = usePlaygroundStore((s) => s.chatInstances);
303
+ const activeChatId = usePlaygroundStore((s) => s.activeChatId);
304
+ const addChatInstance = usePlaygroundStore((s) => s.addChatInstance);
305
+ const removeChatInstance = usePlaygroundStore((s) => s.removeChatInstance);
306
+ const renameChatInstance = usePlaygroundStore((s) => s.renameChatInstance);
307
+ const setActiveChatId = usePlaygroundStore((s) => s.setActiveChatId);
308
+ const toggleSection = (id) => {
309
+ setCollapsedSections((prev) => {
310
+ const next = new Set(prev);
311
+ if (next.has(id)) next.delete(id);
312
+ else next.add(id);
313
+ return next;
314
+ });
315
+ };
316
+ const sidebarContent = (showClose = false) => /* @__PURE__ */ jsxs2("div", { className: "flex flex-col h-full bg-surface-secondary text-text-primary", children: [
317
+ /* @__PURE__ */ jsxs2("div", { className: "flex-none p-3 pt-4 space-y-2", children: [
318
+ showClose && /* @__PURE__ */ jsx2("div", { className: "flex justify-end mb-1", children: /* @__PURE__ */ jsx2("button", { onClick: onClose, className: "w-7 h-7 rounded-full bg-surface-glass hover:bg-surface-elevated flex items-center justify-center text-text-secondary hover:text-text-primary transition-colors", children: /* @__PURE__ */ jsx2(X2, { size: 14 }) }) }),
319
+ /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
320
+ /* @__PURE__ */ jsx2(Search, { size: 14, className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-text-muted" }),
321
+ /* @__PURE__ */ jsx2(
322
+ "input",
323
+ {
324
+ value: searchQuery,
325
+ onChange: (e) => setSearchQuery(e.target.value),
326
+ placeholder: "Buscar conversaciones...",
327
+ className: "w-full bg-surface-glass border border-border-subtle rounded-lg pl-8 pr-3 py-2 text-sm text-text-primary placeholder-text-muted outline-hidden focus:border-border-strong focus:bg-surface-glass transition-colors"
328
+ }
329
+ ),
330
+ searchQuery && /* @__PURE__ */ jsx2("button", { onClick: () => setSearchQuery(""), className: "absolute right-2 top-1/2 -translate-y-1/2 text-text-muted hover:text-text-primary", children: /* @__PURE__ */ jsx2(X2, { size: 12 }) })
331
+ ] }),
332
+ /* @__PURE__ */ jsxs2("button", { onClick: () => addChatInstance(), className: "w-full flex items-center gap-2 px-3 py-2 rounded-lg bg-surface-glass border border-border-subtle hover:bg-surface-glass hover:border-border-default transition-colors text-sm text-text-primary hover:text-text-primary", children: [
333
+ /* @__PURE__ */ jsx2(Plus2, { size: 16 }),
334
+ /* @__PURE__ */ jsx2("span", { children: "Nueva conversaci\xF3n" })
335
+ ] })
336
+ ] }),
337
+ /* @__PURE__ */ jsxs2("div", { className: "flex-1 overflow-y-auto px-3 pb-2 space-y-1", style: { scrollbarWidth: "thin", scrollbarColor: "rgba(255,255,255,0.15) transparent" }, children: [
338
+ /* @__PURE__ */ jsx2(
339
+ ChatHistoryList,
340
+ {
341
+ chatInstances,
342
+ activeChatId: activeChatId || "",
343
+ searchQuery,
344
+ setActiveChatId,
345
+ renameChatInstance,
346
+ removeChatInstance
347
+ }
348
+ ),
349
+ menuSections.length > 0 && /* @__PURE__ */ jsx2("div", { className: "mt-4 pt-3 border-t border-border-subtle", children: menuSections.map((section) => /* @__PURE__ */ jsxs2("div", { className: "mb-3", children: [
350
+ /* @__PURE__ */ jsxs2("button", { onClick: () => section.collapsible && toggleSection(section.id), className: "flex items-center gap-1.5 px-2 py-1.5 text-[11px] font-semibold text-text-muted uppercase tracking-wider w-full hover:text-text-primary transition-colors", children: [
351
+ section.icon,
352
+ /* @__PURE__ */ jsx2("span", { className: "flex-1 text-left", children: section.title }),
353
+ section.collapsible && /* @__PURE__ */ jsx2(ChevronDown, { size: 12, className: `transition-transform ${collapsedSections.has(section.id) ? "-rotate-90" : ""}` })
354
+ ] }),
355
+ /* @__PURE__ */ jsx2(AnimatePresence2, { children: !collapsedSections.has(section.id) && /* @__PURE__ */ jsx2(motion2.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "overflow-hidden", children: section.items.map((item) => /* @__PURE__ */ jsxs2("button", { onClick: item.onClick, className: `w-full flex items-center gap-2 px-2 py-2 rounded-lg text-sm transition-colors ${item.active ? "bg-surface-glass text-text-primary" : "text-text-secondary hover:bg-surface-glass hover:text-text-primary"}`, children: [
356
+ item.icon,
357
+ /* @__PURE__ */ jsx2("span", { className: "flex-1 text-left truncate", children: item.label }),
358
+ item.badge !== void 0 && /* @__PURE__ */ jsx2("span", { className: "px-1.5 py-0.5 rounded-full bg-cyan-500/15 text-cyan-400 text-[10px] font-bold", children: item.badge })
359
+ ] }, item.id)) }) })
360
+ ] }, section.id)) })
361
+ ] }),
362
+ /* @__PURE__ */ jsx2("div", { className: "flex-none border-t border-border-subtle px-3 py-2", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
363
+ /* @__PURE__ */ jsxs2("button", { onClick: onProfile, className: "flex-1 flex items-center gap-2 px-2 py-2 rounded-lg hover:bg-surface-glass transition-colors group", children: [
364
+ /* @__PURE__ */ jsx2("div", { className: "w-7 h-7 rounded-full bg-linear-to-br from-cyan-500 to-purple-600 flex items-center justify-center text-text-primary text-xs font-bold shrink-0", children: profileAvatar || profileName.charAt(0).toUpperCase() }),
365
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary group-hover:text-text-primary truncate", children: profileName })
366
+ ] }),
367
+ /* @__PURE__ */ jsx2(DevToolsFAB, {}),
368
+ /* @__PURE__ */ jsx2("button", { onClick: () => window.dispatchEvent(new CustomEvent("DECIDO_OPEN_MCP_MODAL")), className: "w-8 h-8 rounded-lg text-text-muted hover:text-text-primary hover:bg-surface-glass flex items-center justify-center transition-colors shrink-0", title: "Configuraci\xF3n MCP", children: /* @__PURE__ */ jsx2(Plug, { size: 16 }) }),
369
+ /* @__PURE__ */ jsx2("button", { onClick: () => setShowSettings(true), className: "w-8 h-8 rounded-lg text-text-muted hover:text-text-primary hover:bg-surface-glass flex items-center justify-center transition-colors shrink-0", title: "Configuraci\xF3n", children: /* @__PURE__ */ jsx2(Settings, { size: 16 }) })
370
+ ] }) }),
371
+ /* @__PURE__ */ jsx2(SettingsPanel, { isOpen: showSettings, onClose: () => setShowSettings(false) })
372
+ ] });
373
+ const mobileDrawer = /* @__PURE__ */ jsx2(AnimatePresence2, { children: isOpen && /* @__PURE__ */ jsxs2(Fragment2, { children: [
374
+ /* @__PURE__ */ jsx2(motion2.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, onClick: onClose, className: "md:hidden fixed inset-0 bg-surface-overlay backdrop-blur-xs z-40" }),
375
+ /* @__PURE__ */ jsx2(motion2.div, { initial: { x: "-100%" }, animate: { x: 0 }, exit: { x: "-100%" }, transition: { type: "spring", damping: 30, stiffness: 300 }, className: "md:hidden fixed inset-y-0 left-0 w-[380px] z-50 shadow-2xl", children: sidebarContent(true) })
376
+ ] }) });
377
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
378
+ mobileDrawer,
379
+ isOpen && /* @__PURE__ */ jsx2("div", { className: "hidden md:flex h-full w-full min-h-0", children: sidebarContent(false) })
380
+ ] });
381
+ });
382
+
383
+ export {
384
+ PlaygroundAppSidebar
385
+ };