@decido/shell 4.0.1 → 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 (38) 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 +27 -22
  38. package/src/index.ts +0 -97
@@ -0,0 +1,2381 @@
1
+ import {
2
+ THEME_PRESETS,
3
+ useTheme
4
+ } from "./chunk-JF5QSJYT.mjs";
5
+ import {
6
+ useMorphologyStore
7
+ } from "./chunk-ZCCCBHE6.mjs";
8
+ import {
9
+ useMorphInstanceStore
10
+ } from "./chunk-UHT6FIYF.mjs";
11
+ import {
12
+ useUIComponentStore
13
+ } from "./chunk-3BZX7LF2.mjs";
14
+ import {
15
+ useLayoutStore
16
+ } from "./chunk-MSVEFEXE.mjs";
17
+ import {
18
+ useActionTimelineStore,
19
+ useDebugPanelStore
20
+ } from "./chunk-3P4P3M54.mjs";
21
+ import {
22
+ usePlaygroundStore
23
+ } from "./chunk-XMSU6UWD.mjs";
24
+
25
+ // src/components/playground/DebugPanel.tsx
26
+ import React13 from "react";
27
+ import { motion as motion2, AnimatePresence as AnimatePresence2 } from "motion/react";
28
+ import { X as X3, Bug as Bug2, Activity, Map as Map3, PlayCircle, Database as Database2, Layers as Layers3, Globe as Globe2, UserCog, Clock as Clock3, Gauge as Gauge2, Download as Download3, Palette as Palette2 } from "lucide-react";
29
+
30
+ // src/components/debug/LogsTab.tsx
31
+ import { useEffect, useRef, useMemo, useState } from "react";
32
+ import { AnimatePresence, motion } from "motion/react";
33
+ import { Filter, Trash2, Copy, Check } from "lucide-react";
34
+
35
+ // src/components/debug/debugConfig.tsx
36
+ import React from "react";
37
+ import {
38
+ Info,
39
+ AlertTriangle,
40
+ AlertCircle,
41
+ Bug,
42
+ Zap,
43
+ MessageSquare,
44
+ Settings,
45
+ GitBranch,
46
+ ArrowRight,
47
+ Circle,
48
+ Map as Map2
49
+ } from "lucide-react";
50
+ import { jsx, jsxs } from "react/jsx-runtime";
51
+ var LEVEL_CONFIG = {
52
+ info: { icon: Info, color: "text-blue-400", bg: "bg-blue-500/10", label: "INFO" },
53
+ warn: { icon: AlertTriangle, color: "text-amber-400", bg: "bg-amber-500/10", label: "WARN" },
54
+ error: { icon: AlertCircle, color: "text-red-400", bg: "bg-red-500/10", label: "ERROR" },
55
+ debug: { icon: Bug, color: "text-purple-400", bg: "bg-purple-500/10", label: "DEBUG" }
56
+ };
57
+ var TRACK_CONFIG = {
58
+ trigger: { icon: Zap, color: "text-yellow-400", label: "Trigger" },
59
+ dialogue: { icon: MessageSquare, color: "text-blue-400", label: "Di\xE1logo" },
60
+ logic: { icon: Settings, color: "text-orange-400", label: "L\xF3gica" },
61
+ ui: { icon: Map2, color: "text-green-400", label: "UI" },
62
+ render: { icon: Map2, color: "text-pink-400", label: "Render" },
63
+ condition: { icon: GitBranch, color: "text-amber-400", label: "Condici\xF3n" },
64
+ subflow: { icon: ArrowRight, color: "text-purple-400", label: "Subflow" },
65
+ entry: { icon: Circle, color: "text-emerald-400", label: "Entry" },
66
+ return: { icon: ArrowRight, color: "text-red-400", label: "Return" },
67
+ set: { icon: Settings, color: "text-cyan-400", label: "Variable" },
68
+ morph: { icon: Map2, color: "text-violet-400", label: "Morph" }
69
+ };
70
+ var LogRow = React.memo(function LogRow2({ entry }) {
71
+ const cfg = LEVEL_CONFIG[entry.level];
72
+ const Icon = cfg.icon;
73
+ return /* @__PURE__ */ jsxs("div", { className: `flex items-start gap-2 px-3 py-1 hover:bg-surface-glass font-mono text-[11px] leading-relaxed border-b border-border-subtle ${cfg.bg}`, children: [
74
+ /* @__PURE__ */ jsx("span", { className: "text-text-muted shrink-0 w-[70px] pt-0.5", children: entry.timestamp }),
75
+ /* @__PURE__ */ jsx(Icon, { size: 12, className: `${cfg.color} shrink-0 mt-0.5` }),
76
+ /* @__PURE__ */ jsx("span", { className: `font-bold shrink-0 w-[38px] ${cfg.color}`, children: cfg.label }),
77
+ entry.categories.length > 0 && /* @__PURE__ */ jsx("span", { className: "shrink-0 flex gap-1", children: entry.categories.map((c, i) => /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 rounded text-[9px] font-bold bg-surface-glass text-text-secondary uppercase tracking-widest", children: c }, i)) }),
78
+ /* @__PURE__ */ jsx("span", { className: "text-text-primary flex-1 break-all", children: entry.message }),
79
+ entry.data !== void 0 && /* @__PURE__ */ jsx("span", { className: "text-text-muted shrink-0 truncate max-w-[200px]", children: typeof entry.data === "object" ? JSON.stringify(entry.data) : String(entry.data) })
80
+ ] });
81
+ });
82
+
83
+ // src/components/debug/LogsTab.tsx
84
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
85
+ function LogsTab() {
86
+ const logEntries = useDebugPanelStore((s) => s.logEntries);
87
+ const logFilters = useDebugPanelStore((s) => s.logFilters);
88
+ const allCategories = useDebugPanelStore((s) => s.allCategories);
89
+ const clearLogs = useDebugPanelStore((s) => s.clearLogs);
90
+ const toggleLevel = useDebugPanelStore((s) => s.toggleLevel);
91
+ const toggleCategory = useDebugPanelStore((s) => s.toggleCategory);
92
+ const [showFilters, setShowFilters] = useState(false);
93
+ const [copied, setCopied] = useState(false);
94
+ const scrollRef = useRef(null);
95
+ useEffect(() => {
96
+ if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
97
+ }, [logEntries.length]);
98
+ const filteredEntries = useMemo(() => {
99
+ return logEntries.filter((e) => {
100
+ if (!logFilters.levels.has(e.level)) return false;
101
+ if (logFilters.categories.size > 0 && !e.categories.some((c) => logFilters.categories.has(c))) return false;
102
+ return true;
103
+ });
104
+ }, [logEntries, logFilters]);
105
+ const catArray = useMemo(() => Array.from(allCategories).sort(), [allCategories]);
106
+ return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col h-full", children: [
107
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 py-1.5 border-b border-border-subtle shrink-0 bg-surface-primary/50", children: [
108
+ /* @__PURE__ */ jsx2("div", { className: "flex gap-1", children: Object.keys(LEVEL_CONFIG).map((lvl) => {
109
+ const cfg = LEVEL_CONFIG[lvl];
110
+ const active = logFilters.levels.has(lvl);
111
+ const count = logEntries.filter((e) => e.level === lvl).length;
112
+ return /* @__PURE__ */ jsxs2(
113
+ "button",
114
+ {
115
+ onClick: () => toggleLevel(lvl),
116
+ className: `flex items-center gap-1 px-2 py-0.5 rounded text-[10px] font-bold transition-all border ${active ? `${cfg.bg} ${cfg.color} border-current/20` : "bg-transparent text-text-muted border-transparent hover:text-text-secondary"}`,
117
+ children: [
118
+ cfg.label,
119
+ count > 0 && /* @__PURE__ */ jsx2("span", { className: "text-[9px] opacity-60", children: count })
120
+ ]
121
+ },
122
+ lvl
123
+ );
124
+ }) }),
125
+ /* @__PURE__ */ jsx2("div", { className: "flex-1" }),
126
+ catArray.length > 0 && /* @__PURE__ */ jsx2(
127
+ "button",
128
+ {
129
+ onClick: () => setShowFilters(!showFilters),
130
+ className: `p-1 rounded transition-colors ${showFilters ? "bg-cyan-500/20 text-cyan-400" : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`,
131
+ title: "Filtrar categor\xEDas",
132
+ children: /* @__PURE__ */ jsx2(Filter, { size: 12 })
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsxs2("span", { className: "text-[10px] text-text-muted font-mono", children: [
136
+ filteredEntries.length,
137
+ "/",
138
+ logEntries.length
139
+ ] }),
140
+ /* @__PURE__ */ jsx2(
141
+ "button",
142
+ {
143
+ onClick: () => {
144
+ const text = filteredEntries.map((e) => {
145
+ const cats = e.categories.length > 0 ? ` [${e.categories.join(",")}]` : "";
146
+ const data = e.data !== void 0 ? ` | ${typeof e.data === "object" ? JSON.stringify(e.data) : String(e.data)}` : "";
147
+ return `[${e.timestamp}] ${LEVEL_CONFIG[e.level].label}${cats} ${e.message}${data}`;
148
+ }).join("\n");
149
+ navigator.clipboard.writeText(text).then(() => {
150
+ setCopied(true);
151
+ setTimeout(() => setCopied(false), 1500);
152
+ });
153
+ },
154
+ className: `p-1 rounded transition-colors ${copied ? "text-green-400 bg-green-500/10" : "text-text-muted hover:text-cyan-400 hover:bg-cyan-500/10"}`,
155
+ title: "Copiar logs visibles",
156
+ children: copied ? /* @__PURE__ */ jsx2(Check, { size: 12 }) : /* @__PURE__ */ jsx2(Copy, { size: 12 })
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsx2("button", { onClick: clearLogs, className: "p-1 rounded text-text-muted hover:text-red-400 hover:bg-red-500/10 transition-colors", title: "Limpiar logs", children: /* @__PURE__ */ jsx2(Trash2, { size: 12 }) })
160
+ ] }),
161
+ /* @__PURE__ */ jsx2(AnimatePresence, { children: showFilters && catArray.length > 0 && /* @__PURE__ */ jsx2(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, className: "overflow-hidden border-b border-border-subtle", children: /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-1 px-3 py-2 bg-surface-primary/80", children: catArray.map((cat) => {
162
+ const active = logFilters.categories.size === 0 || logFilters.categories.has(cat);
163
+ return /* @__PURE__ */ jsx2("button", { onClick: () => toggleCategory(cat), className: `px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-wider transition-all border ${active ? "bg-cyan-500/10 text-cyan-400 border-cyan-500/20" : "bg-transparent text-text-muted border-transparent hover:text-text-secondary"}`, children: cat }, cat);
164
+ }) }) }) }),
165
+ /* @__PURE__ */ jsx2("div", { ref: scrollRef, className: "flex-1 overflow-y-auto custom-scrollbar", children: filteredEntries.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-center h-full text-text-muted text-xs font-mono", children: "Sin entradas de log" }) : filteredEntries.map((entry) => /* @__PURE__ */ jsx2(LogRow, { entry }, entry.id)) })
166
+ ] });
167
+ }
168
+
169
+ // src/components/debug/FlowHealthTab.tsx
170
+ import { useMemo as useMemo2 } from "react";
171
+ import { AlertTriangle as AlertTriangle2, XCircle, Info as Info2, CheckCircle, Circle as Circle2 } from "lucide-react";
172
+ import { useTimelineStore } from "@decido/engine";
173
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
174
+ function FlowHealthTab() {
175
+ const prototypeBrand = usePlaygroundStore((s) => s.prototypeBrand);
176
+ const timelines = useTimelineStore((s) => s.timelines);
177
+ const flow = timelines[prototypeBrand];
178
+ const analysis = useMemo2(() => {
179
+ if (!flow) return null;
180
+ const kfs = flow.keyframes || [];
181
+ const edges = flow.edges || [];
182
+ const nodeIds = new Set(kfs.map((k) => k.id));
183
+ const trackCounts = {};
184
+ kfs.forEach((k) => {
185
+ const t = k.track || "unknown";
186
+ trackCounts[t] = (trackCounts[t] || 0) + 1;
187
+ });
188
+ const hasIncoming = new Set(edges.map((e) => e.target));
189
+ const hasOutgoing = new Set(edges.map((e) => e.source));
190
+ const orphans = kfs.filter((k) => {
191
+ if (k.track === "trigger" || k.track === "entry") return false;
192
+ return !hasIncoming.has(k.id) && edges.length > 0;
193
+ });
194
+ const terminals = kfs.filter((k) => hasIncoming.has(k.id) && !hasOutgoing.has(k.id) && k.track !== "return");
195
+ const deadEdges = edges.filter((e) => !nodeIds.has(e.target) || !nodeIds.has(e.source));
196
+ const unlabeled = kfs.filter((k) => !k.label && !k.state && k.track !== "trigger");
197
+ const issues = orphans.length + deadEdges.length + unlabeled.length;
198
+ const score = Math.max(0, Math.min(100, 100 - issues * 10));
199
+ return { kfs, edges, trackCounts, orphans, terminals, deadEdges, unlabeled, score, issues };
200
+ }, [flow]);
201
+ if (!flow || !analysis) return /* @__PURE__ */ jsx3("div", { className: "flex items-center justify-center h-full text-text-muted text-xs font-mono", children: "Sin blueprint activo" });
202
+ const scoreColor = analysis.score >= 80 ? "text-green-400" : analysis.score >= 50 ? "text-amber-400" : "text-red-400";
203
+ const scoreBg = analysis.score >= 80 ? "bg-green-500/10" : analysis.score >= 50 ? "bg-amber-500/10" : "bg-red-500/10";
204
+ return /* @__PURE__ */ jsxs3("div", { className: "h-full overflow-y-auto custom-scrollbar p-4 space-y-4", children: [
205
+ /* @__PURE__ */ jsxs3("div", { className: `flex items-center gap-4 p-4 rounded-xl ${scoreBg} border border-border-subtle`, children: [
206
+ /* @__PURE__ */ jsx3("div", { className: `text-4xl font-black ${scoreColor} font-mono`, children: analysis.score }),
207
+ /* @__PURE__ */ jsxs3("div", { children: [
208
+ /* @__PURE__ */ jsx3("div", { className: `text-sm font-bold ${scoreColor}`, children: analysis.score >= 80 ? "\u2705 Saludable" : analysis.score >= 50 ? "\u26A0\uFE0F Revisar" : "\u{1F534} Problemas detectados" }),
209
+ /* @__PURE__ */ jsxs3("div", { className: "text-[11px] text-text-muted", children: [
210
+ analysis.kfs.length,
211
+ " nodos \xB7 ",
212
+ analysis.edges.length,
213
+ " conexiones \xB7 ",
214
+ analysis.issues,
215
+ " problemas"
216
+ ] })
217
+ ] })
218
+ ] }),
219
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
220
+ /* @__PURE__ */ jsx3("div", { className: "text-[11px] font-bold text-text-secondary uppercase tracking-widest", children: "Distribuci\xF3n por Track" }),
221
+ /* @__PURE__ */ jsx3("div", { className: "grid grid-cols-2 lg:grid-cols-3 gap-2", children: Object.entries(analysis.trackCounts).map(([track, count]) => {
222
+ const cfg = TRACK_CONFIG[track] || { icon: Circle2, color: "text-text-secondary", label: track };
223
+ const Icon = cfg.icon;
224
+ return /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-2 rounded-lg bg-surface-glass border border-border-subtle", children: [
225
+ /* @__PURE__ */ jsx3(Icon, { size: 14, className: cfg.color }),
226
+ /* @__PURE__ */ jsx3("span", { className: "text-[11px] text-text-primary font-semibold", children: cfg.label }),
227
+ /* @__PURE__ */ jsx3("span", { className: "ml-auto text-[11px] font-mono text-text-muted", children: count })
228
+ ] }, track);
229
+ }) })
230
+ ] }),
231
+ analysis.orphans.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
232
+ /* @__PURE__ */ jsxs3("div", { className: "text-[11px] font-bold text-amber-400 flex items-center gap-1", children: [
233
+ /* @__PURE__ */ jsx3(AlertTriangle2, { size: 12 }),
234
+ " Nodos Hu\xE9rfanos (",
235
+ analysis.orphans.length,
236
+ ")"
237
+ ] }),
238
+ analysis.orphans.map((k) => /* @__PURE__ */ jsxs3("div", { className: "pl-5 text-[11px] text-text-muted font-mono", children: [
239
+ "\xB7 ",
240
+ k.label || k.id,
241
+ " ",
242
+ /* @__PURE__ */ jsxs3("span", { className: "text-text-muted", children: [
243
+ "(",
244
+ k.track,
245
+ ")"
246
+ ] })
247
+ ] }, k.id))
248
+ ] }),
249
+ analysis.deadEdges.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
250
+ /* @__PURE__ */ jsxs3("div", { className: "text-[11px] font-bold text-red-400 flex items-center gap-1", children: [
251
+ /* @__PURE__ */ jsx3(XCircle, { size: 12 }),
252
+ " Conexiones Rotas (",
253
+ analysis.deadEdges.length,
254
+ ")"
255
+ ] }),
256
+ analysis.deadEdges.map((e, i) => /* @__PURE__ */ jsxs3("div", { className: "pl-5 text-[11px] text-text-muted font-mono", children: [
257
+ "\xB7 ",
258
+ e.source,
259
+ " \u2192 ",
260
+ e.target
261
+ ] }, i))
262
+ ] }),
263
+ analysis.unlabeled.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
264
+ /* @__PURE__ */ jsxs3("div", { className: "text-[11px] font-bold text-text-muted flex items-center gap-1", children: [
265
+ /* @__PURE__ */ jsx3(Info2, { size: 12 }),
266
+ " Sin Etiqueta (",
267
+ analysis.unlabeled.length,
268
+ ")"
269
+ ] }),
270
+ analysis.unlabeled.slice(0, 5).map((k) => /* @__PURE__ */ jsxs3("div", { className: "pl-5 text-[11px] text-text-muted font-mono", children: [
271
+ "\xB7 ",
272
+ k.id,
273
+ " ",
274
+ /* @__PURE__ */ jsxs3("span", { className: "text-text-muted", children: [
275
+ "(",
276
+ k.track,
277
+ ")"
278
+ ] })
279
+ ] }, k.id))
280
+ ] }),
281
+ analysis.terminals.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
282
+ /* @__PURE__ */ jsxs3("div", { className: "text-[11px] font-bold text-text-secondary flex items-center gap-1", children: [
283
+ /* @__PURE__ */ jsx3(CheckCircle, { size: 12 }),
284
+ " Nodos Terminales (",
285
+ analysis.terminals.length,
286
+ ")"
287
+ ] }),
288
+ analysis.terminals.map((k) => /* @__PURE__ */ jsxs3("div", { className: "pl-5 text-[11px] text-text-muted font-mono", children: [
289
+ "\xB7 ",
290
+ k.label || k.id,
291
+ " ",
292
+ /* @__PURE__ */ jsxs3("span", { className: "text-text-muted", children: [
293
+ "(",
294
+ k.track,
295
+ ")"
296
+ ] })
297
+ ] }, k.id))
298
+ ] })
299
+ ] });
300
+ }
301
+
302
+ // src/components/debug/TopologyTab.tsx
303
+ import { ArrowRight as ArrowRight2, Circle as Circle3 } from "lucide-react";
304
+ import { useTimelineStore as useTimelineStore2 } from "@decido/engine";
305
+ import { useEngineStore } from "@decido/engine";
306
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
307
+ function TopologyTab() {
308
+ const prototypeBrand = usePlaygroundStore((s) => s.prototypeBrand);
309
+ const timelines = useTimelineStore2((s) => s.timelines);
310
+ const activeNodeIds = useEngineStore((s) => s.activeNodeIds);
311
+ const flow = timelines[prototypeBrand];
312
+ if (!flow) return /* @__PURE__ */ jsx4("div", { className: "flex items-center justify-center h-full text-text-muted text-xs font-mono", children: "Sin blueprint activo" });
313
+ const kfs = flow.keyframes || [];
314
+ const edges = flow.edges || [];
315
+ const activeSet = new Set(activeNodeIds);
316
+ return /* @__PURE__ */ jsxs4("div", { className: "h-full overflow-y-auto custom-scrollbar p-3", children: [
317
+ /* @__PURE__ */ jsxs4("div", { className: "text-[10px] font-bold text-text-muted uppercase tracking-widest mb-3", children: [
318
+ "Grafo: ",
319
+ flow.name || prototypeBrand,
320
+ " \xB7 ",
321
+ kfs.length,
322
+ " nodos \xB7 ",
323
+ edges.length,
324
+ " aristas"
325
+ ] }),
326
+ /* @__PURE__ */ jsx4("div", { className: "space-y-1", children: kfs.map((kf) => {
327
+ const cfg = TRACK_CONFIG[kf.track] || { icon: Circle3, color: "text-text-secondary", label: kf.track };
328
+ const Icon = cfg.icon;
329
+ const isActive = activeSet.has(kf.id);
330
+ const outEdges = edges.filter((e) => e.source === kf.id);
331
+ return /* @__PURE__ */ jsxs4("div", { className: `group rounded-lg border transition-all ${isActive ? "bg-cyan-500/10 border-cyan-500/30 ring-1 ring-cyan-500/20" : "bg-surface-glass border-border-subtle hover:bg-surface-glass"}`, children: [
332
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 px-3 py-2", children: [
333
+ /* @__PURE__ */ jsx4(Icon, { size: 13, className: cfg.color }),
334
+ /* @__PURE__ */ jsx4("span", { className: `text-[11px] font-semibold flex-1 ${isActive ? "text-cyan-300" : "text-text-primary"}`, children: kf.label || kf.state || kf.id }),
335
+ /* @__PURE__ */ jsx4("span", { className: "text-[9px] text-text-muted font-mono", children: kf.track }),
336
+ isActive && /* @__PURE__ */ jsx4("span", { className: "w-2 h-2 rounded-full bg-cyan-400 animate-pulse" })
337
+ ] }),
338
+ outEdges.length > 0 && /* @__PURE__ */ jsx4("div", { className: "px-3 pb-2 flex flex-wrap gap-1", children: outEdges.map((e, i) => {
339
+ const target = kfs.find((k) => k.id === e.target);
340
+ return /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1 text-[9px] text-text-muted bg-surface-glass rounded px-1.5 py-0.5", children: [
341
+ /* @__PURE__ */ jsx4(ArrowRight2, { size: 8, className: "text-text-muted" }),
342
+ target?.label || target?.state || e.target,
343
+ e.sourceHandle && e.sourceHandle !== "success" && /* @__PURE__ */ jsxs4("span", { className: "text-amber-500/70", children: [
344
+ "(",
345
+ e.sourceHandle,
346
+ ")"
347
+ ] })
348
+ ] }, i);
349
+ }) })
350
+ ] }, kf.id);
351
+ }) })
352
+ ] });
353
+ }
354
+
355
+ // src/components/debug/ReplayTab.tsx
356
+ import { useMemo as useMemo3, useState as useState2 } from "react";
357
+ import { SkipBack, SkipForward } from "lucide-react";
358
+ import { useEngineStore as useEngineStore2 } from "@decido/engine";
359
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
360
+ function ReplayTab() {
361
+ const logEntries = useDebugPanelStore((s) => s.logEntries);
362
+ const activeNodeIds = useEngineStore2((s) => s.activeNodeIds);
363
+ const [selectedIdx, setSelectedIdx] = useState2(-1);
364
+ const engineLogs = useMemo3(() => {
365
+ return logEntries.filter(
366
+ (e) => e.categories.some((c) => ["ENGINE", "PLUGIN:DIALOGUE", "PLUGIN:LOGIC", "PLUGIN:SUBFLOW", "PLUGIN:RETURN", "PLUGIN:UI", "PLUGIN:UIRENDER"].includes(c.toUpperCase())) || e.message.includes("\u{1F680}") || e.message.includes("\u{1F500}") || e.message.includes("\u{1F5E3}") || e.message.includes("\u26A1") || e.message.includes("\u{1F3C1}")
367
+ );
368
+ }, [logEntries]);
369
+ const selected = selectedIdx >= 0 ? engineLogs[selectedIdx] : null;
370
+ return /* @__PURE__ */ jsxs5("div", { className: "h-full flex flex-col", children: [
371
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border-subtle shrink-0 bg-surface-primary/50", children: [
372
+ /* @__PURE__ */ jsx5("button", { onClick: () => setSelectedIdx(Math.max(0, selectedIdx - 1)), disabled: selectedIdx <= 0, className: "p-1 rounded text-text-muted hover:text-text-primary hover:bg-surface-glass disabled:opacity-30 transition-colors", children: /* @__PURE__ */ jsx5(SkipBack, { size: 14 }) }),
373
+ /* @__PURE__ */ jsx5("span", { className: "text-[10px] text-text-muted font-mono w-16 text-center", children: selectedIdx >= 0 ? `${selectedIdx + 1}/${engineLogs.length}` : `\u2014/${engineLogs.length}` }),
374
+ /* @__PURE__ */ jsx5("button", { onClick: () => setSelectedIdx(Math.min(engineLogs.length - 1, selectedIdx + 1)), disabled: selectedIdx >= engineLogs.length - 1, className: "p-1 rounded text-text-muted hover:text-text-primary hover:bg-surface-glass disabled:opacity-30 transition-colors", children: /* @__PURE__ */ jsx5(SkipForward, { size: 14 }) }),
375
+ /* @__PURE__ */ jsx5("div", { className: "flex-1" }),
376
+ /* @__PURE__ */ jsx5("span", { className: "text-[10px] text-text-muted", children: activeNodeIds.length > 0 && `Nodo activo: ${activeNodeIds[0]?.substring(0, 12)}...` })
377
+ ] }),
378
+ /* @__PURE__ */ jsx5("div", { className: "flex-1 overflow-y-auto custom-scrollbar", children: engineLogs.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-center h-full text-text-muted text-xs font-mono", children: "Ejecuta un flujo para ver el replay" }) : /* @__PURE__ */ jsx5("div", { className: "py-1", children: engineLogs.map((entry, idx) => {
379
+ const isSelected = idx === selectedIdx;
380
+ const isPast = idx < selectedIdx;
381
+ return /* @__PURE__ */ jsxs5("button", { onClick: () => setSelectedIdx(idx), className: `w-full flex items-start gap-2 px-3 py-1.5 text-left transition-all border-l-2 ${isSelected ? "bg-amber-500/10 border-amber-400 text-amber-300" : isPast ? "border-border-default text-text-muted hover:bg-surface-glass" : "border-transparent text-text-secondary hover:bg-surface-glass"}`, children: [
382
+ /* @__PURE__ */ jsx5("span", { className: `shrink-0 w-5 h-5 rounded-full flex items-center justify-center text-[9px] font-bold mt-0.5 ${isSelected ? "bg-amber-500/20 text-amber-400" : isPast ? "bg-surface-glass text-text-muted" : "bg-surface-glass text-text-muted"}`, children: idx + 1 }),
383
+ /* @__PURE__ */ jsxs5("div", { className: "flex-1 min-w-0", children: [
384
+ /* @__PURE__ */ jsx5("div", { className: "text-[11px] font-mono truncate", children: entry.message }),
385
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 mt-0.5", children: [
386
+ /* @__PURE__ */ jsx5("span", { className: "text-[9px] text-text-muted", children: entry.timestamp }),
387
+ entry.categories.map((c, i) => /* @__PURE__ */ jsx5("span", { className: "text-[8px] px-1 py-0.5 rounded bg-surface-glass text-text-muted uppercase tracking-widest", children: c }, i))
388
+ ] })
389
+ ] })
390
+ ] }, entry.id);
391
+ }) }) }),
392
+ selected && /* @__PURE__ */ jsxs5("div", { className: "border-t border-border-subtle px-3 py-2 bg-surface-primary/80 shrink-0", children: [
393
+ /* @__PURE__ */ jsxs5("div", { className: "text-[10px] font-bold text-text-secondary mb-1", children: [
394
+ "Detalle del paso ",
395
+ selectedIdx + 1
396
+ ] }),
397
+ /* @__PURE__ */ jsx5("div", { className: "text-[11px] text-text-primary font-mono break-all", children: selected.message }),
398
+ selected.data && /* @__PURE__ */ jsx5("pre", { className: "text-[10px] text-text-muted font-mono mt-1 max-h-20 overflow-y-auto", children: typeof selected.data === "object" ? JSON.stringify(selected.data, null, 2) : String(selected.data) })
399
+ ] })
400
+ ] });
401
+ }
402
+
403
+ // src/components/debug/StoresTab.tsx
404
+ import { useState as useState3, useMemo as useMemo4, useCallback, useSyncExternalStore } from "react";
405
+ import { Database, Zap as Zap2, ChevronRight, ChevronDown, ToggleLeft, ToggleRight, Camera, ArrowLeftRight, Download } from "lucide-react";
406
+ import { useEngineStore as useEngineStore3, useTimelineStore as useTimelineStore3, useUserStateStore } from "@decido/engine";
407
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
408
+ var _shellStores = null;
409
+ function getShellStores() {
410
+ if (_shellStores) return _shellStores;
411
+ const registry = globalThis.__DECIDO_SHELL_STORES__;
412
+ _shellStores = registry || [];
413
+ return _shellStores;
414
+ }
415
+ var STUDIO_STORES = [
416
+ { name: "Playground", group: "studio", store: usePlaygroundStore },
417
+ { name: "Engine", group: "studio", store: useEngineStore3 },
418
+ { name: "Timeline", group: "studio", store: useTimelineStore3 },
419
+ { name: "Morphology", group: "studio", store: useMorphologyStore },
420
+ { name: "UserState", group: "studio", store: useUserStateStore },
421
+ { name: "UIComponents", group: "studio", store: useUIComponentStore }
422
+ ];
423
+ function ValueEditor({ value, path, onUpdate, depth = 0 }) {
424
+ const [collapsed, setCollapsed] = useState3(depth > 1);
425
+ if (value === null || value === void 0) return /* @__PURE__ */ jsx6("span", { className: "text-text-muted italic text-[10px] font-mono", children: String(value) });
426
+ if (typeof value === "function") return null;
427
+ if (typeof value === "boolean") {
428
+ return /* @__PURE__ */ jsxs6("button", { onClick: () => onUpdate(path, !value), className: `flex items-center gap-1 text-[10px] font-mono transition-colors ${value ? "text-emerald-400" : "text-text-muted"}`, children: [
429
+ value ? /* @__PURE__ */ jsx6(ToggleRight, { size: 14 }) : /* @__PURE__ */ jsx6(ToggleLeft, { size: 14 }),
430
+ String(value)
431
+ ] });
432
+ }
433
+ if (typeof value === "number") return /* @__PURE__ */ jsx6("input", { type: "number", value, onChange: (e) => onUpdate(path, Number(e.target.value)), className: "bg-surface-tertiary border border-border-default rounded px-1.5 py-0.5 text-[10px] font-mono text-cyan-300 w-24 outline-hidden focus:border-cyan-500/50" });
434
+ if (typeof value === "string") return /* @__PURE__ */ jsx6("input", { type: "text", value, onChange: (e) => onUpdate(path, e.target.value), className: "bg-surface-tertiary border border-border-default rounded px-1.5 py-0.5 text-[10px] font-mono text-amber-300 flex-1 min-w-[80px] max-w-[300px] outline-hidden focus:border-amber-500/50" });
435
+ const tag = Object.prototype.toString.call(value);
436
+ if (tag === "[object Map]") {
437
+ const entries = Array.from(value.entries());
438
+ return /* @__PURE__ */ jsxs6("div", { className: "pl-3 border-l border-border-subtle", children: [
439
+ /* @__PURE__ */ jsxs6("button", { onClick: () => setCollapsed(!collapsed), className: "flex items-center gap-1 text-[10px] text-text-muted hover:text-text-primary", children: [
440
+ collapsed ? /* @__PURE__ */ jsx6(ChevronRight, { size: 10 }) : /* @__PURE__ */ jsx6(ChevronDown, { size: 10 }),
441
+ /* @__PURE__ */ jsx6("span", { className: "text-violet-400", children: "Map" }),
442
+ "(",
443
+ entries.length,
444
+ ")"
445
+ ] }),
446
+ !collapsed && entries.map((entry, i) => /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2 py-0.5 pl-2", children: [
447
+ /* @__PURE__ */ jsxs6("span", { className: "text-[10px] text-text-muted font-mono shrink-0", children: [
448
+ String(entry[0]),
449
+ ":"
450
+ ] }),
451
+ /* @__PURE__ */ jsx6(ValueEditor, { value: entry[1], path: `${path}.${String(entry[0])}`, onUpdate: () => {
452
+ }, depth: depth + 1 })
453
+ ] }, i))
454
+ ] });
455
+ }
456
+ if (tag === "[object Set]") {
457
+ const items = Array.from(value);
458
+ return /* @__PURE__ */ jsxs6("div", { className: "pl-3 border-l border-border-subtle", children: [
459
+ /* @__PURE__ */ jsxs6("button", { onClick: () => setCollapsed(!collapsed), className: "flex items-center gap-1 text-[10px] text-text-muted hover:text-text-primary", children: [
460
+ collapsed ? /* @__PURE__ */ jsx6(ChevronRight, { size: 10 }) : /* @__PURE__ */ jsx6(ChevronDown, { size: 10 }),
461
+ /* @__PURE__ */ jsx6("span", { className: "text-violet-400", children: "Set" }),
462
+ "(",
463
+ items.length,
464
+ ")"
465
+ ] }),
466
+ !collapsed && items.map((v, i) => /* @__PURE__ */ jsx6("div", { className: "pl-2 py-0.5", children: /* @__PURE__ */ jsx6(ValueEditor, { value: v, path: `${path}[${i}]`, onUpdate: () => {
467
+ }, depth: depth + 1 }) }, i))
468
+ ] });
469
+ }
470
+ if (Array.isArray(value)) {
471
+ return /* @__PURE__ */ jsxs6("div", { className: "pl-3 border-l border-border-subtle", children: [
472
+ /* @__PURE__ */ jsxs6("button", { onClick: () => setCollapsed(!collapsed), className: "flex items-center gap-1 text-[10px] text-text-muted hover:text-text-primary", children: [
473
+ collapsed ? /* @__PURE__ */ jsx6(ChevronRight, { size: 10 }) : /* @__PURE__ */ jsx6(ChevronDown, { size: 10 }),
474
+ /* @__PURE__ */ jsx6("span", { className: "text-blue-400", children: "Array" }),
475
+ /* @__PURE__ */ jsxs6("span", { className: "text-text-muted", children: [
476
+ "[",
477
+ value.length,
478
+ "]"
479
+ ] })
480
+ ] }),
481
+ !collapsed && value.slice(0, 50).map((item, i) => /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2 py-0.5 pl-2", children: [
482
+ /* @__PURE__ */ jsx6("span", { className: "text-[9px] text-text-muted font-mono shrink-0 w-4 text-right", children: i }),
483
+ /* @__PURE__ */ jsx6(ValueEditor, { value: item, path: `${path}[${i}]`, onUpdate, depth: depth + 1 })
484
+ ] }, i)),
485
+ value.length > 50 && /* @__PURE__ */ jsxs6("span", { className: "text-[9px] text-text-muted pl-2", children: [
486
+ "... +",
487
+ value.length - 50,
488
+ " m\xE1s"
489
+ ] })
490
+ ] });
491
+ }
492
+ if (typeof value === "object") {
493
+ const entries = Object.entries(value).filter(([, v]) => typeof v !== "function");
494
+ return /* @__PURE__ */ jsxs6("div", { className: "pl-3 border-l border-border-subtle", children: [
495
+ /* @__PURE__ */ jsxs6("button", { onClick: () => setCollapsed(!collapsed), className: "flex items-center gap-1 text-[10px] text-text-muted hover:text-text-primary", children: [
496
+ collapsed ? /* @__PURE__ */ jsx6(ChevronRight, { size: 10 }) : /* @__PURE__ */ jsx6(ChevronDown, { size: 10 }),
497
+ /* @__PURE__ */ jsx6("span", { className: "text-orange-400", children: `{${entries.length}}` })
498
+ ] }),
499
+ !collapsed && entries.map(([k, v]) => /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2 py-0.5 pl-2", children: [
500
+ /* @__PURE__ */ jsxs6("span", { className: "text-[10px] text-text-secondary font-mono shrink-0", children: [
501
+ k,
502
+ ":"
503
+ ] }),
504
+ /* @__PURE__ */ jsx6(ValueEditor, { value: v, path: `${path}.${k}`, onUpdate, depth: depth + 1 })
505
+ ] }, k))
506
+ ] });
507
+ }
508
+ return /* @__PURE__ */ jsx6("span", { className: "text-text-muted text-[10px] font-mono", children: String(value) });
509
+ }
510
+ function StoresTab() {
511
+ const allStores = useMemo4(() => [...getShellStores(), ...STUDIO_STORES], []);
512
+ const [activeStore, setActiveStore] = useState3(allStores[0]?.name || "");
513
+ const entry = useMemo4(() => allStores.find((s) => s.name === activeStore), [allStores, activeStore]);
514
+ const storeSnapshot = useSyncExternalStore(
515
+ useCallback((cb) => entry?.store?.subscribe?.(cb) || (() => {
516
+ }), [entry]),
517
+ useCallback(() => entry?.store?.getState?.() ?? {}, [entry])
518
+ );
519
+ const { stateEntries, actionEntries } = useMemo4(() => {
520
+ const stateE = [];
521
+ const actionE = [];
522
+ for (const [k, v] of Object.entries(storeSnapshot)) {
523
+ if (typeof v === "function") actionE.push([k, v]);
524
+ else stateE.push([k, v]);
525
+ }
526
+ return { stateEntries: stateE, actionEntries: actionE };
527
+ }, [storeSnapshot]);
528
+ const handleUpdate = useCallback((path, newValue) => {
529
+ if (!entry) return;
530
+ const parts = path.split(".");
531
+ const topKey = parts[1];
532
+ if (!topKey) return;
533
+ if (parts.length === 2) {
534
+ entry.store.setState({ [topKey]: newValue });
535
+ } else {
536
+ const current = entry.store.getState()[topKey];
537
+ try {
538
+ const clone = JSON.parse(JSON.stringify(current));
539
+ let target = clone;
540
+ for (let i = 2; i < parts.length - 1; i++) target = target[parts[i].replace(/\[(\d+)\]/, ".$1")];
541
+ const lastKey = parts[parts.length - 1].replace(/\[(\d+)\]/, "$1");
542
+ target[lastKey] = newValue;
543
+ entry.store.setState({ [topKey]: clone });
544
+ } catch {
545
+ entry.store.setState({ [topKey]: newValue });
546
+ }
547
+ }
548
+ }, [entry]);
549
+ const [actionFeedback, setActionFeedback] = useState3(null);
550
+ const [snapshots, setSnapshots] = useState3([]);
551
+ const [showDiff, setShowDiff] = useState3(null);
552
+ return /* @__PURE__ */ jsxs6("div", { className: "flex h-full", children: [
553
+ /* @__PURE__ */ jsx6("div", { className: "w-32 shrink-0 border-r border-border-subtle overflow-y-auto bg-surface-primary/50", children: ["shell", "studio"].map((group) => {
554
+ const groupStores = allStores.filter((s) => s.group === group);
555
+ if (groupStores.length === 0) return null;
556
+ return /* @__PURE__ */ jsxs6("div", { children: [
557
+ /* @__PURE__ */ jsx6("div", { className: "px-2 py-1 text-[8px] font-bold text-text-muted uppercase tracking-widest", children: group }),
558
+ groupStores.map((s) => /* @__PURE__ */ jsx6("button", { onClick: () => setActiveStore(s.name), className: `w-full text-left px-2 py-1.5 text-[10px] font-semibold transition-all ${activeStore === s.name ? "bg-emerald-500/10 text-emerald-400 border-r-2 border-emerald-400" : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`, children: s.name }, s.name))
559
+ ] }, group);
560
+ }) }),
561
+ /* @__PURE__ */ jsxs6("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3 space-y-3", children: [
562
+ /* @__PURE__ */ jsxs6("div", { children: [
563
+ /* @__PURE__ */ jsxs6("div", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest mb-2 flex items-center gap-1", children: [
564
+ /* @__PURE__ */ jsx6(Database, { size: 10 }),
565
+ " Estado (",
566
+ stateEntries.length,
567
+ ")"
568
+ ] }),
569
+ /* @__PURE__ */ jsx6("div", { className: "space-y-1", children: stateEntries.map(([key, value]) => /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2 py-0.5", children: [
570
+ /* @__PURE__ */ jsx6("span", { className: "text-[10px] text-text-primary font-mono font-semibold shrink-0 min-w-[100px]", children: key }),
571
+ /* @__PURE__ */ jsx6(ValueEditor, { value, path: `root.${key}`, onUpdate: handleUpdate, depth: 0 })
572
+ ] }, key)) })
573
+ ] }),
574
+ actionEntries.length > 0 && /* @__PURE__ */ jsxs6("div", { children: [
575
+ /* @__PURE__ */ jsxs6("div", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest mb-2 flex items-center gap-1", children: [
576
+ /* @__PURE__ */ jsx6(Zap2, { size: 10 }),
577
+ " Acciones (",
578
+ actionEntries.length,
579
+ ")"
580
+ ] }),
581
+ /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-1", children: actionEntries.map(([name, fn]) => /* @__PURE__ */ jsxs6("button", { onClick: () => {
582
+ try {
583
+ const r = fn();
584
+ if (r instanceof Promise) r.catch((e) => setActionFeedback(`\u274C ${name}: ${e.message}`));
585
+ setActionFeedback(`\u2705 ${name}()`);
586
+ } catch (e) {
587
+ setActionFeedback(`\u274C ${name}: ${e.message}`);
588
+ }
589
+ setTimeout(() => setActionFeedback(null), 2e3);
590
+ }, className: "px-2 py-1 rounded text-[9px] font-mono font-bold bg-surface-glass text-text-secondary hover:text-emerald-400 hover:bg-emerald-500/10 border border-border-subtle hover:border-emerald-500/20 transition-all", title: `Ejecutar ${name}()`, children: [
591
+ "\u25B6 ",
592
+ name
593
+ ] }, name)) }),
594
+ actionFeedback && /* @__PURE__ */ jsx6("div", { className: "mt-2 text-[10px] font-mono text-text-secondary animate-pulse", children: actionFeedback })
595
+ ] }),
596
+ /* @__PURE__ */ jsxs6("div", { className: "border-t border-border-subtle pt-3 mt-3", children: [
597
+ /* @__PURE__ */ jsxs6("div", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest mb-2 flex items-center gap-1", children: [
598
+ /* @__PURE__ */ jsx6(Camera, { size: 10 }),
599
+ " Snapshots"
600
+ ] }),
601
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-wrap gap-1 mb-2", children: [
602
+ /* @__PURE__ */ jsx6(
603
+ "button",
604
+ {
605
+ onClick: () => {
606
+ if (!entry) return;
607
+ const state = entry.store.getState();
608
+ const snap = {};
609
+ for (const [k, v] of Object.entries(state)) {
610
+ if (typeof v !== "function") snap[k] = v;
611
+ }
612
+ setSnapshots((prev) => [...prev, {
613
+ id: Date.now(),
614
+ label: `${activeStore} @ ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`,
615
+ data: JSON.parse(JSON.stringify(snap, (_, v) => {
616
+ if (v instanceof Map) return Object.fromEntries(v);
617
+ if (v instanceof Set) return Array.from(v);
618
+ return v;
619
+ }))
620
+ }]);
621
+ },
622
+ className: "px-2 py-1 rounded text-[9px] font-mono font-bold bg-violet-500/10 text-violet-400 hover:bg-violet-500/20 border border-violet-500/20",
623
+ children: "\u{1F4F8} Snapshot"
624
+ }
625
+ ),
626
+ snapshots.length > 0 && showDiff === null && /* @__PURE__ */ jsxs6(
627
+ "button",
628
+ {
629
+ onClick: () => setShowDiff(snapshots[snapshots.length - 1].id),
630
+ className: "px-2 py-1 rounded text-[9px] font-mono font-bold bg-cyan-500/10 text-cyan-400 hover:bg-cyan-500/20 border border-cyan-500/20",
631
+ children: [
632
+ /* @__PURE__ */ jsx6(ArrowLeftRight, { size: 10, className: "inline mr-1" }),
633
+ "Diff vs \xFAltimo"
634
+ ]
635
+ }
636
+ ),
637
+ showDiff !== null && /* @__PURE__ */ jsx6("button", { onClick: () => setShowDiff(null), className: "px-2 py-1 rounded text-[9px] font-mono bg-surface-tertiary text-text-secondary hover:bg-surface-tertiary", children: "Cerrar diff" }),
638
+ snapshots.length > 0 && /* @__PURE__ */ jsxs6(
639
+ "button",
640
+ {
641
+ onClick: () => {
642
+ const blob = new Blob([JSON.stringify(snapshots, null, 2)], { type: "application/json" });
643
+ const url = URL.createObjectURL(blob);
644
+ const a = document.createElement("a");
645
+ a.href = url;
646
+ a.download = `snapshots-${activeStore}.json`;
647
+ a.click();
648
+ URL.revokeObjectURL(url);
649
+ },
650
+ className: "px-2 py-1 rounded text-[9px] font-mono text-text-muted hover:text-text-primary hover:bg-surface-glass",
651
+ children: [
652
+ /* @__PURE__ */ jsx6(Download, { size: 10, className: "inline mr-1" }),
653
+ "Export"
654
+ ]
655
+ }
656
+ )
657
+ ] }),
658
+ snapshots.map((snap, i) => /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 py-0.5 text-[9px]", children: [
659
+ /* @__PURE__ */ jsx6("span", { className: "text-text-muted font-mono", children: snap.label }),
660
+ /* @__PURE__ */ jsx6("button", { onClick: () => setShowDiff(showDiff === snap.id ? null : snap.id), className: `px-1.5 py-0.5 rounded font-bold ${showDiff === snap.id ? "bg-cyan-500/20 text-cyan-400" : "text-text-muted hover:text-cyan-400"}`, children: "diff" }),
661
+ /* @__PURE__ */ jsx6("button", { onClick: () => setSnapshots((prev) => prev.filter((s) => s.id !== snap.id)), className: "text-text-muted hover:text-red-400", children: "\xD7" })
662
+ ] }, snap.id)),
663
+ showDiff !== null && (() => {
664
+ const snap = snapshots.find((s) => s.id === showDiff);
665
+ if (!snap) return null;
666
+ const current = {};
667
+ for (const [k, v] of stateEntries) current[k] = v;
668
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(snap.data), ...Object.keys(current)]);
669
+ return /* @__PURE__ */ jsxs6("div", { className: "mt-2 bg-surface-primary rounded border border-border-subtle p-2 max-h-[200px] overflow-y-auto custom-scrollbar", children: [
670
+ /* @__PURE__ */ jsxs6("div", { className: "text-[8px] text-text-muted mb-1", children: [
671
+ "Diff: ",
672
+ snap.label,
673
+ " \u2192 actual"
674
+ ] }),
675
+ Array.from(allKeys).map((key) => {
676
+ const oldVal = JSON.stringify(snap.data[key]);
677
+ const newVal = JSON.stringify(current[key], (_, v) => {
678
+ if (v instanceof Map) return Object.fromEntries(v);
679
+ if (v instanceof Set) return Array.from(v);
680
+ return v;
681
+ });
682
+ if (oldVal === newVal) return null;
683
+ return /* @__PURE__ */ jsxs6("div", { className: "py-0.5 font-mono text-[9px]", children: [
684
+ /* @__PURE__ */ jsxs6("span", { className: "text-text-secondary font-semibold", children: [
685
+ key,
686
+ ":"
687
+ ] }),
688
+ oldVal !== void 0 && /* @__PURE__ */ jsxs6("div", { className: "text-red-400/70 pl-3", children: [
689
+ "- ",
690
+ oldVal?.slice(0, 100)
691
+ ] }),
692
+ newVal !== void 0 && /* @__PURE__ */ jsxs6("div", { className: "text-emerald-400/70 pl-3", children: [
693
+ "+ ",
694
+ newVal?.slice(0, 100)
695
+ ] })
696
+ ] }, key);
697
+ })
698
+ ] });
699
+ })()
700
+ ] })
701
+ ] })
702
+ ] });
703
+ }
704
+
705
+ // src/components/debug/MorphStackTab.tsx
706
+ import { useMemo as useMemo5, useEffect as useEffect2, useState as useState4, useRef as useRef2 } from "react";
707
+ import { Layers, AlertTriangle as AlertTriangle3, ArrowUp, Clock, RotateCcw } from "lucide-react";
708
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
709
+ var _eventId = 0;
710
+ var MAX_EVENTS = 100;
711
+ var STAGE_ICONS = {
712
+ "2d": "\u{1F4CA}",
713
+ "3d": "\u{1F9CA}",
714
+ workbench: "\u{1F527}",
715
+ liquid: "\u{1F4A7}",
716
+ artifact: "\u{1F4C4}",
717
+ custom: "\u2699\uFE0F"
718
+ };
719
+ var STAGE_COLORS = {
720
+ "2d": "border-cyan-500 bg-cyan-500/10",
721
+ "3d": "border-violet-500 bg-violet-500/10",
722
+ workbench: "border-amber-500 bg-amber-500/10",
723
+ liquid: "border-blue-500 bg-blue-500/10",
724
+ artifact: "border-emerald-500 bg-emerald-500/10",
725
+ custom: "border-border-default bg-surface-glass"
726
+ };
727
+ function getTimestamp() {
728
+ const now = /* @__PURE__ */ new Date();
729
+ return `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`;
730
+ }
731
+ function MorphStackTab() {
732
+ const morphActiveStage = useMorphologyStore((s) => s.activeStage);
733
+ const morphHistory = useMorphologyStore((s) => s.stageHistory);
734
+ const layoutActiveStage = useLayoutStore((s) => s.activeStage);
735
+ const layoutHistory = useLayoutStore((s) => s.stageHistory);
736
+ const [events, setEvents] = useState4([]);
737
+ const eventLogRef = useRef2(null);
738
+ const isDesync = useMemo5(() => {
739
+ const morphType = morphActiveStage?.type || null;
740
+ const layoutType = layoutActiveStage?.type || null;
741
+ return morphType !== layoutType;
742
+ }, [morphActiveStage, layoutActiveStage]);
743
+ const stackDepth = morphHistory.length;
744
+ const isDeepStack = stackDepth > 5;
745
+ useEffect2(() => {
746
+ let prevStage = useMorphologyStore.getState().activeStage;
747
+ let prevDepth = useMorphologyStore.getState().stageHistory.length;
748
+ const unsub = useMorphologyStore.subscribe((state) => {
749
+ const newStage = state.activeStage;
750
+ const newDepth = state.stageHistory.length;
751
+ if (newStage !== prevStage || newDepth !== prevDepth) {
752
+ let action = "change";
753
+ let level = "info";
754
+ if (newDepth > prevDepth) {
755
+ action = "\u2B07\uFE0F pushStage";
756
+ } else if (newDepth < prevDepth && newStage) {
757
+ action = "\u2B06\uFE0F popStage";
758
+ } else if (!newStage && prevStage) {
759
+ action = "\u{1F5D1}\uFE0F clearStages";
760
+ level = "warn";
761
+ } else if (newStage && !prevStage) {
762
+ action = "\u{1F4CC} setStage";
763
+ } else {
764
+ action = "\u{1F504} setStage";
765
+ }
766
+ setEvents((prev) => {
767
+ const updated = [...prev, {
768
+ id: ++_eventId,
769
+ timestamp: getTimestamp(),
770
+ action,
771
+ stageType: newStage?.type || null,
772
+ label: newStage?.label || newStage?.type || "null",
773
+ data: { depth: newDepth, sourceNodeId: newStage?.sourceNodeId },
774
+ level
775
+ }];
776
+ return updated.length > MAX_EVENTS ? updated.slice(-MAX_EVENTS) : updated;
777
+ });
778
+ prevStage = newStage;
779
+ prevDepth = newDepth;
780
+ }
781
+ });
782
+ return unsub;
783
+ }, []);
784
+ useEffect2(() => {
785
+ if (eventLogRef.current) {
786
+ eventLogRef.current.scrollTop = eventLogRef.current.scrollHeight;
787
+ }
788
+ }, [events]);
789
+ return /* @__PURE__ */ jsxs7("div", { className: "flex h-full text-[10px]", children: [
790
+ /* @__PURE__ */ jsxs7("div", { className: "w-48 shrink-0 border-r border-border-subtle p-3 space-y-2 overflow-y-auto", children: [
791
+ /* @__PURE__ */ jsxs7("div", { className: "text-[9px] font-bold text-text-muted uppercase tracking-widest mb-2 flex items-center gap-1", children: [
792
+ /* @__PURE__ */ jsx7(Layers, { size: 10 }),
793
+ " Stack (",
794
+ stackDepth + (morphActiveStage ? 1 : 0),
795
+ ")"
796
+ ] }),
797
+ isDesync && /* @__PURE__ */ jsxs7("div", { className: "px-2 py-1.5 rounded-lg bg-red-500/10 border border-red-500/30 text-red-400 text-[9px] font-bold flex items-center gap-1 animate-pulse", children: [
798
+ /* @__PURE__ */ jsx7(AlertTriangle3, { size: 10 }),
799
+ " Stores desincronizados"
800
+ ] }),
801
+ isDeepStack && /* @__PURE__ */ jsxs7("div", { className: "px-2 py-1.5 rounded-lg bg-amber-500/10 border border-amber-500/30 text-amber-400 text-[9px] font-bold flex items-center gap-1", children: [
802
+ /* @__PURE__ */ jsx7(AlertTriangle3, { size: 10 }),
803
+ " Stack depth: ",
804
+ stackDepth,
805
+ " (posible leak)"
806
+ ] }),
807
+ morphActiveStage ? /* @__PURE__ */ jsxs7("div", { className: `px-3 py-2 rounded-xl border-2 ${STAGE_COLORS[morphActiveStage.type] || "border-border-default bg-surface-glass"} relative`, children: [
808
+ /* @__PURE__ */ jsx7("div", { className: "absolute -top-2 right-2 px-1.5 py-0.5 rounded text-[7px] font-bold bg-cyan-500 text-text-inverse uppercase", children: "Activo" }),
809
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5", children: [
810
+ /* @__PURE__ */ jsx7("span", { className: "text-lg", children: STAGE_ICONS[morphActiveStage.type] || "\u2753" }),
811
+ /* @__PURE__ */ jsxs7("div", { children: [
812
+ /* @__PURE__ */ jsx7("div", { className: "font-bold text-text-primary text-[11px]", children: morphActiveStage.type.toUpperCase() }),
813
+ morphActiveStage.label && /* @__PURE__ */ jsx7("div", { className: "text-text-secondary text-[9px]", children: morphActiveStage.label })
814
+ ] })
815
+ ] }),
816
+ morphActiveStage.sourceNodeId && /* @__PURE__ */ jsxs7("div", { className: "mt-1 text-[8px] text-text-muted font-mono truncate", children: [
817
+ "src: ",
818
+ morphActiveStage.sourceNodeId
819
+ ] })
820
+ ] }) : /* @__PURE__ */ jsx7("div", { className: "px-3 py-2 rounded-xl border border-dashed border-border-default text-text-muted text-center italic", children: "Sin stage activo" }),
821
+ morphHistory.length > 0 && /* @__PURE__ */ jsx7("div", { className: "flex justify-center text-text-muted", children: /* @__PURE__ */ jsx7(ArrowUp, { size: 12 }) }),
822
+ [...morphHistory].reverse().map((stage, i) => /* @__PURE__ */ jsx7(
823
+ "div",
824
+ {
825
+ className: `px-3 py-1.5 rounded-lg border ${STAGE_COLORS[stage.type] || "border-border-default bg-surface-tertiary/50"} opacity-50 hover:opacity-80 cursor-pointer transition-all`,
826
+ onClick: () => {
827
+ const popsNeeded = i + 1;
828
+ const ms = useMorphologyStore.getState();
829
+ const ls = useLayoutStore.getState();
830
+ for (let j = 0; j < popsNeeded; j++) {
831
+ ms.popStage();
832
+ ls.popStage();
833
+ }
834
+ },
835
+ title: `Click para volver a: ${stage.label || stage.type}`,
836
+ children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5", children: [
837
+ /* @__PURE__ */ jsx7("span", { children: STAGE_ICONS[stage.type] || "\u2753" }),
838
+ /* @__PURE__ */ jsx7("span", { className: "font-semibold text-text-primary", children: stage.type }),
839
+ stage.label && /* @__PURE__ */ jsxs7("span", { className: "text-text-muted truncate max-w-[80px]", children: [
840
+ " \xB7 ",
841
+ stage.label
842
+ ] })
843
+ ] })
844
+ },
845
+ i
846
+ ))
847
+ ] }),
848
+ /* @__PURE__ */ jsxs7("div", { className: "flex-1 flex flex-col", children: [
849
+ /* @__PURE__ */ jsxs7("div", { className: "px-3 py-1.5 border-b border-border-subtle flex items-center justify-between", children: [
850
+ /* @__PURE__ */ jsxs7("div", { className: "text-[9px] font-bold text-text-muted uppercase tracking-widest flex items-center gap-1", children: [
851
+ /* @__PURE__ */ jsx7(Clock, { size: 10 }),
852
+ " Eventos (",
853
+ events.length,
854
+ ")"
855
+ ] }),
856
+ /* @__PURE__ */ jsx7("button", { onClick: () => setEvents([]), className: "p-0.5 rounded hover:bg-surface-glass text-text-muted hover:text-text-secondary", title: "Limpiar eventos", children: /* @__PURE__ */ jsx7(RotateCcw, { size: 10 }) })
857
+ ] }),
858
+ /* @__PURE__ */ jsx7("div", { ref: eventLogRef, className: "flex-1 overflow-y-auto custom-scrollbar", children: events.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "flex items-center justify-center h-full text-text-muted italic", children: "Esperando eventos morph..." }) : events.map((evt) => /* @__PURE__ */ jsxs7(
859
+ "div",
860
+ {
861
+ className: `flex items-start gap-2 px-3 py-1 border-b border-border-subtle hover:bg-surface-glass ${evt.level === "warn" ? "bg-amber-500/5" : evt.level === "error" ? "bg-red-500/5" : ""}`,
862
+ children: [
863
+ /* @__PURE__ */ jsx7("span", { className: "text-text-muted shrink-0 font-mono w-[50px]", children: evt.timestamp }),
864
+ /* @__PURE__ */ jsx7("span", { className: "shrink-0 w-[90px] font-semibold text-text-secondary", children: evt.action }),
865
+ /* @__PURE__ */ jsx7("span", { className: `font-mono ${evt.stageType ? "text-cyan-400" : "text-text-muted"}`, children: evt.label }),
866
+ evt.data?.depth !== void 0 && /* @__PURE__ */ jsxs7("span", { className: "text-text-muted ml-auto shrink-0", children: [
867
+ "depth: ",
868
+ evt.data.depth
869
+ ] })
870
+ ]
871
+ },
872
+ evt.id
873
+ )) }),
874
+ isDesync && /* @__PURE__ */ jsxs7("div", { className: "px-3 py-2 border-t border-red-500/20 bg-red-500/5", children: [
875
+ /* @__PURE__ */ jsx7("div", { className: "text-[9px] font-bold text-red-400 mb-1", children: "\u26A0\uFE0F Store Desync Detectado" }),
876
+ /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-2 gap-2 text-[9px] font-mono", children: [
877
+ /* @__PURE__ */ jsxs7("div", { children: [
878
+ /* @__PURE__ */ jsx7("span", { className: "text-text-muted", children: "morph:" }),
879
+ " ",
880
+ /* @__PURE__ */ jsx7("span", { className: "text-violet-400", children: morphActiveStage?.type || "null" }),
881
+ /* @__PURE__ */ jsxs7("span", { className: "text-text-muted", children: [
882
+ " (depth: ",
883
+ morphHistory.length,
884
+ ")"
885
+ ] })
886
+ ] }),
887
+ /* @__PURE__ */ jsxs7("div", { children: [
888
+ /* @__PURE__ */ jsx7("span", { className: "text-text-muted", children: "layout:" }),
889
+ " ",
890
+ /* @__PURE__ */ jsx7("span", { className: "text-emerald-400", children: layoutActiveStage?.type || "null" }),
891
+ /* @__PURE__ */ jsxs7("span", { className: "text-text-muted", children: [
892
+ " (depth: ",
893
+ layoutHistory.length,
894
+ ")"
895
+ ] })
896
+ ] })
897
+ ] })
898
+ ] })
899
+ ] })
900
+ ] });
901
+ }
902
+
903
+ // src/components/debug/NetworkTab.tsx
904
+ import { useState as useState5, useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback2, useMemo as useMemo6 } from "react";
905
+ import { Globe, ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, RotateCcw as RotateCcw2 } from "lucide-react";
906
+
907
+ // src/lib/networkInterceptor.ts
908
+ var _networkId = 0;
909
+ var MAX_ENTRIES = 200;
910
+ var _entries = [];
911
+ var _listeners = /* @__PURE__ */ new Set();
912
+ function _getTimestamp() {
913
+ const now = /* @__PURE__ */ new Date();
914
+ return `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}:${String(now.getSeconds()).padStart(2, "0")}`;
915
+ }
916
+ function _addEntry(entry) {
917
+ _entries.push(entry);
918
+ if (_entries.length > MAX_ENTRIES) _entries.shift();
919
+ _listeners.forEach((fn) => fn());
920
+ }
921
+ function getNetworkEntries() {
922
+ return _entries;
923
+ }
924
+ function clearNetworkEntries() {
925
+ _entries.length = 0;
926
+ _listeners.forEach((fn) => fn());
927
+ }
928
+ function subscribeNetwork(cb) {
929
+ _listeners.add(cb);
930
+ return () => _listeners.delete(cb);
931
+ }
932
+ var _installed = false;
933
+ function installNetworkInterceptor() {
934
+ if (_installed) return;
935
+ _installed = true;
936
+ const _origFetch = window.fetch;
937
+ window.fetch = async function(input, init) {
938
+ const method = init?.method?.toUpperCase() || "GET";
939
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
940
+ const id = ++_networkId;
941
+ const t0 = performance.now();
942
+ let requestBody;
943
+ try {
944
+ if (init?.body) {
945
+ requestBody = typeof init.body === "string" ? init.body.slice(0, 2048) : "[binary]";
946
+ }
947
+ } catch {
948
+ }
949
+ try {
950
+ const res = await _origFetch.call(window, input, init);
951
+ const duration = Math.round(performance.now() - t0);
952
+ let responseBody;
953
+ let size = 0;
954
+ try {
955
+ const clone = res.clone();
956
+ const text = await clone.text();
957
+ size = text.length;
958
+ responseBody = text.slice(0, 2048);
959
+ } catch {
960
+ }
961
+ _addEntry({
962
+ id,
963
+ timestamp: _getTimestamp(),
964
+ method,
965
+ url,
966
+ status: res.status,
967
+ duration,
968
+ requestBody,
969
+ responseBody,
970
+ size
971
+ });
972
+ return res;
973
+ } catch (err) {
974
+ const duration = Math.round(performance.now() - t0);
975
+ _addEntry({
976
+ id,
977
+ timestamp: _getTimestamp(),
978
+ method,
979
+ url,
980
+ status: 0,
981
+ duration,
982
+ requestBody,
983
+ size: 0,
984
+ error: err.message
985
+ });
986
+ throw err;
987
+ }
988
+ };
989
+ }
990
+
991
+ // src/components/debug/NetworkTab.tsx
992
+ import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
993
+ installNetworkInterceptor();
994
+ var STATUS_COLORS = {
995
+ "2": "text-emerald-400",
996
+ "3": "text-amber-400",
997
+ "4": "text-red-400",
998
+ "5": "text-red-500",
999
+ "0": "text-text-muted"
1000
+ };
1001
+ function getStatusColor(status) {
1002
+ return STATUS_COLORS[String(status).charAt(0)] || "text-text-secondary";
1003
+ }
1004
+ function truncateUrl(url) {
1005
+ try {
1006
+ const u = new URL(url);
1007
+ const path = u.pathname + u.search;
1008
+ return path.length > 60 ? path.slice(0, 57) + "..." : path;
1009
+ } catch {
1010
+ return url.length > 60 ? url.slice(0, 57) + "..." : url;
1011
+ }
1012
+ }
1013
+ function getDomain(url) {
1014
+ try {
1015
+ return new URL(url).hostname;
1016
+ } catch {
1017
+ return "";
1018
+ }
1019
+ }
1020
+ function formatSize(bytes) {
1021
+ if (bytes < 1024) return `${bytes}B`;
1022
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
1023
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
1024
+ }
1025
+ function NetworkRow({ entry, isExpanded, onToggle }) {
1026
+ return /* @__PURE__ */ jsxs8(Fragment, { children: [
1027
+ /* @__PURE__ */ jsxs8(
1028
+ "div",
1029
+ {
1030
+ onClick: onToggle,
1031
+ className: `flex items-center gap-2 px-3 py-1 text-[10px] font-mono cursor-pointer hover:bg-surface-glass border-b border-border-subtle ${entry.error ? "bg-red-500/5" : ""}`,
1032
+ children: [
1033
+ isExpanded ? /* @__PURE__ */ jsx8(ChevronDown2, { size: 10, className: "text-text-muted" }) : /* @__PURE__ */ jsx8(ChevronRight2, { size: 10, className: "text-text-muted" }),
1034
+ /* @__PURE__ */ jsx8("span", { className: "text-text-muted w-[50px] shrink-0", children: entry.timestamp }),
1035
+ /* @__PURE__ */ jsx8("span", { className: `w-[40px] shrink-0 font-bold ${entry.method === "POST" ? "text-amber-400" : "text-cyan-400"}`, children: entry.method }),
1036
+ /* @__PURE__ */ jsx8("span", { className: `w-[30px] shrink-0 font-bold ${getStatusColor(entry.status)}`, children: entry.status || "ERR" }),
1037
+ /* @__PURE__ */ jsx8("span", { className: "flex-1 text-text-primary truncate", title: entry.url, children: truncateUrl(entry.url) }),
1038
+ /* @__PURE__ */ jsxs8("span", { className: "text-text-muted w-[50px] shrink-0 text-right", children: [
1039
+ entry.duration,
1040
+ "ms"
1041
+ ] }),
1042
+ /* @__PURE__ */ jsx8("span", { className: "text-text-muted w-[40px] shrink-0 text-right", children: formatSize(entry.size) })
1043
+ ]
1044
+ }
1045
+ ),
1046
+ isExpanded && /* @__PURE__ */ jsxs8("div", { className: "px-6 py-2 bg-surface-primary/80 border-b border-border-subtle text-[9px] font-mono space-y-2", children: [
1047
+ /* @__PURE__ */ jsxs8("div", { children: [
1048
+ /* @__PURE__ */ jsx8("span", { className: "text-text-muted", children: "URL:" }),
1049
+ " ",
1050
+ /* @__PURE__ */ jsx8("span", { className: "text-text-primary break-all", children: entry.url })
1051
+ ] }),
1052
+ entry.error && /* @__PURE__ */ jsxs8("div", { className: "text-red-400", children: [
1053
+ "Error: ",
1054
+ entry.error
1055
+ ] }),
1056
+ entry.requestBody && /* @__PURE__ */ jsxs8("div", { children: [
1057
+ /* @__PURE__ */ jsx8("div", { className: "text-text-muted mb-0.5", children: "Request Body:" }),
1058
+ /* @__PURE__ */ jsx8("pre", { className: "bg-surface-secondary rounded p-2 text-text-secondary overflow-x-auto max-h-[150px] overflow-y-auto whitespace-pre-wrap", children: (() => {
1059
+ try {
1060
+ return JSON.stringify(JSON.parse(entry.requestBody), null, 2);
1061
+ } catch {
1062
+ return entry.requestBody;
1063
+ }
1064
+ })() })
1065
+ ] }),
1066
+ entry.responseBody && /* @__PURE__ */ jsxs8("div", { children: [
1067
+ /* @__PURE__ */ jsx8("div", { className: "text-text-muted mb-0.5", children: "Response Body:" }),
1068
+ /* @__PURE__ */ jsx8("pre", { className: "bg-surface-secondary rounded p-2 text-text-secondary overflow-x-auto max-h-[150px] overflow-y-auto whitespace-pre-wrap", children: (() => {
1069
+ try {
1070
+ return JSON.stringify(JSON.parse(entry.responseBody), null, 2);
1071
+ } catch {
1072
+ return entry.responseBody;
1073
+ }
1074
+ })() })
1075
+ ] })
1076
+ ] })
1077
+ ] });
1078
+ }
1079
+ function NetworkTab() {
1080
+ const entries = useSyncExternalStore2(
1081
+ useCallback2((cb) => subscribeNetwork(cb), []),
1082
+ useCallback2(() => getNetworkEntries(), [])
1083
+ );
1084
+ const [expandedIds, setExpandedIds] = useState5(/* @__PURE__ */ new Set());
1085
+ const [domainFilter, setDomainFilter] = useState5("");
1086
+ const domains = useMemo6(() => {
1087
+ const set = /* @__PURE__ */ new Set();
1088
+ entries.forEach((e) => {
1089
+ const d = getDomain(e.url);
1090
+ if (d) set.add(d);
1091
+ });
1092
+ return Array.from(set).sort();
1093
+ }, [entries]);
1094
+ const filtered = useMemo6(() => {
1095
+ if (!domainFilter) return entries;
1096
+ return entries.filter((e) => getDomain(e.url).includes(domainFilter));
1097
+ }, [entries, domainFilter]);
1098
+ const toggleExpand = useCallback2((id) => {
1099
+ setExpandedIds((prev) => {
1100
+ const next = new Set(prev);
1101
+ if (next.has(id)) next.delete(id);
1102
+ else next.add(id);
1103
+ return next;
1104
+ });
1105
+ }, []);
1106
+ const totalErrors = useMemo6(() => entries.filter((e) => e.status >= 400 || e.error).length, [entries]);
1107
+ return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col h-full", children: [
1108
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 px-3 py-1.5 border-b border-border-subtle shrink-0", children: [
1109
+ /* @__PURE__ */ jsx8(Globe, { size: 12, className: "text-cyan-400" }),
1110
+ /* @__PURE__ */ jsx8("span", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest", children: "Network" }),
1111
+ /* @__PURE__ */ jsxs8("span", { className: "text-[9px] text-text-muted font-mono", children: [
1112
+ filtered.length,
1113
+ "/",
1114
+ entries.length
1115
+ ] }),
1116
+ totalErrors > 0 && /* @__PURE__ */ jsxs8("span", { className: "px-1.5 py-0.5 rounded-full text-[8px] font-bold bg-red-500/20 text-red-400", children: [
1117
+ totalErrors,
1118
+ " err"
1119
+ ] }),
1120
+ /* @__PURE__ */ jsx8("div", { className: "flex-1" }),
1121
+ domains.length > 0 && /* @__PURE__ */ jsxs8(
1122
+ "select",
1123
+ {
1124
+ value: domainFilter,
1125
+ onChange: (e) => setDomainFilter(e.target.value),
1126
+ className: "bg-surface-secondary border border-border-default rounded px-1.5 py-0.5 text-[9px] text-text-secondary outline-hidden",
1127
+ children: [
1128
+ /* @__PURE__ */ jsx8("option", { value: "", children: "All domains" }),
1129
+ domains.map((d) => /* @__PURE__ */ jsx8("option", { value: d, children: d }, d))
1130
+ ]
1131
+ }
1132
+ ),
1133
+ /* @__PURE__ */ jsx8("button", { onClick: clearNetworkEntries, className: "p-0.5 rounded hover:bg-surface-glass text-text-muted hover:text-text-secondary", title: "Limpiar", children: /* @__PURE__ */ jsx8(RotateCcw2, { size: 10 }) })
1134
+ ] }),
1135
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 px-3 py-0.5 text-[8px] font-bold text-text-muted uppercase tracking-widest border-b border-border-subtle shrink-0", children: [
1136
+ /* @__PURE__ */ jsx8("span", { className: "w-[14px]" }),
1137
+ /* @__PURE__ */ jsx8("span", { className: "w-[50px]", children: "Time" }),
1138
+ /* @__PURE__ */ jsx8("span", { className: "w-[40px]", children: "Method" }),
1139
+ /* @__PURE__ */ jsx8("span", { className: "w-[30px]", children: "Status" }),
1140
+ /* @__PURE__ */ jsx8("span", { className: "flex-1", children: "URL" }),
1141
+ /* @__PURE__ */ jsx8("span", { className: "w-[50px] text-right", children: "Duration" }),
1142
+ /* @__PURE__ */ jsx8("span", { className: "w-[40px] text-right", children: "Size" })
1143
+ ] }),
1144
+ /* @__PURE__ */ jsx8("div", { className: "flex-1 overflow-y-auto custom-scrollbar", children: filtered.length === 0 ? /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-center h-full text-text-muted text-[10px] italic", children: "Sin peticiones de red capturadas" }) : filtered.map((entry) => /* @__PURE__ */ jsx8(
1145
+ NetworkRow,
1146
+ {
1147
+ entry,
1148
+ isExpanded: expandedIds.has(entry.id),
1149
+ onToggle: () => toggleExpand(entry.id)
1150
+ },
1151
+ entry.id
1152
+ )) })
1153
+ ] });
1154
+ }
1155
+
1156
+ // src/components/debug/ProfilesTab.tsx
1157
+ import { useState as useState6, useMemo as useMemo7, useCallback as useCallback3, useSyncExternalStore as useSyncExternalStore3 } from "react";
1158
+ import { Plus, Trash2 as Trash22, Eye, Zap as Zap3, StickyNote, X, Star, StarOff } from "lucide-react";
1159
+
1160
+ // src/store/useDebugProfileStore.ts
1161
+ import { create } from "zustand";
1162
+ import { persist } from "zustand/middleware";
1163
+ var useDebugProfileStore = create()(
1164
+ persist(
1165
+ (set, get) => ({
1166
+ profiles: [],
1167
+ activeProfileId: null,
1168
+ createProfile: (name) => {
1169
+ const profile = {
1170
+ id: Date.now().toString(36),
1171
+ name,
1172
+ watchList: [],
1173
+ pinnedActions: [],
1174
+ logCategories: [],
1175
+ logLevels: ["info", "warn", "error", "debug"],
1176
+ notes: "",
1177
+ createdAt: Date.now()
1178
+ };
1179
+ set((s) => ({ profiles: [...s.profiles, profile], activeProfileId: profile.id }));
1180
+ },
1181
+ updateProfile: (id, partial) => {
1182
+ set((s) => ({
1183
+ profiles: s.profiles.map((p) => p.id === id ? { ...p, ...partial } : p)
1184
+ }));
1185
+ },
1186
+ deleteProfile: (id) => {
1187
+ set((s) => ({
1188
+ profiles: s.profiles.filter((p) => p.id !== id),
1189
+ activeProfileId: s.activeProfileId === id ? null : s.activeProfileId
1190
+ }));
1191
+ },
1192
+ activateProfile: (id) => set({ activeProfileId: id }),
1193
+ getActiveProfile: () => {
1194
+ const { profiles, activeProfileId } = get();
1195
+ return profiles.find((p) => p.id === activeProfileId);
1196
+ },
1197
+ addWatch: (profileId, entry) => {
1198
+ set((s) => ({
1199
+ profiles: s.profiles.map(
1200
+ (p) => p.id === profileId ? { ...p, watchList: [...p.watchList, entry] } : p
1201
+ )
1202
+ }));
1203
+ },
1204
+ removeWatch: (profileId, index) => {
1205
+ set((s) => ({
1206
+ profiles: s.profiles.map(
1207
+ (p) => p.id === profileId ? { ...p, watchList: p.watchList.filter((_, i) => i !== index) } : p
1208
+ )
1209
+ }));
1210
+ },
1211
+ addPinnedAction: (profileId, action) => {
1212
+ set((s) => ({
1213
+ profiles: s.profiles.map(
1214
+ (p) => p.id === profileId ? { ...p, pinnedActions: [...p.pinnedActions, action] } : p
1215
+ )
1216
+ }));
1217
+ },
1218
+ removePinnedAction: (profileId, index) => {
1219
+ set((s) => ({
1220
+ profiles: s.profiles.map(
1221
+ (p) => p.id === profileId ? { ...p, pinnedActions: p.pinnedActions.filter((_, i) => i !== index) } : p
1222
+ )
1223
+ }));
1224
+ }
1225
+ }),
1226
+ {
1227
+ name: "decido-debug-profiles-v1"
1228
+ }
1229
+ )
1230
+ );
1231
+
1232
+ // src/components/debug/ProfilesTab.tsx
1233
+ import { useEngineStore as useEngineStore4, useTimelineStore as useTimelineStore4, useUserStateStore as useUserStateStore2 } from "@decido/engine";
1234
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1235
+ var STORE_MAP = {
1236
+ Playground: usePlaygroundStore,
1237
+ Engine: useEngineStore4,
1238
+ Timeline: useTimelineStore4,
1239
+ Morphology: useMorphologyStore,
1240
+ UserState: useUserStateStore2,
1241
+ UIComponents: useUIComponentStore,
1242
+ MorphInstance: useMorphInstanceStore
1243
+ };
1244
+ function getNestedValue(obj, path) {
1245
+ const parts = path.split(".");
1246
+ let current = obj;
1247
+ for (const part of parts) {
1248
+ if (current == null) return void 0;
1249
+ current = current[part];
1250
+ }
1251
+ return current;
1252
+ }
1253
+ function formatValue(val) {
1254
+ if (val === null || val === void 0) return String(val);
1255
+ if (typeof val === "function") return "[fn]";
1256
+ if (typeof val === "object") {
1257
+ const tag = Object.prototype.toString.call(val);
1258
+ if (tag === "[object Map]") return `Map(${val.size})`;
1259
+ if (tag === "[object Set]") return `Set(${val.size})`;
1260
+ if (Array.isArray(val)) return `Array(${val.length})`;
1261
+ try {
1262
+ return JSON.stringify(val).slice(0, 100);
1263
+ } catch {
1264
+ return "[object]";
1265
+ }
1266
+ }
1267
+ return String(val);
1268
+ }
1269
+ function WatchValue({ storeName, path }) {
1270
+ const store = STORE_MAP[storeName];
1271
+ const snapshot = useSyncExternalStore3(
1272
+ useCallback3((cb) => store?.subscribe?.(cb) || (() => {
1273
+ }), [store]),
1274
+ useCallback3(() => store?.getState?.() ?? {}, [store])
1275
+ );
1276
+ const value = getNestedValue(snapshot, path);
1277
+ const formatted = formatValue(value);
1278
+ const color = typeof value === "number" ? "text-cyan-300" : typeof value === "string" ? "text-amber-300" : typeof value === "boolean" ? value ? "text-emerald-400" : "text-text-muted" : value === null || value === void 0 ? "text-text-muted italic" : "text-text-secondary";
1279
+ return /* @__PURE__ */ jsx9("span", { className: `font-mono text-[9px] ${color} max-w-[200px] truncate`, title: formatted, children: formatted });
1280
+ }
1281
+ function ProfileEditor({ profile }) {
1282
+ const { updateProfile, addWatch, removeWatch, addPinnedAction, removePinnedAction, deleteProfile } = useDebugProfileStore();
1283
+ const [newWatchStore, setNewWatchStore] = useState6(Object.keys(STORE_MAP)[0]);
1284
+ const [newWatchPath, setNewWatchPath] = useState6("");
1285
+ const [newActionStore, setNewActionStore] = useState6(Object.keys(STORE_MAP)[0]);
1286
+ const [newActionName, setNewActionName] = useState6("");
1287
+ const storeKeys = useMemo7(() => {
1288
+ const store = STORE_MAP[newWatchStore];
1289
+ if (!store) return [];
1290
+ const state = store.getState();
1291
+ return Object.entries(state).filter(([, v]) => typeof v !== "function").map(([k]) => k);
1292
+ }, [newWatchStore]);
1293
+ const actionKeys = useMemo7(() => {
1294
+ const store = STORE_MAP[newActionStore];
1295
+ if (!store) return [];
1296
+ const state = store.getState();
1297
+ return Object.entries(state).filter(([, v]) => typeof v === "function").map(([k]) => k);
1298
+ }, [newActionStore]);
1299
+ return /* @__PURE__ */ jsxs9("div", { className: "space-y-3 p-3", children: [
1300
+ /* @__PURE__ */ jsxs9("div", { children: [
1301
+ /* @__PURE__ */ jsxs9("div", { className: "text-[9px] font-bold text-text-secondary uppercase tracking-widest mb-1.5 flex items-center gap-1", children: [
1302
+ /* @__PURE__ */ jsx9(Eye, { size: 10 }),
1303
+ " Watch List (",
1304
+ profile.watchList.length,
1305
+ ")"
1306
+ ] }),
1307
+ profile.watchList.map((w, i) => /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 py-0.5 group", children: [
1308
+ /* @__PURE__ */ jsx9("span", { className: "text-[8px] text-text-muted font-bold uppercase", children: w.storeName }),
1309
+ /* @__PURE__ */ jsx9("span", { className: "text-[9px] text-text-secondary font-mono", children: w.path }),
1310
+ /* @__PURE__ */ jsx9("span", { className: "text-text-muted", children: "=" }),
1311
+ /* @__PURE__ */ jsx9(WatchValue, { storeName: w.storeName, path: w.path }),
1312
+ /* @__PURE__ */ jsx9("button", { onClick: () => removeWatch(profile.id, i), className: "opacity-0 group-hover:opacity-100 text-text-muted hover:text-red-400 transition-all ml-auto", children: /* @__PURE__ */ jsx9(X, { size: 10 }) })
1313
+ ] }, i)),
1314
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 mt-1", children: [
1315
+ /* @__PURE__ */ jsx9("select", { value: newWatchStore, onChange: (e) => setNewWatchStore(e.target.value), className: "bg-surface-secondary border border-border-default rounded px-1 py-0.5 text-[8px] text-text-secondary", children: Object.keys(STORE_MAP).map((n) => /* @__PURE__ */ jsx9("option", { value: n, children: n }, n)) }),
1316
+ /* @__PURE__ */ jsxs9("select", { value: newWatchPath, onChange: (e) => setNewWatchPath(e.target.value), className: "bg-surface-secondary border border-border-default rounded px-1 py-0.5 text-[8px] text-text-secondary flex-1", children: [
1317
+ /* @__PURE__ */ jsx9("option", { value: "", children: "Select property..." }),
1318
+ storeKeys.map((k) => /* @__PURE__ */ jsx9("option", { value: k, children: k }, k))
1319
+ ] }),
1320
+ /* @__PURE__ */ jsx9(
1321
+ "button",
1322
+ {
1323
+ onClick: () => {
1324
+ if (newWatchPath) {
1325
+ addWatch(profile.id, { storeName: newWatchStore, path: newWatchPath });
1326
+ setNewWatchPath("");
1327
+ }
1328
+ },
1329
+ disabled: !newWatchPath,
1330
+ className: "px-1.5 py-0.5 rounded text-[8px] font-bold bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20 border border-emerald-500/20 disabled:opacity-30",
1331
+ children: /* @__PURE__ */ jsx9(Plus, { size: 10 })
1332
+ }
1333
+ )
1334
+ ] })
1335
+ ] }),
1336
+ /* @__PURE__ */ jsxs9("div", { children: [
1337
+ /* @__PURE__ */ jsxs9("div", { className: "text-[9px] font-bold text-text-secondary uppercase tracking-widest mb-1.5 flex items-center gap-1", children: [
1338
+ /* @__PURE__ */ jsx9(Zap3, { size: 10 }),
1339
+ " Quick Actions (",
1340
+ profile.pinnedActions.length,
1341
+ ")"
1342
+ ] }),
1343
+ /* @__PURE__ */ jsx9("div", { className: "flex flex-wrap gap-1 mb-1", children: profile.pinnedActions.map((a, i) => /* @__PURE__ */ jsxs9(
1344
+ "button",
1345
+ {
1346
+ onClick: () => {
1347
+ const store = STORE_MAP[a.storeName];
1348
+ if (store) {
1349
+ const fn = store.getState()[a.actionName];
1350
+ if (typeof fn === "function") fn();
1351
+ }
1352
+ },
1353
+ className: "group px-2 py-0.5 rounded text-[8px] font-mono bg-surface-glass text-text-secondary hover:text-amber-400 hover:bg-amber-500/10 border border-border-subtle hover:border-amber-500/20 flex items-center gap-1",
1354
+ children: [
1355
+ "\u25B6 ",
1356
+ a.storeName,
1357
+ ".",
1358
+ a.actionName,
1359
+ /* @__PURE__ */ jsx9("span", { onClick: (e) => {
1360
+ e.stopPropagation();
1361
+ removePinnedAction(profile.id, i);
1362
+ }, className: "opacity-0 group-hover:opacity-100 text-text-muted hover:text-red-400", children: /* @__PURE__ */ jsx9(X, { size: 8 }) })
1363
+ ]
1364
+ },
1365
+ i
1366
+ )) }),
1367
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
1368
+ /* @__PURE__ */ jsx9("select", { value: newActionStore, onChange: (e) => setNewActionStore(e.target.value), className: "bg-surface-secondary border border-border-default rounded px-1 py-0.5 text-[8px] text-text-secondary", children: Object.keys(STORE_MAP).map((n) => /* @__PURE__ */ jsx9("option", { value: n, children: n }, n)) }),
1369
+ /* @__PURE__ */ jsxs9("select", { value: newActionName, onChange: (e) => setNewActionName(e.target.value), className: "bg-surface-secondary border border-border-default rounded px-1 py-0.5 text-[8px] text-text-secondary flex-1", children: [
1370
+ /* @__PURE__ */ jsx9("option", { value: "", children: "Select action..." }),
1371
+ actionKeys.map((k) => /* @__PURE__ */ jsx9("option", { value: k, children: k }, k))
1372
+ ] }),
1373
+ /* @__PURE__ */ jsx9(
1374
+ "button",
1375
+ {
1376
+ onClick: () => {
1377
+ if (newActionName) {
1378
+ addPinnedAction(profile.id, { storeName: newActionStore, actionName: newActionName });
1379
+ setNewActionName("");
1380
+ }
1381
+ },
1382
+ disabled: !newActionName,
1383
+ className: "px-1.5 py-0.5 rounded text-[8px] font-bold bg-amber-500/10 text-amber-400 hover:bg-amber-500/20 border border-amber-500/20 disabled:opacity-30",
1384
+ children: /* @__PURE__ */ jsx9(Plus, { size: 10 })
1385
+ }
1386
+ )
1387
+ ] })
1388
+ ] }),
1389
+ /* @__PURE__ */ jsxs9("div", { children: [
1390
+ /* @__PURE__ */ jsxs9("div", { className: "text-[9px] font-bold text-text-secondary uppercase tracking-widest mb-1 flex items-center gap-1", children: [
1391
+ /* @__PURE__ */ jsx9(StickyNote, { size: 10 }),
1392
+ " Notas"
1393
+ ] }),
1394
+ /* @__PURE__ */ jsx9(
1395
+ "textarea",
1396
+ {
1397
+ value: profile.notes,
1398
+ onChange: (e) => updateProfile(profile.id, { notes: e.target.value }),
1399
+ placeholder: "Hip\xF3tesis de debugging, observaciones...",
1400
+ className: "w-full bg-surface-secondary border border-border-default rounded px-2 py-1.5 text-[9px] text-text-primary font-mono outline-hidden focus:border-violet-500/50 resize-y min-h-[40px] max-h-[120px]"
1401
+ }
1402
+ )
1403
+ ] }),
1404
+ /* @__PURE__ */ jsxs9("button", { onClick: () => deleteProfile(profile.id), className: "flex items-center gap-1 px-2 py-1 rounded text-[9px] text-red-400/60 hover:text-red-400 hover:bg-red-500/10 transition-all", children: [
1405
+ /* @__PURE__ */ jsx9(Trash22, { size: 10 }),
1406
+ " Eliminar perfil"
1407
+ ] })
1408
+ ] });
1409
+ }
1410
+ function ProfilesTab() {
1411
+ const profiles = useDebugProfileStore((s) => s.profiles);
1412
+ const activeProfileId = useDebugProfileStore((s) => s.activeProfileId);
1413
+ const { createProfile, activateProfile } = useDebugProfileStore();
1414
+ const [newName, setNewName] = useState6("");
1415
+ const activeProfile = useMemo7(() => profiles.find((p) => p.id === activeProfileId), [profiles, activeProfileId]);
1416
+ return /* @__PURE__ */ jsxs9("div", { className: "flex h-full", children: [
1417
+ /* @__PURE__ */ jsxs9("div", { className: "w-40 shrink-0 border-r border-border-subtle overflow-y-auto bg-surface-primary/50 flex flex-col", children: [
1418
+ /* @__PURE__ */ jsxs9("div", { className: "p-2", children: [
1419
+ /* @__PURE__ */ jsx9("div", { className: "text-[8px] font-bold text-text-muted uppercase tracking-widest mb-1", children: "Perfiles" }),
1420
+ profiles.map((p) => /* @__PURE__ */ jsxs9(
1421
+ "button",
1422
+ {
1423
+ onClick: () => activateProfile(p.id),
1424
+ className: `w-full text-left px-2 py-1.5 text-[10px] font-semibold transition-all rounded mb-0.5 flex items-center gap-1.5 ${activeProfileId === p.id ? "bg-violet-500/10 text-violet-400 border-r-2 border-violet-400" : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`,
1425
+ children: [
1426
+ activeProfileId === p.id ? /* @__PURE__ */ jsx9(Star, { size: 10 }) : /* @__PURE__ */ jsx9(StarOff, { size: 10, className: "opacity-30" }),
1427
+ /* @__PURE__ */ jsx9("span", { className: "truncate", children: p.name }),
1428
+ /* @__PURE__ */ jsx9("span", { className: "ml-auto text-[8px] text-text-muted", children: p.watchList.length })
1429
+ ]
1430
+ },
1431
+ p.id
1432
+ ))
1433
+ ] }),
1434
+ /* @__PURE__ */ jsx9("div", { className: "mt-auto p-2 border-t border-border-subtle", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1", children: [
1435
+ /* @__PURE__ */ jsx9(
1436
+ "input",
1437
+ {
1438
+ value: newName,
1439
+ onChange: (e) => setNewName(e.target.value),
1440
+ onKeyDown: (e) => {
1441
+ if (e.key === "Enter" && newName.trim()) {
1442
+ createProfile(newName.trim());
1443
+ setNewName("");
1444
+ }
1445
+ },
1446
+ placeholder: "Nuevo perfil...",
1447
+ className: "flex-1 bg-surface-secondary border border-border-default rounded px-1.5 py-0.5 text-[9px] text-text-primary outline-hidden focus:border-violet-500/50"
1448
+ }
1449
+ ),
1450
+ /* @__PURE__ */ jsx9(
1451
+ "button",
1452
+ {
1453
+ onClick: () => {
1454
+ if (newName.trim()) {
1455
+ createProfile(newName.trim());
1456
+ setNewName("");
1457
+ }
1458
+ },
1459
+ disabled: !newName.trim(),
1460
+ className: "p-1 rounded bg-violet-500/10 text-violet-400 hover:bg-violet-500/20 disabled:opacity-30",
1461
+ children: /* @__PURE__ */ jsx9(Plus, { size: 12 })
1462
+ }
1463
+ )
1464
+ ] }) })
1465
+ ] }),
1466
+ /* @__PURE__ */ jsx9("div", { className: "flex-1 overflow-y-auto custom-scrollbar", children: activeProfile ? /* @__PURE__ */ jsx9(ProfileEditor, { profile: activeProfile }) : /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-center h-full text-text-muted text-[10px] italic flex-col gap-2", children: [
1467
+ /* @__PURE__ */ jsx9("span", { children: "Selecciona o crea un perfil de debug" }),
1468
+ /* @__PURE__ */ jsx9("span", { className: "text-[8px] text-text-muted", children: "Los perfiles te permiten monitorear variables espec\xEDficas, ejecutar acciones, y tomar notas" })
1469
+ ] }) })
1470
+ ] });
1471
+ }
1472
+
1473
+ // src/components/debug/ActionTimelineTab.tsx
1474
+ import { useMemo as useMemo8, useRef as useRef3, useEffect as useEffect3 } from "react";
1475
+ import { Clock as Clock2, Pause, Play, RotateCcw as RotateCcw3, Search } from "lucide-react";
1476
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1477
+ var STORE_COLORS = {
1478
+ morph: "border-l-violet-500 bg-violet-500/5",
1479
+ layout: "border-l-emerald-500 bg-emerald-500/5",
1480
+ gemini: "border-l-blue-500 bg-blue-500/5",
1481
+ chat: "border-l-cyan-500 bg-cyan-500/5",
1482
+ store: "border-l-amber-500 bg-amber-500/5",
1483
+ engine: "border-l-orange-500 bg-orange-500/5",
1484
+ network: "border-l-teal-500 bg-teal-500/5",
1485
+ shell: "border-l-pink-500 bg-pink-500/5",
1486
+ system: "border-l-text-muted bg-surface-glass"
1487
+ };
1488
+ var STORE_BADGES = {
1489
+ morph: "bg-violet-500/20 text-violet-400",
1490
+ layout: "bg-emerald-500/20 text-emerald-400",
1491
+ gemini: "bg-blue-500/20 text-blue-400",
1492
+ chat: "bg-cyan-500/20 text-cyan-400",
1493
+ store: "bg-amber-500/20 text-amber-400",
1494
+ engine: "bg-orange-500/20 text-orange-400",
1495
+ network: "bg-teal-500/20 text-teal-400",
1496
+ shell: "bg-pink-500/20 text-pink-400",
1497
+ system: "bg-surface-glass text-text-secondary"
1498
+ };
1499
+ function TimelineCard({ event }) {
1500
+ const colors = STORE_COLORS[event.storeName] || "border-l-text-muted bg-surface-glass";
1501
+ const badge = STORE_BADGES[event.storeName] || "bg-surface-glass text-text-secondary";
1502
+ return /* @__PURE__ */ jsxs10("div", { className: `border-l-2 ${colors} px-3 py-1.5 hover:bg-surface-glass transition-colors`, children: [
1503
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 text-[10px]", children: [
1504
+ /* @__PURE__ */ jsx10("span", { className: "text-text-muted font-mono shrink-0 w-[65px]", children: event.timestamp }),
1505
+ /* @__PURE__ */ jsx10("span", { className: `px-1.5 py-0.5 rounded text-[8px] font-bold uppercase tracking-wider ${badge}`, children: event.storeName }),
1506
+ /* @__PURE__ */ jsx10("span", { className: "font-semibold text-text-primary truncate", children: event.actionName }),
1507
+ event.level === "warn" && /* @__PURE__ */ jsx10("span", { className: "text-[8px] text-amber-400", children: "\u26A0" }),
1508
+ event.level === "error" && /* @__PURE__ */ jsx10("span", { className: "text-[8px] text-red-400", children: "\u2715" })
1509
+ ] }),
1510
+ event.data && /* @__PURE__ */ jsx10("div", { className: "mt-0.5 text-[9px] text-text-muted font-mono truncate max-w-full", children: typeof event.data === "object" ? JSON.stringify(event.data) : String(event.data) })
1511
+ ] });
1512
+ }
1513
+ function ActionTimelineTab() {
1514
+ const events = useActionTimelineStore((s) => s.events);
1515
+ const isPaused = useActionTimelineStore((s) => s.isPaused);
1516
+ const filter = useActionTimelineStore((s) => s.filter);
1517
+ const { clear, togglePause, setFilter } = useActionTimelineStore();
1518
+ const scrollRef = useRef3(null);
1519
+ const filtered = useMemo8(() => {
1520
+ if (!filter) return events;
1521
+ const q = filter.toLowerCase();
1522
+ return events.filter(
1523
+ (e) => e.storeName.includes(q) || e.actionName.toLowerCase().includes(q)
1524
+ );
1525
+ }, [events, filter]);
1526
+ useEffect3(() => {
1527
+ if (!isPaused && scrollRef.current) {
1528
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
1529
+ }
1530
+ }, [filtered, isPaused]);
1531
+ return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col h-full", children: [
1532
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 px-3 py-1.5 border-b border-border-subtle shrink-0", children: [
1533
+ /* @__PURE__ */ jsx10(Clock2, { size: 12, className: "text-amber-400" }),
1534
+ /* @__PURE__ */ jsx10("span", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest", children: "Timeline" }),
1535
+ /* @__PURE__ */ jsxs10("span", { className: "text-[9px] text-text-muted font-mono", children: [
1536
+ filtered.length,
1537
+ "/",
1538
+ events.length
1539
+ ] }),
1540
+ isPaused && /* @__PURE__ */ jsx10("span", { className: "px-1.5 py-0.5 rounded text-[8px] font-bold bg-amber-500/20 text-amber-400 animate-pulse", children: "PAUSADO" }),
1541
+ /* @__PURE__ */ jsx10("div", { className: "flex-1" }),
1542
+ /* @__PURE__ */ jsxs10("div", { className: "flex items-center bg-surface-secondary border border-border-default rounded px-1.5 gap-1", children: [
1543
+ /* @__PURE__ */ jsx10(Search, { size: 10, className: "text-text-muted" }),
1544
+ /* @__PURE__ */ jsx10(
1545
+ "input",
1546
+ {
1547
+ value: filter,
1548
+ onChange: (e) => setFilter(e.target.value),
1549
+ placeholder: "Filtrar...",
1550
+ className: "bg-transparent text-[9px] text-text-primary outline-hidden w-24 py-0.5"
1551
+ }
1552
+ )
1553
+ ] }),
1554
+ /* @__PURE__ */ jsx10("button", { onClick: togglePause, className: `p-1 rounded transition-colors ${isPaused ? "bg-amber-500/10 text-amber-400" : "text-text-muted hover:text-text-secondary hover:bg-surface-glass"}`, title: isPaused ? "Reanudar" : "Pausar", children: isPaused ? /* @__PURE__ */ jsx10(Play, { size: 10 }) : /* @__PURE__ */ jsx10(Pause, { size: 10 }) }),
1555
+ /* @__PURE__ */ jsx10("button", { onClick: clear, className: "p-0.5 rounded hover:bg-surface-glass text-text-muted hover:text-text-secondary", title: "Limpiar", children: /* @__PURE__ */ jsx10(RotateCcw3, { size: 10 }) })
1556
+ ] }),
1557
+ /* @__PURE__ */ jsx10("div", { ref: scrollRef, className: "flex-1 overflow-y-auto custom-scrollbar", children: filtered.length === 0 ? /* @__PURE__ */ jsx10("div", { className: "flex items-center justify-center h-full text-text-muted text-[10px] italic", children: events.length === 0 ? "Esperando acciones..." : "Sin resultados para el filtro" }) : filtered.map((evt) => /* @__PURE__ */ jsx10(TimelineCard, { event: evt }, evt.id)) })
1558
+ ] });
1559
+ }
1560
+
1561
+ // src/components/debug/PerformanceTab.tsx
1562
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
1563
+ import { Cpu, HardDrive, BarChart3 } from "lucide-react";
1564
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1565
+ function usePerfMetrics(intervalMs = 1e3) {
1566
+ const [metrics, setMetrics] = useState7({ fps: 0, memory: null, domNodes: 0 });
1567
+ const framesRef = useRef4(0);
1568
+ const lastTimeRef = useRef4(performance.now());
1569
+ useEffect4(() => {
1570
+ let rafId;
1571
+ const countFrame = () => {
1572
+ framesRef.current++;
1573
+ rafId = requestAnimationFrame(countFrame);
1574
+ };
1575
+ rafId = requestAnimationFrame(countFrame);
1576
+ const timer = setInterval(() => {
1577
+ const now = performance.now();
1578
+ const elapsed = (now - lastTimeRef.current) / 1e3;
1579
+ const fps = Math.round(framesRef.current / elapsed);
1580
+ framesRef.current = 0;
1581
+ lastTimeRef.current = now;
1582
+ let memory = null;
1583
+ const perfMemory = performance.memory;
1584
+ if (perfMemory) {
1585
+ const usedMB = Math.round(perfMemory.usedJSHeapSize / 1024 / 1024);
1586
+ const totalMB = Math.round(perfMemory.jsHeapSizeLimit / 1024 / 1024);
1587
+ memory = { usedMB, totalMB, percent: Math.round(usedMB / totalMB * 100) };
1588
+ }
1589
+ const domNodes = document.querySelectorAll("*").length;
1590
+ setMetrics({ fps, memory, domNodes });
1591
+ }, intervalMs);
1592
+ return () => {
1593
+ cancelAnimationFrame(rafId);
1594
+ clearInterval(timer);
1595
+ };
1596
+ }, [intervalMs]);
1597
+ return metrics;
1598
+ }
1599
+ function Sparkline({ data, color, height = 24, width = 80 }) {
1600
+ if (data.length < 2) return null;
1601
+ const max = Math.max(...data, 1);
1602
+ const min = Math.min(...data, 0);
1603
+ const range = max - min || 1;
1604
+ const points = data.map((v, i) => {
1605
+ const x = i / (data.length - 1) * width;
1606
+ const y = height - (v - min) / range * height;
1607
+ return `${x},${y}`;
1608
+ }).join(" ");
1609
+ return /* @__PURE__ */ jsx11("svg", { width, height, className: "shrink-0", children: /* @__PURE__ */ jsx11("polyline", { points, fill: "none", stroke: color, strokeWidth: "1.5", strokeLinejoin: "round" }) });
1610
+ }
1611
+ function FpsGauge({ fps }) {
1612
+ const color = fps >= 50 ? "text-emerald-400" : fps >= 30 ? "text-amber-400" : "text-red-400";
1613
+ const bg = fps >= 50 ? "bg-emerald-500/10" : fps >= 30 ? "bg-amber-500/10" : "bg-red-500/10";
1614
+ const pct = Math.min(fps / 60, 1);
1615
+ return /* @__PURE__ */ jsxs11("div", { className: `rounded-xl ${bg} px-4 py-3 flex items-center gap-3`, children: [
1616
+ /* @__PURE__ */ jsxs11("div", { className: "relative w-12 h-12", children: [
1617
+ /* @__PURE__ */ jsxs11("svg", { className: "w-12 h-12 -rotate-90", viewBox: "0 0 48 48", children: [
1618
+ /* @__PURE__ */ jsx11("circle", { cx: "24", cy: "24", r: "20", fill: "none", stroke: "currentColor", className: "text-text-muted", strokeWidth: "3" }),
1619
+ /* @__PURE__ */ jsx11(
1620
+ "circle",
1621
+ {
1622
+ cx: "24",
1623
+ cy: "24",
1624
+ r: "20",
1625
+ fill: "none",
1626
+ stroke: "currentColor",
1627
+ className: color,
1628
+ strokeWidth: "3",
1629
+ strokeDasharray: `${pct * 125.6} 125.6`,
1630
+ strokeLinecap: "round"
1631
+ }
1632
+ )
1633
+ ] }),
1634
+ /* @__PURE__ */ jsx11("span", { className: `absolute inset-0 flex items-center justify-center text-[11px] font-bold ${color}`, children: fps })
1635
+ ] }),
1636
+ /* @__PURE__ */ jsxs11("div", { children: [
1637
+ /* @__PURE__ */ jsx11("div", { className: "text-[10px] font-bold text-text-primary", children: "FPS" }),
1638
+ /* @__PURE__ */ jsx11("div", { className: `text-[9px] ${color}`, children: fps >= 50 ? "\u2705 Excelente" : fps >= 30 ? "\u26A0\uFE0F Aceptable" : "\u{1F534} Bajo" })
1639
+ ] })
1640
+ ] });
1641
+ }
1642
+ function PerformanceTab() {
1643
+ const metrics = usePerfMetrics(500);
1644
+ const [fpsHistory, setFpsHistory] = useState7([]);
1645
+ const [memHistory, setMemHistory] = useState7([]);
1646
+ useEffect4(() => {
1647
+ setFpsHistory((prev) => {
1648
+ const next = [...prev, metrics.fps];
1649
+ return next.length > 60 ? next.slice(-60) : next;
1650
+ });
1651
+ if (metrics.memory) {
1652
+ setMemHistory((prev) => {
1653
+ const next = [...prev, metrics.memory.usedMB];
1654
+ return next.length > 60 ? next.slice(-60) : next;
1655
+ });
1656
+ }
1657
+ }, [metrics.fps, metrics.memory?.usedMB]);
1658
+ return /* @__PURE__ */ jsxs11("div", { className: "p-3 space-y-3 overflow-y-auto h-full custom-scrollbar", children: [
1659
+ /* @__PURE__ */ jsxs11("div", { className: "text-[9px] font-bold text-text-muted uppercase tracking-widest flex items-center gap-1", children: [
1660
+ /* @__PURE__ */ jsx11(BarChart3, { size: 10 }),
1661
+ " Performance Dashboard"
1662
+ ] }),
1663
+ /* @__PURE__ */ jsxs11("div", { className: "grid grid-cols-3 gap-3", children: [
1664
+ /* @__PURE__ */ jsx11(FpsGauge, { fps: metrics.fps }),
1665
+ /* @__PURE__ */ jsxs11("div", { className: "rounded-xl bg-blue-500/10 px-4 py-3", children: [
1666
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 mb-1", children: [
1667
+ /* @__PURE__ */ jsx11(HardDrive, { size: 12, className: "text-blue-400" }),
1668
+ /* @__PURE__ */ jsx11("span", { className: "text-[10px] font-bold text-text-primary", children: "Memoria" })
1669
+ ] }),
1670
+ metrics.memory ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
1671
+ /* @__PURE__ */ jsxs11("div", { className: "text-[14px] font-bold text-blue-400", children: [
1672
+ metrics.memory.usedMB,
1673
+ "MB"
1674
+ ] }),
1675
+ /* @__PURE__ */ jsxs11("div", { className: "text-[9px] text-text-muted", children: [
1676
+ metrics.memory.percent,
1677
+ "% de ",
1678
+ metrics.memory.totalMB,
1679
+ "MB"
1680
+ ] }),
1681
+ /* @__PURE__ */ jsx11("div", { className: "mt-1 h-1.5 bg-surface-tertiary rounded-full overflow-hidden", children: /* @__PURE__ */ jsx11(
1682
+ "div",
1683
+ {
1684
+ className: `h-full rounded-full transition-all ${metrics.memory.percent > 80 ? "bg-red-500" : metrics.memory.percent > 50 ? "bg-amber-500" : "bg-blue-500"}`,
1685
+ style: { width: `${metrics.memory.percent}%` }
1686
+ }
1687
+ ) })
1688
+ ] }) : /* @__PURE__ */ jsx11("div", { className: "text-[9px] text-text-muted italic", children: "No disponible" })
1689
+ ] }),
1690
+ /* @__PURE__ */ jsxs11("div", { className: "rounded-xl bg-violet-500/10 px-4 py-3", children: [
1691
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 mb-1", children: [
1692
+ /* @__PURE__ */ jsx11(Cpu, { size: 12, className: "text-violet-400" }),
1693
+ /* @__PURE__ */ jsx11("span", { className: "text-[10px] font-bold text-text-primary", children: "DOM" })
1694
+ ] }),
1695
+ /* @__PURE__ */ jsx11("div", { className: "text-[14px] font-bold text-violet-400", children: metrics.domNodes.toLocaleString() }),
1696
+ /* @__PURE__ */ jsx11("div", { className: "text-[9px] text-text-muted", children: metrics.domNodes > 5e3 ? "\u26A0\uFE0F Alto" : metrics.domNodes > 2e3 ? "Normal" : "\u2705 Ligero" })
1697
+ ] })
1698
+ ] }),
1699
+ /* @__PURE__ */ jsxs11("div", { className: "grid grid-cols-2 gap-3", children: [
1700
+ /* @__PURE__ */ jsxs11("div", { className: "rounded-xl bg-surface-secondary/50 border border-border-subtle px-3 py-2", children: [
1701
+ /* @__PURE__ */ jsx11("div", { className: "text-[9px] text-text-muted mb-1", children: "FPS (\xFAltimos 30s)" }),
1702
+ /* @__PURE__ */ jsx11(Sparkline, { data: fpsHistory, color: "#34d399", width: 200, height: 30 })
1703
+ ] }),
1704
+ metrics.memory && /* @__PURE__ */ jsxs11("div", { className: "rounded-xl bg-surface-secondary/50 border border-border-subtle px-3 py-2", children: [
1705
+ /* @__PURE__ */ jsx11("div", { className: "text-[9px] text-text-muted mb-1", children: "Memoria (\xFAltimos 30s)" }),
1706
+ /* @__PURE__ */ jsx11(Sparkline, { data: memHistory, color: "#60a5fa", width: 200, height: 30 })
1707
+ ] })
1708
+ ] })
1709
+ ] });
1710
+ }
1711
+
1712
+ // src/components/debug/ExportTab.tsx
1713
+ import { useCallback as useCallback5, useState as useState8 } from "react";
1714
+ import { Download as Download2, Copy as Copy2, Check as Check2, FileJson, FileText } from "lucide-react";
1715
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1716
+ function generateReport() {
1717
+ const now = /* @__PURE__ */ new Date();
1718
+ return {
1719
+ meta: {
1720
+ exportedAt: now.toISOString(),
1721
+ userAgent: navigator.userAgent,
1722
+ url: window.location.href,
1723
+ screenSize: `${window.innerWidth}x${window.innerHeight}`
1724
+ },
1725
+ logs: useDebugPanelStore.getState().logEntries.slice(-100),
1726
+ timeline: useActionTimelineStore.getState().events,
1727
+ network: getNetworkEntries(),
1728
+ morphology: {
1729
+ activeStage: useMorphologyStore.getState().activeStage,
1730
+ stageHistory: useMorphologyStore.getState().stageHistory
1731
+ },
1732
+ layout: {
1733
+ activeStage: useLayoutStore.getState().activeStage,
1734
+ stageHistory: useLayoutStore.getState().stageHistory,
1735
+ slots: useLayoutStore.getState().slots
1736
+ },
1737
+ instances: (() => {
1738
+ const inst = useMorphInstanceStore.getState().instances;
1739
+ const arr = [];
1740
+ inst.forEach((v, k) => arr.push({ instanceId: k, ...v }));
1741
+ return arr;
1742
+ })(),
1743
+ profiles: useDebugProfileStore.getState().profiles
1744
+ };
1745
+ }
1746
+ function generateMarkdownReport() {
1747
+ const report = generateReport();
1748
+ const lines = [];
1749
+ const ts = (/* @__PURE__ */ new Date()).toLocaleString();
1750
+ lines.push(`# Debug Report \u2014 ${ts}
1751
+ `);
1752
+ lines.push(`## Meta`);
1753
+ lines.push(`- **Screen**: ${report.meta.screenSize}`);
1754
+ lines.push(`- **URL**: ${report.meta.url}`);
1755
+ lines.push(`- **UA**: ${report.meta.userAgent}
1756
+ `);
1757
+ lines.push(`## Morphology State`);
1758
+ lines.push(`- **Active Stage**: ${report.morphology.activeStage?.type || "null"} (${report.morphology.activeStage?.label || "\u2013"})`);
1759
+ lines.push(`- **History Depth**: ${report.morphology.stageHistory.length}`);
1760
+ const layoutSync = report.morphology.activeStage?.type === report.layout.activeStage?.type ? "\u2705 Sincronizado" : "\u26A0\uFE0F DESINCRONIZADO";
1761
+ lines.push(`- **Layout Sync**: ${layoutSync}
1762
+ `);
1763
+ const logsByLevel = { info: 0, warn: 0, error: 0, debug: 0 };
1764
+ report.logs.forEach((l) => {
1765
+ logsByLevel[l.level]++;
1766
+ });
1767
+ lines.push(`## Logs Summary (${report.logs.length})`);
1768
+ lines.push(`| Level | Count |
1769
+ |-------|-------|
1770
+ | info | ${logsByLevel.info} |
1771
+ | warn | ${logsByLevel.warn} |
1772
+ | error | ${logsByLevel.error} |
1773
+ | debug | ${logsByLevel.debug} |
1774
+ `);
1775
+ const netErrors = report.network.filter((n) => n.status >= 400 || n.error).length;
1776
+ lines.push(`## Network (${report.network.length} requests, ${netErrors} errors)`);
1777
+ if (report.network.length > 0) {
1778
+ lines.push(`| Time | Method | Status | URL | Duration |`);
1779
+ lines.push(`|------|--------|--------|-----|----------|`);
1780
+ report.network.slice(-20).forEach((n) => {
1781
+ const url = n.url.length > 50 ? n.url.slice(0, 47) + "..." : n.url;
1782
+ lines.push(`| ${n.timestamp} | ${n.method} | ${n.status || "ERR"} | ${url} | ${n.duration}ms |`);
1783
+ });
1784
+ }
1785
+ lines.push("");
1786
+ lines.push(`## Timeline Events (${report.timeline.length})`);
1787
+ report.timeline.slice(-30).forEach((e) => {
1788
+ lines.push(`- \`${e.timestamp}\` **${e.storeName}**.${e.actionName} ${e.level !== "info" ? `(${e.level})` : ""}`);
1789
+ });
1790
+ return lines.join("\n");
1791
+ }
1792
+ function downloadFile(content, filename, mimeType) {
1793
+ const blob = new Blob([content], { type: mimeType });
1794
+ const url = URL.createObjectURL(blob);
1795
+ const a = document.createElement("a");
1796
+ a.href = url;
1797
+ a.download = filename;
1798
+ a.click();
1799
+ URL.revokeObjectURL(url);
1800
+ }
1801
+ function ExportTab() {
1802
+ const [copied, setCopied] = useState8(false);
1803
+ const [lastAction, setLastAction] = useState8(null);
1804
+ const handleExportJSON = useCallback5(() => {
1805
+ const report = generateReport();
1806
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1807
+ downloadFile(JSON.stringify(report, null, 2), `debug-report-${ts}.json`, "application/json");
1808
+ setLastAction("\u{1F4E6} JSON exportado");
1809
+ setTimeout(() => setLastAction(null), 2e3);
1810
+ }, []);
1811
+ const handleExportMD = useCallback5(() => {
1812
+ const md = generateMarkdownReport();
1813
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1814
+ downloadFile(md, `debug-report-${ts}.md`, "text/markdown");
1815
+ setLastAction("\u{1F4DD} Markdown exportado");
1816
+ setTimeout(() => setLastAction(null), 2e3);
1817
+ }, []);
1818
+ const handleCopyClipboard = useCallback5(async () => {
1819
+ const md = generateMarkdownReport();
1820
+ await navigator.clipboard.writeText(md);
1821
+ setCopied(true);
1822
+ setLastAction("\u{1F4CB} Copiado al portapapeles");
1823
+ setTimeout(() => {
1824
+ setCopied(false);
1825
+ setLastAction(null);
1826
+ }, 2e3);
1827
+ }, []);
1828
+ const logCount = useDebugPanelStore((s) => s.logEntries.length);
1829
+ const timelineCount = useActionTimelineStore((s) => s.events.length);
1830
+ return /* @__PURE__ */ jsxs12("div", { className: "p-4 space-y-4 overflow-y-auto h-full custom-scrollbar", children: [
1831
+ /* @__PURE__ */ jsxs12("div", { className: "text-[10px] font-bold text-text-secondary uppercase tracking-widest flex items-center gap-1", children: [
1832
+ /* @__PURE__ */ jsx12(Download2, { size: 10 }),
1833
+ " Exportar Sesi\xF3n de Debug"
1834
+ ] }),
1835
+ /* @__PURE__ */ jsxs12("div", { className: "grid grid-cols-3 gap-3", children: [
1836
+ /* @__PURE__ */ jsxs12(
1837
+ "button",
1838
+ {
1839
+ onClick: handleExportJSON,
1840
+ className: "rounded-xl bg-blue-500/10 border border-blue-500/20 p-4 hover:bg-blue-500/15 transition-all group",
1841
+ children: [
1842
+ /* @__PURE__ */ jsx12(FileJson, { size: 24, className: "text-blue-400 mb-2 group-hover:scale-110 transition-transform" }),
1843
+ /* @__PURE__ */ jsx12("div", { className: "text-[11px] font-bold text-text-primary", children: "JSON Completo" }),
1844
+ /* @__PURE__ */ jsx12("div", { className: "text-[9px] text-text-muted mt-1", children: "Logs, timeline, network, morph state, profiles" })
1845
+ ]
1846
+ }
1847
+ ),
1848
+ /* @__PURE__ */ jsxs12(
1849
+ "button",
1850
+ {
1851
+ onClick: handleExportMD,
1852
+ className: "rounded-xl bg-violet-500/10 border border-violet-500/20 p-4 hover:bg-violet-500/15 transition-all group",
1853
+ children: [
1854
+ /* @__PURE__ */ jsx12(FileText, { size: 24, className: "text-violet-400 mb-2 group-hover:scale-110 transition-transform" }),
1855
+ /* @__PURE__ */ jsx12("div", { className: "text-[11px] font-bold text-text-primary", children: "Markdown Report" }),
1856
+ /* @__PURE__ */ jsx12("div", { className: "text-[9px] text-text-muted mt-1", children: "Resumen legible con tablas y m\xE9tricas" })
1857
+ ]
1858
+ }
1859
+ ),
1860
+ /* @__PURE__ */ jsxs12(
1861
+ "button",
1862
+ {
1863
+ onClick: handleCopyClipboard,
1864
+ className: "rounded-xl bg-emerald-500/10 border border-emerald-500/20 p-4 hover:bg-emerald-500/15 transition-all group",
1865
+ children: [
1866
+ copied ? /* @__PURE__ */ jsx12(Check2, { size: 24, className: "text-emerald-400 mb-2" }) : /* @__PURE__ */ jsx12(Copy2, { size: 24, className: "text-emerald-400 mb-2 group-hover:scale-110 transition-transform" }),
1867
+ /* @__PURE__ */ jsx12("div", { className: "text-[11px] font-bold text-text-primary", children: "Copiar al Clipboard" }),
1868
+ /* @__PURE__ */ jsx12("div", { className: "text-[9px] text-text-muted mt-1", children: "Pegar en chat, issue, o documento" })
1869
+ ]
1870
+ }
1871
+ )
1872
+ ] }),
1873
+ /* @__PURE__ */ jsxs12("div", { className: "rounded-xl bg-surface-secondary/50 border border-border-subtle p-3", children: [
1874
+ /* @__PURE__ */ jsx12("div", { className: "text-[9px] font-bold text-text-muted uppercase tracking-widest mb-2", children: "Datos a exportar" }),
1875
+ /* @__PURE__ */ jsxs12("div", { className: "grid grid-cols-4 gap-3 text-center", children: [
1876
+ /* @__PURE__ */ jsxs12("div", { children: [
1877
+ /* @__PURE__ */ jsx12("div", { className: "text-[14px] font-bold text-green-400", children: logCount }),
1878
+ /* @__PURE__ */ jsx12("div", { className: "text-[8px] text-text-muted", children: "Logs" })
1879
+ ] }),
1880
+ /* @__PURE__ */ jsxs12("div", { children: [
1881
+ /* @__PURE__ */ jsx12("div", { className: "text-[14px] font-bold text-amber-400", children: timelineCount }),
1882
+ /* @__PURE__ */ jsx12("div", { className: "text-[8px] text-text-muted", children: "Timeline" })
1883
+ ] }),
1884
+ /* @__PURE__ */ jsxs12("div", { children: [
1885
+ /* @__PURE__ */ jsx12("div", { className: "text-[14px] font-bold text-cyan-400", children: getNetworkEntries().length }),
1886
+ /* @__PURE__ */ jsx12("div", { className: "text-[8px] text-text-muted", children: "Network" })
1887
+ ] }),
1888
+ /* @__PURE__ */ jsxs12("div", { children: [
1889
+ /* @__PURE__ */ jsx12("div", { className: "text-[14px] font-bold text-violet-400", children: useDebugProfileStore.getState().profiles.length }),
1890
+ /* @__PURE__ */ jsx12("div", { className: "text-[8px] text-text-muted", children: "Profiles" })
1891
+ ] })
1892
+ ] })
1893
+ ] }),
1894
+ lastAction && /* @__PURE__ */ jsx12("div", { className: "text-[10px] text-emerald-400 font-mono animate-pulse text-center", children: lastAction })
1895
+ ] });
1896
+ }
1897
+
1898
+ // src/components/debug/CSSInspectorTab.tsx
1899
+ import { useState as useState9, useCallback as useCallback6, useEffect as useEffect5, useMemo as useMemo9 } from "react";
1900
+ import { Eye as Eye2, EyeOff, Search as Search2, Palette, Copy as Copy3, X as X2, Plus as Plus2, AlertTriangle as AlertTriangle4, Box, Layers as Layers2 } from "lucide-react";
1901
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1902
+ var OutlineOverlay = ({ target, color = "#3b82f6" }) => {
1903
+ const [rect, setRect] = useState9(null);
1904
+ useEffect5(() => {
1905
+ if (!target) {
1906
+ setRect(null);
1907
+ return;
1908
+ }
1909
+ const update = () => setRect(target.getBoundingClientRect());
1910
+ update();
1911
+ const obs = new ResizeObserver(update);
1912
+ obs.observe(target);
1913
+ window.addEventListener("scroll", update, true);
1914
+ return () => {
1915
+ obs.disconnect();
1916
+ window.removeEventListener("scroll", update, true);
1917
+ };
1918
+ }, [target]);
1919
+ if (!rect) return null;
1920
+ return /* @__PURE__ */ jsx13("div", { className: "fixed pointer-events-none z-99999", style: {
1921
+ left: rect.left - 2,
1922
+ top: rect.top - 2,
1923
+ width: rect.width + 4,
1924
+ height: rect.height + 4,
1925
+ border: `2px solid ${color}`,
1926
+ borderRadius: 4,
1927
+ background: `${color}11`,
1928
+ transition: "all 0.15s ease"
1929
+ }, children: /* @__PURE__ */ jsxs13("span", { className: "absolute -top-5 left-0 text-[9px] font-mono px-1.5 py-0.5 rounded", style: { background: color, color: "#fff" }, children: [
1930
+ target?.tagName.toLowerCase(),
1931
+ target?.id ? `#${target.id}` : "",
1932
+ target?.classList.length ? `.${Array.from(target.classList).slice(0, 2).join(".")}` : ""
1933
+ ] }) });
1934
+ };
1935
+ var KEY_PROPS = [
1936
+ "display",
1937
+ "position",
1938
+ "z-index",
1939
+ "opacity",
1940
+ "width",
1941
+ "height",
1942
+ "max-width",
1943
+ "max-height",
1944
+ "margin",
1945
+ "padding",
1946
+ "gap",
1947
+ "flex",
1948
+ "flex-direction",
1949
+ "align-items",
1950
+ "justify-content",
1951
+ "background-color",
1952
+ "color",
1953
+ "font-size",
1954
+ "font-weight",
1955
+ "border",
1956
+ "border-radius",
1957
+ "box-shadow",
1958
+ "backdrop-filter",
1959
+ "overflow",
1960
+ "transform",
1961
+ "pointer-events"
1962
+ ];
1963
+ function isHardcodedColor(value) {
1964
+ if (!value) return false;
1965
+ return /^#[0-9a-f]{3,8}$/i.test(value) || /^rgb/i.test(value);
1966
+ }
1967
+ function getActiveTokens(el) {
1968
+ const style = getComputedStyle(el);
1969
+ const root = getComputedStyle(document.documentElement);
1970
+ const tokens = [];
1971
+ const dsVars = [
1972
+ "surface-primary",
1973
+ "surface-secondary",
1974
+ "surface-tertiary",
1975
+ "surface-elevated",
1976
+ "surface-glass",
1977
+ "text-primary",
1978
+ "text-secondary",
1979
+ "text-muted",
1980
+ "accent-blue",
1981
+ "accent-purple",
1982
+ "accent-green",
1983
+ "accent-red",
1984
+ "accent-amber",
1985
+ "accent-cyan",
1986
+ "border-subtle",
1987
+ "border-default",
1988
+ "border-strong",
1989
+ "border-glow"
1990
+ ];
1991
+ const bgColor = style.backgroundColor;
1992
+ const textColor = style.color;
1993
+ const borderColor = style.borderColor;
1994
+ for (const v of dsVars) {
1995
+ const tokenVal = root.getPropertyValue(`--ds-${v}`).trim();
1996
+ if (!tokenVal) continue;
1997
+ if (bgColor === tokenVal || textColor === tokenVal || borderColor === tokenVal) {
1998
+ tokens.push({ token: `--ds-${v}`, value: tokenVal });
1999
+ }
2000
+ }
2001
+ return tokens;
2002
+ }
2003
+ var BoxModelViz = ({ el }) => {
2004
+ const style = getComputedStyle(el);
2005
+ const m = { t: style.marginTop, r: style.marginRight, b: style.marginBottom, l: style.marginLeft };
2006
+ const p = { t: style.paddingTop, r: style.paddingRight, b: style.paddingBottom, l: style.paddingLeft };
2007
+ const w = el.offsetWidth;
2008
+ const h = el.offsetHeight;
2009
+ return /* @__PURE__ */ jsx13("div", { className: "flex justify-center py-3", children: /* @__PURE__ */ jsx13("div", { className: "relative text-[8px] font-mono select-none", children: /* @__PURE__ */ jsxs13("div", { className: "border border-dashed border-accent-amber/40 bg-accent-amber/5 px-6 py-4 rounded", children: [
2010
+ /* @__PURE__ */ jsx13("span", { className: "absolute top-0.5 left-1 text-accent-amber/60", children: "margin" }),
2011
+ /* @__PURE__ */ jsx13("span", { className: "absolute top-1 left-1/2 -translate-x-1/2 text-accent-amber", children: m.t }),
2012
+ /* @__PURE__ */ jsx13("span", { className: "absolute bottom-1 left-1/2 -translate-x-1/2 text-accent-amber", children: m.b }),
2013
+ /* @__PURE__ */ jsx13("span", { className: "absolute left-1 top-1/2 -translate-y-1/2 text-accent-amber", children: m.l }),
2014
+ /* @__PURE__ */ jsx13("span", { className: "absolute right-1 top-1/2 -translate-y-1/2 text-accent-amber", children: m.r }),
2015
+ /* @__PURE__ */ jsxs13("div", { className: "border border-dashed border-accent-green/40 bg-accent-green/5 px-6 py-4 rounded relative", children: [
2016
+ /* @__PURE__ */ jsx13("span", { className: "absolute top-0.5 left-1 text-accent-green/60", children: "padding" }),
2017
+ /* @__PURE__ */ jsx13("span", { className: "absolute top-1 left-1/2 -translate-x-1/2 text-accent-green", children: p.t }),
2018
+ /* @__PURE__ */ jsx13("span", { className: "absolute bottom-1 left-1/2 -translate-x-1/2 text-accent-green", children: p.b }),
2019
+ /* @__PURE__ */ jsx13("span", { className: "absolute left-1 top-1/2 -translate-y-1/2 text-accent-green", children: p.l }),
2020
+ /* @__PURE__ */ jsx13("span", { className: "absolute right-1 top-1/2 -translate-y-1/2 text-accent-green", children: p.r }),
2021
+ /* @__PURE__ */ jsxs13("div", { className: "bg-accent-blue/10 border border-accent-blue/30 rounded px-4 py-2 text-center text-accent-blue", children: [
2022
+ w,
2023
+ " \xD7 ",
2024
+ h
2025
+ ] })
2026
+ ] })
2027
+ ] }) }) });
2028
+ };
2029
+ var CSSInspectorTab = () => {
2030
+ const [selected, setSelected] = useState9(null);
2031
+ const [hovered, setHovered] = useState9(null);
2032
+ const [pickMode, setPickMode] = useState9(false);
2033
+ const [subTab, setSubTab] = useState9("classes");
2034
+ const [filter, setFilter] = useState9("");
2035
+ const [showAll, setShowAll] = useState9(false);
2036
+ const [addClass, setAddClass] = useState9("");
2037
+ const [hardcodedEls, setHardcodedEls] = useState9([]);
2038
+ const setTheme = useTheme((s) => s.setTheme);
2039
+ const currentThemeId = useTheme((s) => s.currentThemeId);
2040
+ useEffect5(() => {
2041
+ if (!pickMode) return;
2042
+ const onClick = (e) => {
2043
+ e.preventDefault();
2044
+ e.stopPropagation();
2045
+ const t = e.target;
2046
+ if (t.closest("[data-debug-panel]")) return;
2047
+ setSelected(t);
2048
+ setPickMode(false);
2049
+ };
2050
+ const onMove = (e) => {
2051
+ const t = e.target;
2052
+ if (!t.closest("[data-debug-panel]")) setHovered(t);
2053
+ };
2054
+ document.addEventListener("click", onClick, true);
2055
+ document.addEventListener("mousemove", onMove, true);
2056
+ document.body.style.cursor = "crosshair";
2057
+ return () => {
2058
+ document.removeEventListener("click", onClick, true);
2059
+ document.removeEventListener("mousemove", onMove, true);
2060
+ document.body.style.cursor = "";
2061
+ };
2062
+ }, [pickMode]);
2063
+ const classes = useMemo9(() => {
2064
+ if (!selected) return [];
2065
+ return Array.from(selected.classList).filter((c) => !filter || c.includes(filter));
2066
+ }, [selected, filter]);
2067
+ const computedProps = useMemo9(() => {
2068
+ if (!selected) return [];
2069
+ const computed = getComputedStyle(selected);
2070
+ const props = showAll ? Array.from({ length: computed.length }, (_, i) => computed[i]) : KEY_PROPS;
2071
+ return props.map((p) => ({ prop: p, value: computed.getPropertyValue(p) })).filter((p) => p.value && p.value !== "none" && p.value !== "normal" && p.value !== "auto" && p.value !== "0px").filter((p) => !filter || p.prop.includes(filter) || p.value.includes(filter));
2072
+ }, [selected, filter, showAll]);
2073
+ const tokens = useMemo9(() => selected ? getActiveTokens(selected) : [], [selected]);
2074
+ const toggleClass = useCallback6((cls) => {
2075
+ if (!selected) return;
2076
+ selected.classList.toggle(cls);
2077
+ setSelected(selected);
2078
+ setFilter((f) => f);
2079
+ }, [selected]);
2080
+ const handleAddClass = useCallback6(() => {
2081
+ if (!selected || !addClass.trim()) return;
2082
+ selected.classList.add(...addClass.trim().split(/\s+/));
2083
+ setAddClass("");
2084
+ setFilter((f) => f);
2085
+ }, [selected, addClass]);
2086
+ const findHardcoded = useCallback6(() => {
2087
+ const root = document.getElementById("root");
2088
+ if (!root) return;
2089
+ const els = [];
2090
+ root.querySelectorAll("*").forEach((el) => {
2091
+ if (!(el instanceof HTMLElement)) return;
2092
+ const s = getComputedStyle(el);
2093
+ const bg = s.backgroundColor;
2094
+ const color = s.color;
2095
+ if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
2096
+ const hasBgToken = Array.from(el.classList).some((c) => c.startsWith("bg-surface-") || c.startsWith("bg-accent-"));
2097
+ if (!hasBgToken && isHardcodedColor(bg)) {
2098
+ els.push(el);
2099
+ }
2100
+ }
2101
+ });
2102
+ setHardcodedEls(els);
2103
+ }, []);
2104
+ const SUB_TABS = [
2105
+ { id: "classes", label: "Classes", icon: Layers2 },
2106
+ { id: "computed", label: "CSS", icon: Box },
2107
+ { id: "tokens", label: "Tokens", icon: Palette },
2108
+ { id: "box", label: "Box", icon: Box }
2109
+ ];
2110
+ return /* @__PURE__ */ jsxs13("div", { className: "flex flex-col h-full text-text-primary", "data-debug-panel": true, children: [
2111
+ /* @__PURE__ */ jsx13(OutlineOverlay, { target: pickMode ? hovered : selected, color: pickMode ? "#f59e0b" : "#3b82f6" }),
2112
+ hovered && !pickMode && hovered !== selected && /* @__PURE__ */ jsx13(OutlineOverlay, { target: hovered, color: "#22d3ee44" }),
2113
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 px-2 py-1.5 border-b border-border-subtle bg-surface-secondary/50 shrink-0", children: [
2114
+ /* @__PURE__ */ jsxs13(
2115
+ "button",
2116
+ {
2117
+ onClick: () => setPickMode(!pickMode),
2118
+ className: `flex items-center gap-1 px-2 py-1 rounded text-[10px] font-semibold transition-all ${pickMode ? "bg-accent-amber/20 text-accent-amber ring-1 ring-accent-amber/40" : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`,
2119
+ title: "Pick Element",
2120
+ children: [
2121
+ pickMode ? /* @__PURE__ */ jsx13(Eye2, { size: 11 }) : /* @__PURE__ */ jsx13(EyeOff, { size: 11 }),
2122
+ "Pick"
2123
+ ]
2124
+ }
2125
+ ),
2126
+ /* @__PURE__ */ jsx13("div", { className: "w-px h-4 bg-border-subtle mx-1" }),
2127
+ /* @__PURE__ */ jsx13(
2128
+ "select",
2129
+ {
2130
+ value: currentThemeId,
2131
+ onChange: (e) => setTheme(e.target.value),
2132
+ className: "bg-surface-tertiary text-text-primary text-[10px] font-mono rounded px-1.5 py-1 border border-border-subtle outline-none cursor-pointer",
2133
+ children: THEME_PRESETS.map((t) => /* @__PURE__ */ jsx13("option", { value: t.id, children: t.name }, t.id))
2134
+ }
2135
+ ),
2136
+ /* @__PURE__ */ jsx13("div", { className: "w-px h-4 bg-border-subtle mx-1" }),
2137
+ /* @__PURE__ */ jsxs13(
2138
+ "button",
2139
+ {
2140
+ onClick: findHardcoded,
2141
+ className: "flex items-center gap-1 px-2 py-1 rounded text-[10px] font-semibold text-text-muted hover:text-accent-red hover:bg-accent-red/10 transition-all",
2142
+ title: "Find elements with hardcoded colors",
2143
+ children: [
2144
+ /* @__PURE__ */ jsx13(AlertTriangle4, { size: 10 }),
2145
+ "Audit",
2146
+ hardcodedEls.length > 0 && /* @__PURE__ */ jsx13("span", { className: "text-[8px] bg-accent-red/20 text-accent-red px-1 rounded-full", children: hardcodedEls.length })
2147
+ ]
2148
+ }
2149
+ ),
2150
+ selected && /* @__PURE__ */ jsxs13("div", { className: "ml-auto text-[9px] font-mono text-text-muted truncate max-w-[180px]", children: [
2151
+ "<",
2152
+ selected.tagName.toLowerCase(),
2153
+ selected.id ? `#${selected.id}` : "",
2154
+ ">",
2155
+ /* @__PURE__ */ jsxs13("span", { className: "text-text-muted/50 ml-1", children: [
2156
+ selected.offsetWidth,
2157
+ "\xD7",
2158
+ selected.offsetHeight
2159
+ ] })
2160
+ ] })
2161
+ ] }),
2162
+ selected ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
2163
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-0.5 px-2 py-1 border-b border-border-subtle shrink-0", children: [
2164
+ SUB_TABS.map((t) => /* @__PURE__ */ jsx13(
2165
+ "button",
2166
+ {
2167
+ onClick: () => setSubTab(t.id),
2168
+ className: `px-2 py-0.5 rounded text-[10px] font-semibold transition-all ${subTab === t.id ? "bg-surface-glass text-text-primary" : "text-text-muted hover:text-text-primary"}`,
2169
+ children: t.label
2170
+ },
2171
+ t.id
2172
+ )),
2173
+ /* @__PURE__ */ jsxs13("div", { className: "ml-auto flex items-center gap-1 bg-surface-tertiary rounded px-1.5 py-0.5 border border-border-subtle", children: [
2174
+ /* @__PURE__ */ jsx13(Search2, { size: 9, className: "text-text-muted" }),
2175
+ /* @__PURE__ */ jsx13(
2176
+ "input",
2177
+ {
2178
+ value: filter,
2179
+ onChange: (e) => setFilter(e.target.value),
2180
+ placeholder: "Filter...",
2181
+ className: "bg-transparent text-text-primary text-[10px] font-mono outline-none w-20"
2182
+ }
2183
+ )
2184
+ ] })
2185
+ ] }),
2186
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 overflow-auto scrollbar-thin", children: [
2187
+ subTab === "classes" && /* @__PURE__ */ jsxs13("div", { className: "p-2", children: [
2188
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 mb-2", children: [
2189
+ /* @__PURE__ */ jsx13(
2190
+ "input",
2191
+ {
2192
+ value: addClass,
2193
+ onChange: (e) => setAddClass(e.target.value),
2194
+ onKeyDown: (e) => e.key === "Enter" && handleAddClass(),
2195
+ placeholder: "Add TW class...",
2196
+ className: "flex-1 bg-surface-tertiary text-text-primary text-[10px] font-mono px-2 py-1 rounded border border-border-subtle outline-none focus:border-accent-blue/50"
2197
+ }
2198
+ ),
2199
+ /* @__PURE__ */ jsx13("button", { onClick: handleAddClass, className: "p-1 rounded text-text-muted hover:text-accent-green hover:bg-accent-green/10", children: /* @__PURE__ */ jsx13(Plus2, { size: 11 }) })
2200
+ ] }),
2201
+ /* @__PURE__ */ jsxs13("div", { className: "flex flex-wrap gap-1", children: [
2202
+ classes.map((cls) => /* @__PURE__ */ jsxs13(
2203
+ "button",
2204
+ {
2205
+ onClick: () => toggleClass(cls),
2206
+ className: "group flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[9px] font-mono bg-surface-glass border border-border-subtle text-text-secondary hover:text-text-primary hover:border-accent-blue/40 transition-all",
2207
+ children: [
2208
+ cls,
2209
+ /* @__PURE__ */ jsx13(X2, { size: 8, className: "opacity-0 group-hover:opacity-100 text-accent-red" })
2210
+ ]
2211
+ },
2212
+ cls
2213
+ )),
2214
+ classes.length === 0 && /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-text-muted italic", children: "No classes match filter" })
2215
+ ] }),
2216
+ /* @__PURE__ */ jsxs13(
2217
+ "button",
2218
+ {
2219
+ onClick: () => selected && navigator.clipboard.writeText(Array.from(selected.classList).join(" ")),
2220
+ className: "mt-2 flex items-center gap-1 text-[9px] text-text-muted hover:text-accent-cyan transition-colors",
2221
+ children: [
2222
+ /* @__PURE__ */ jsx13(Copy3, { size: 9 }),
2223
+ " Copy all classes"
2224
+ ]
2225
+ }
2226
+ )
2227
+ ] }),
2228
+ subTab === "computed" && /* @__PURE__ */ jsxs13("div", { children: [
2229
+ /* @__PURE__ */ jsx13("div", { className: "px-2 py-1 flex justify-end", children: /* @__PURE__ */ jsx13(
2230
+ "button",
2231
+ {
2232
+ onClick: () => setShowAll(!showAll),
2233
+ className: `text-[9px] font-mono px-1.5 py-0.5 rounded ${showAll ? "bg-accent-purple/20 text-accent-purple" : "text-text-muted hover:text-text-primary"}`,
2234
+ children: showAll ? "ALL" : "KEY"
2235
+ }
2236
+ ) }),
2237
+ computedProps.map(({ prop, value }) => /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1 px-2 py-0.5 text-[10px] font-mono hover:bg-surface-glass group", children: [
2238
+ /* @__PURE__ */ jsxs13("span", { className: "text-accent-purple shrink-0 w-[110px] truncate", children: [
2239
+ prop,
2240
+ ":"
2241
+ ] }),
2242
+ /* @__PURE__ */ jsx13("span", { className: "flex-1 text-text-secondary truncate", children: value }),
2243
+ (prop.includes("color") || prop === "background-color") && value !== "transparent" && value !== "rgba(0, 0, 0, 0)" && /* @__PURE__ */ jsx13("span", { className: "w-3 h-3 rounded-sm border border-border-subtle shrink-0", style: { backgroundColor: value } }),
2244
+ /* @__PURE__ */ jsx13("button", { onClick: () => navigator.clipboard.writeText(`${prop}: ${value}`), className: "opacity-0 group-hover:opacity-100 text-text-muted hover:text-accent-cyan", children: /* @__PURE__ */ jsx13(Copy3, { size: 9 }) })
2245
+ ] }, prop))
2246
+ ] }),
2247
+ subTab === "tokens" && /* @__PURE__ */ jsxs13("div", { className: "p-2", children: [
2248
+ /* @__PURE__ */ jsx13("div", { className: "text-[9px] font-mono text-text-muted uppercase tracking-wider mb-2", children: "Active Design Tokens" }),
2249
+ tokens.length > 0 ? tokens.map(({ token, value }) => /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2 px-2 py-1 rounded hover:bg-surface-glass text-[10px] font-mono", children: [
2250
+ /* @__PURE__ */ jsx13("span", { className: "w-4 h-4 rounded border border-border-subtle shrink-0", style: { backgroundColor: value } }),
2251
+ /* @__PURE__ */ jsx13("span", { className: "text-accent-cyan", children: token }),
2252
+ /* @__PURE__ */ jsx13("span", { className: "text-text-muted ml-auto", children: value })
2253
+ ] }, token)) : /* @__PURE__ */ jsxs13("div", { className: "text-text-muted text-[10px] italic", children: [
2254
+ "No `--ds-*` tokens detected on this element.",
2255
+ /* @__PURE__ */ jsx13("br", {}),
2256
+ "This might use hardcoded colors."
2257
+ ] }),
2258
+ selected?.style.cssText && /* @__PURE__ */ jsxs13("div", { className: "mt-3", children: [
2259
+ /* @__PURE__ */ jsx13("div", { className: "text-[9px] font-mono text-text-muted uppercase tracking-wider mb-1", children: "Inline Styles" }),
2260
+ /* @__PURE__ */ jsx13("div", { className: "text-[10px] font-mono text-accent-amber bg-surface-glass rounded p-2 break-all", children: selected.style.cssText })
2261
+ ] })
2262
+ ] }),
2263
+ subTab === "box" && selected && /* @__PURE__ */ jsx13(BoxModelViz, { el: selected })
2264
+ ] })
2265
+ ] }) : /* @__PURE__ */ jsxs13("div", { className: "flex-1 flex flex-col items-center justify-center text-text-muted text-xs gap-2 py-8", children: [
2266
+ /* @__PURE__ */ jsx13(Eye2, { size: 24, className: "opacity-30" }),
2267
+ /* @__PURE__ */ jsxs13("span", { children: [
2268
+ "Click ",
2269
+ /* @__PURE__ */ jsx13("strong", { children: '"Pick"' }),
2270
+ " to select an element"
2271
+ ] }),
2272
+ /* @__PURE__ */ jsxs13("span", { className: "text-[9px]", children: [
2273
+ "or use ",
2274
+ /* @__PURE__ */ jsx13("strong", { children: '"Audit"' }),
2275
+ " to find hardcoded colors"
2276
+ ] })
2277
+ ] }),
2278
+ hardcodedEls.length > 0 && /* @__PURE__ */ jsxs13("div", { className: "shrink-0 border-t border-border-subtle px-2 py-1 bg-accent-red/5", children: [
2279
+ /* @__PURE__ */ jsxs13("div", { className: "text-[9px] font-mono text-accent-red mb-1", children: [
2280
+ "\u26A0 ",
2281
+ hardcodedEls.length,
2282
+ " elements with potential hardcoded colors"
2283
+ ] }),
2284
+ /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap gap-1 max-h-12 overflow-auto", children: hardcodedEls.slice(0, 20).map((el, i) => /* @__PURE__ */ jsxs13(
2285
+ "button",
2286
+ {
2287
+ onClick: () => {
2288
+ setSelected(el);
2289
+ setSubTab("computed");
2290
+ },
2291
+ className: "text-[8px] font-mono text-text-muted hover:text-accent-red bg-surface-glass rounded px-1 py-0.5",
2292
+ children: [
2293
+ el.tagName.toLowerCase(),
2294
+ el.className && typeof el.className === "string" ? `.${el.className.split(" ")[0]}` : ""
2295
+ ]
2296
+ },
2297
+ i
2298
+ )) })
2299
+ ] })
2300
+ ] });
2301
+ };
2302
+
2303
+ // src/components/playground/DebugPanel.tsx
2304
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2305
+ var TABS = [
2306
+ { id: "logs", label: "Logs", icon: Bug2, color: "text-green-400" },
2307
+ { id: "flow-health", label: "Health", icon: Activity, color: "text-cyan-400" },
2308
+ { id: "topology", label: "Topology", icon: Map3, color: "text-purple-400" },
2309
+ { id: "replay", label: "Replay", icon: PlayCircle, color: "text-amber-400" },
2310
+ { id: "stores", label: "Stores", icon: Database2, color: "text-emerald-400" },
2311
+ { id: "morph-stack", label: "Morph", icon: Layers3, color: "text-violet-400" },
2312
+ { id: "network", label: "Network", icon: Globe2, color: "text-cyan-400" },
2313
+ { id: "profiles", label: "Profiles", icon: UserCog, color: "text-rose-400" },
2314
+ { id: "timeline", label: "Timeline", icon: Clock3, color: "text-amber-400" },
2315
+ { id: "performance", label: "Perf", icon: Gauge2, color: "text-lime-400" },
2316
+ { id: "export", label: "Export", icon: Download3, color: "text-text-secondary" },
2317
+ { id: "css-inspector", label: "CSS", icon: Palette2, color: "text-indigo-400" }
2318
+ ];
2319
+ var TAB_COMPONENTS = {
2320
+ "logs": LogsTab,
2321
+ "flow-health": FlowHealthTab,
2322
+ "topology": TopologyTab,
2323
+ "replay": ReplayTab,
2324
+ "stores": StoresTab,
2325
+ "morph-stack": MorphStackTab,
2326
+ "network": NetworkTab,
2327
+ "profiles": ProfilesTab,
2328
+ "timeline": ActionTimelineTab,
2329
+ "performance": PerformanceTab,
2330
+ "export": ExportTab,
2331
+ "css-inspector": CSSInspectorTab
2332
+ };
2333
+ var DebugPanel = React13.memo(function DebugPanel2({ className }) {
2334
+ const isOpen = useDebugPanelStore((s) => s.isOpen);
2335
+ const activeTab = useDebugPanelStore((s) => s.activeTab);
2336
+ const setActiveTab = useDebugPanelStore((s) => s.setActiveTab);
2337
+ const togglePanel = useDebugPanelStore((s) => s.togglePanel);
2338
+ const errorCount = useDebugPanelStore((s) => s.errorCount);
2339
+ if (!isOpen) return null;
2340
+ const ActiveComponent = TAB_COMPONENTS[activeTab];
2341
+ return /* @__PURE__ */ jsx14(AnimatePresence2, { children: /* @__PURE__ */ jsxs14(
2342
+ motion2.div,
2343
+ {
2344
+ initial: { height: 0, opacity: 0 },
2345
+ animate: { height: "100%", opacity: 1 },
2346
+ exit: { height: 0, opacity: 0 },
2347
+ transition: { duration: 0.15, ease: "easeOut" },
2348
+ className: `flex flex-col bg-surface-primary border-t border-border-default overflow-hidden ${className || ""}`,
2349
+ children: [
2350
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center justify-between px-2 py-1 border-b border-border-subtle shrink-0 bg-surface-primary/80", children: [
2351
+ /* @__PURE__ */ jsx14("div", { className: "flex items-center gap-0.5 overflow-x-auto flex-1 min-w-0", style: { scrollbarWidth: "none" }, children: TABS.map((tab) => {
2352
+ const Icon = tab.icon;
2353
+ const isActive = activeTab === tab.id;
2354
+ return /* @__PURE__ */ jsxs14(
2355
+ "button",
2356
+ {
2357
+ onClick: () => setActiveTab(tab.id),
2358
+ className: `flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-semibold transition-all whitespace-nowrap shrink-0 ${isActive ? `bg-surface-glass text-text-primary shadow-xs` : "text-text-muted hover:text-text-primary hover:bg-surface-glass"}`,
2359
+ children: [
2360
+ /* @__PURE__ */ jsx14(Icon, { size: 11, className: isActive ? tab.color : "" }),
2361
+ tab.label,
2362
+ tab.id === "logs" && errorCount > 0 && /* @__PURE__ */ jsx14("span", { className: "ml-0.5 px-1 py-0.5 rounded-full text-[8px] font-bold bg-red-500/20 text-red-400", children: errorCount })
2363
+ ]
2364
+ },
2365
+ tab.id
2366
+ );
2367
+ }) }),
2368
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1 shrink-0 ml-1", children: [
2369
+ /* @__PURE__ */ jsx14("span", { className: "text-[9px] text-text-muted font-mono mr-1", children: "\u2303\u21E7D" }),
2370
+ /* @__PURE__ */ jsx14("button", { onClick: togglePanel, className: "p-1 rounded text-text-muted hover:text-text-primary hover:bg-surface-glass transition-colors", title: "Cerrar panel", children: /* @__PURE__ */ jsx14(X3, { size: 14 }) })
2371
+ ] })
2372
+ ] }),
2373
+ /* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx14(ActiveComponent, {}) })
2374
+ ]
2375
+ }
2376
+ ) });
2377
+ });
2378
+
2379
+ export {
2380
+ DebugPanel
2381
+ };