zerochat 7.3.0__py3-none-any.whl

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 (130) hide show
  1. zerochat-7.3.0.dist-info/METADATA +70 -0
  2. zerochat-7.3.0.dist-info/RECORD +130 -0
  3. zerochat-7.3.0.dist-info/WHEEL +5 -0
  4. zerochat-7.3.0.dist-info/entry_points.txt +2 -0
  5. zerochat-7.3.0.dist-info/licenses/LICENSE +34 -0
  6. zerochat-7.3.0.dist-info/top_level.txt +2 -0
  7. zerochat.py +2004 -0
  8. zerochat_runtime/__init__.py +1 -0
  9. zerochat_runtime/assets/css/base.css +199 -0
  10. zerochat_runtime/assets/css/components/composer.css +1258 -0
  11. zerochat_runtime/assets/css/components/debug.css +777 -0
  12. zerochat_runtime/assets/css/components/header.css +97 -0
  13. zerochat_runtime/assets/css/components/icons.css +39 -0
  14. zerochat_runtime/assets/css/components/markdown.css +685 -0
  15. zerochat_runtime/assets/css/components/messages.css +473 -0
  16. zerochat_runtime/assets/css/components/modals.css +1319 -0
  17. zerochat_runtime/assets/css/components/sidebar.css +622 -0
  18. zerochat_runtime/assets/css/components/tools.css +1223 -0
  19. zerochat_runtime/assets/css/layout.css +171 -0
  20. zerochat_runtime/assets/css/print.css +120 -0
  21. zerochat_runtime/assets/css/styles.css +18 -0
  22. zerochat_runtime/assets/css/theme-overrides.css +555 -0
  23. zerochat_runtime/assets/css/tokens.css +165 -0
  24. zerochat_runtime/assets/help/architecture.html +247 -0
  25. zerochat_runtime/assets/help/composer.html +134 -0
  26. zerochat_runtime/assets/help/conversations.html +105 -0
  27. zerochat_runtime/assets/help/debug.html +108 -0
  28. zerochat_runtime/assets/help/en/architecture.html +247 -0
  29. zerochat_runtime/assets/help/en/composer.html +134 -0
  30. zerochat_runtime/assets/help/en/conversations.html +104 -0
  31. zerochat_runtime/assets/help/en/debug.html +105 -0
  32. zerochat_runtime/assets/help/en/gemini-free.html +39 -0
  33. zerochat_runtime/assets/help/en/index.html +191 -0
  34. zerochat_runtime/assets/help/en/learning.html +71 -0
  35. zerochat_runtime/assets/help/en/mcp.html +143 -0
  36. zerochat_runtime/assets/help/en/openrouter-free.html +39 -0
  37. zerochat_runtime/assets/help/en/profiles.html +173 -0
  38. zerochat_runtime/assets/help/en/rag.html +130 -0
  39. zerochat_runtime/assets/help/en/reasoning-telemetry.html +108 -0
  40. zerochat_runtime/assets/help/en/tools-agent.html +133 -0
  41. zerochat_runtime/assets/help/en/webllm.html +355 -0
  42. zerochat_runtime/assets/help/gemini-free.html +39 -0
  43. zerochat_runtime/assets/help/help.css +604 -0
  44. zerochat_runtime/assets/help/help.js +51 -0
  45. zerochat_runtime/assets/help/index.html +194 -0
  46. zerochat_runtime/assets/help/learning.html +71 -0
  47. zerochat_runtime/assets/help/mcp.html +143 -0
  48. zerochat_runtime/assets/help/openrouter-free.html +39 -0
  49. zerochat_runtime/assets/help/profiles.html +174 -0
  50. zerochat_runtime/assets/help/rag.html +130 -0
  51. zerochat_runtime/assets/help/reasoning-telemetry.html +111 -0
  52. zerochat_runtime/assets/help/tools-agent.html +133 -0
  53. zerochat_runtime/assets/help/webllm.html +359 -0
  54. zerochat_runtime/assets/js/agent-core.js +1553 -0
  55. zerochat_runtime/assets/js/api.js +844 -0
  56. zerochat_runtime/assets/js/app.js +2558 -0
  57. zerochat_runtime/assets/js/attachments.js +220 -0
  58. zerochat_runtime/assets/js/charts.js +338 -0
  59. zerochat_runtime/assets/js/chat-engine.js +566 -0
  60. zerochat_runtime/assets/js/config-store.js +207 -0
  61. zerochat_runtime/assets/js/context-manager.js +584 -0
  62. zerochat_runtime/assets/js/conversation-service.js +484 -0
  63. zerochat_runtime/assets/js/cookies.js +688 -0
  64. zerochat_runtime/assets/js/data-reset-service.js +136 -0
  65. zerochat_runtime/assets/js/debug.js +508 -0
  66. zerochat_runtime/assets/js/defaults.js +16 -0
  67. zerochat_runtime/assets/js/export.js +179 -0
  68. zerochat_runtime/assets/js/file-parser.js +2088 -0
  69. zerochat_runtime/assets/js/generation-controller.js +417 -0
  70. zerochat_runtime/assets/js/i18n.js +1483 -0
  71. zerochat_runtime/assets/js/icons.js +156 -0
  72. zerochat_runtime/assets/js/ingestionEngine.js +436 -0
  73. zerochat_runtime/assets/js/markdown.js +588 -0
  74. zerochat_runtime/assets/js/mcp.js +1271 -0
  75. zerochat_runtime/assets/js/message-turns.js +62 -0
  76. zerochat_runtime/assets/js/profile-backup.js +118 -0
  77. zerochat_runtime/assets/js/profile-export-bundle.js +481 -0
  78. zerochat_runtime/assets/js/profile-repository.js +213 -0
  79. zerochat_runtime/assets/js/providers-webllm.js +486 -0
  80. zerochat_runtime/assets/js/providers.js +1560 -0
  81. zerochat_runtime/assets/js/rag-index.js +295 -0
  82. zerochat_runtime/assets/js/rag-service.js +530 -0
  83. zerochat_runtime/assets/js/rag-ui.js +997 -0
  84. zerochat_runtime/assets/js/ragStorage.js +676 -0
  85. zerochat_runtime/assets/js/sandbox.js +449 -0
  86. zerochat_runtime/assets/js/state.js +704 -0
  87. zerochat_runtime/assets/js/storage-db.js +144 -0
  88. zerochat_runtime/assets/js/tool-cards.js +330 -0
  89. zerochat_runtime/assets/js/tool-security.js +653 -0
  90. zerochat_runtime/assets/js/tools/README.md +50 -0
  91. zerochat_runtime/assets/js/tools/builtin/agent-checkpoint.tool.js +212 -0
  92. zerochat_runtime/assets/js/tools/builtin/download-pdf.tool.js +111 -0
  93. zerochat_runtime/assets/js/tools/builtin/execute-javascript.tool.js +219 -0
  94. zerochat_runtime/assets/js/tools/builtin/fetch-web-page.tool.js +112 -0
  95. zerochat_runtime/assets/js/tools/builtin/list-documents.tool.js +117 -0
  96. zerochat_runtime/assets/js/tools/builtin/read-knowledge-chunk.tool.js +129 -0
  97. zerochat_runtime/assets/js/tools/builtin/read-knowledge-image.tool.js +95 -0
  98. zerochat_runtime/assets/js/tools/builtin/render-chart.tool.js +90 -0
  99. zerochat_runtime/assets/js/tools/builtin/search-knowledge-base.tool.js +124 -0
  100. zerochat_runtime/assets/js/tools/builtin/search-web.tool.js +125 -0
  101. zerochat_runtime/assets/js/tools/tool-manifest.js +53 -0
  102. zerochat_runtime/assets/js/tools/tool-runtime.js +77 -0
  103. zerochat_runtime/assets/js/ui-composer.js +319 -0
  104. zerochat_runtime/assets/js/ui-conversation.js +655 -0
  105. zerochat_runtime/assets/js/ui-dialogs.js +132 -0
  106. zerochat_runtime/assets/js/ui-generation-status.js +119 -0
  107. zerochat_runtime/assets/js/ui-inspector.js +804 -0
  108. zerochat_runtime/assets/js/ui-mcp.js +604 -0
  109. zerochat_runtime/assets/js/ui-profiles.js +824 -0
  110. zerochat_runtime/assets/js/ui-reasoning.js +146 -0
  111. zerochat_runtime/assets/js/ui-settings.js +825 -0
  112. zerochat_runtime/assets/js/ui-shell.js +215 -0
  113. zerochat_runtime/assets/js/ui-sidebar.js +429 -0
  114. zerochat_runtime/assets/js/ui-telemetry.js +404 -0
  115. zerochat_runtime/assets/js/ui-transfer.js +262 -0
  116. zerochat_runtime/assets/js/utils.js +216 -0
  117. zerochat_runtime/assets/js/vendor/orama.browser.js +11 -0
  118. zerochat_runtime/assets/js/web-browser.js +569 -0
  119. zerochat_runtime/assets/js/web-search.js +519 -0
  120. zerochat_runtime/assets/manifest.webmanifest +20 -0
  121. zerochat_runtime/assets/services/dummy_mcp/dummy_mcp_server.py +47 -0
  122. zerochat_runtime/assets/services/dummy_mcp/service.json +22 -0
  123. zerochat_runtime/assets/services/lsp/installer.json +9 -0
  124. zerochat_runtime/assets/services/lsp/service.json +22 -0
  125. zerochat_runtime/assets/services/memory/installer.json +9 -0
  126. zerochat_runtime/assets/services/memory/service.json +24 -0
  127. zerochat_runtime/assets/services/playwright/installer.json +10 -0
  128. zerochat_runtime/assets/services/playwright/service.json +39 -0
  129. zerochat_runtime/assets/sw.js +164 -0
  130. zerochat_runtime/assets/zerochat.html +671 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Módulo UI Shell para ZeroChat:
3
+ * Gestión de altura de viewport adaptativo, listeners de orientación y redimensionamiento,
4
+ * diálogo de información de ejecución / alcance de almacenamiento y fallback de light-dismiss.
5
+ */
6
+ (function (root, factory) {
7
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
8
+ module.exports = factory();
9
+ } else {
10
+ root.ChatUIShell = factory();
11
+ }
12
+ }(typeof self !== 'undefined' ? self : this, function () {
13
+ 'use strict';
14
+
15
+ function resolveI18n() {
16
+ if (typeof window !== 'undefined' && window.ChatI18n) return window.ChatI18n;
17
+ if (typeof require !== 'undefined') {
18
+ try { return require('./i18n.js'); } catch (_) {}
19
+ }
20
+ return null;
21
+ }
22
+
23
+ function t(key, params) {
24
+ const I18n = resolveI18n();
25
+ return I18n?.t?.(key, params) || key;
26
+ }
27
+
28
+ let activeCleanupFns = [];
29
+ let cachedElements = null;
30
+
31
+ function isHttpExecution(win) {
32
+ const w = win || (typeof window !== 'undefined' ? window : null);
33
+ return Boolean(w && ['http:', 'https:'].includes(w.location?.protocol));
34
+ }
35
+
36
+ function updateViewportHeight(doc, win) {
37
+ const d = doc || (typeof document !== 'undefined' ? document : null);
38
+ const w = win || (typeof window !== 'undefined' ? window : null);
39
+ if (!d || !w) return;
40
+ let vh = w.innerHeight;
41
+ if (w.visualViewport) {
42
+ vh = w.visualViewport.height;
43
+ }
44
+ if (d.documentElement?.style?.setProperty) {
45
+ d.documentElement.style.setProperty('--app-height', `${vh}px`);
46
+ }
47
+ }
48
+
49
+ function updateExecutionInfo(elements) {
50
+ const els = elements || cachedElements || {};
51
+ const httpExecution = isHttpExecution();
52
+ if (els.executionStorageScope) {
53
+ els.executionStorageScope.textContent = t(httpExecution ? 'execution_info_http' : 'execution_info_file');
54
+ }
55
+ }
56
+
57
+ function openExecutionInfo(elements) {
58
+ const els = elements || cachedElements || {};
59
+ if (!els.executionInfoDialog) return;
60
+ updateExecutionInfo(els);
61
+ if (!els.executionInfoDialog.open && els.executionInfoDialog.showModal) {
62
+ els.executionInfoDialog.showModal();
63
+ }
64
+ }
65
+
66
+ function closeExecutionInfo(elements) {
67
+ const els = elements || cachedElements || {};
68
+ if (els.executionInfoDialog?.open && els.executionInfoDialog.close) {
69
+ els.executionInfoDialog.close();
70
+ }
71
+ }
72
+
73
+ function setupViewportListeners(elements, callbacks = {}) {
74
+ const w = typeof window !== 'undefined' ? window : null;
75
+ const d = typeof document !== 'undefined' ? document : null;
76
+ if (!w || !d) return () => {};
77
+
78
+ const cleanups = [];
79
+ const triggerChange = () => {
80
+ updateViewportHeight(d, w);
81
+ if (typeof callbacks.onViewportChange === 'function') {
82
+ callbacks.onViewportChange();
83
+ }
84
+ };
85
+
86
+ updateViewportHeight(d, w);
87
+
88
+ if (w.visualViewport) {
89
+ const onVvResize = () => triggerChange();
90
+ const onVvScroll = () => triggerChange();
91
+ w.visualViewport.addEventListener('resize', onVvResize);
92
+ w.visualViewport.addEventListener('scroll', onVvScroll);
93
+ cleanups.push(() => {
94
+ w.visualViewport.removeEventListener('resize', onVvResize);
95
+ w.visualViewport.removeEventListener('scroll', onVvScroll);
96
+ });
97
+ }
98
+
99
+ const onWinResize = () => triggerChange();
100
+ w.addEventListener('resize', onWinResize);
101
+ cleanups.push(() => w.removeEventListener('resize', onWinResize));
102
+
103
+ const onOrientationChange = () => {
104
+ const t1 = setTimeout(() => triggerChange(), 100);
105
+ const t2 = setTimeout(() => triggerChange(), 300);
106
+ cleanups.push(() => { clearTimeout(t1); clearTimeout(t2); });
107
+ };
108
+ w.addEventListener('orientationchange', onOrientationChange);
109
+ cleanups.push(() => w.removeEventListener('orientationchange', onOrientationChange));
110
+
111
+ const userInput = elements?.userInput;
112
+ if (userInput && userInput.addEventListener) {
113
+ let focusTimeout = null;
114
+ const onFocus = () => {
115
+ focusTimeout = setTimeout(() => {
116
+ triggerChange();
117
+ if (userInput.scrollIntoView) {
118
+ userInput.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
119
+ }
120
+ }, 150);
121
+ };
122
+ userInput.addEventListener('focus', onFocus);
123
+ cleanups.push(() => {
124
+ userInput.removeEventListener('focus', onFocus);
125
+ if (focusTimeout) clearTimeout(focusTimeout);
126
+ });
127
+ }
128
+
129
+ return () => {
130
+ cleanups.forEach(fn => { try { fn(); } catch (_) {} });
131
+ };
132
+ }
133
+
134
+ function setupLightDismissDialogs(doc, callbacks = {}) {
135
+ const d = doc || (typeof document !== 'undefined' ? document : null);
136
+ if (!d || typeof HTMLDialogElement === 'undefined') return () => {};
137
+ if ('closedBy' in HTMLDialogElement.prototype) return () => {};
138
+
139
+ const cleanups = [];
140
+ const dialogs = d.querySelectorAll ? d.querySelectorAll('dialog[closedby="any"]:not(#notice-dialog)') : [];
141
+ dialogs.forEach(dialog => {
142
+ const handler = (e) => {
143
+ if (e.target === dialog) {
144
+ if (dialog.id === 'profiles-dialog') {
145
+ if (typeof callbacks.onDismissProfiles === 'function') {
146
+ callbacks.onDismissProfiles();
147
+ return;
148
+ }
149
+ }
150
+ if (typeof dialog.close === 'function') {
151
+ dialog.close();
152
+ }
153
+ }
154
+ };
155
+ dialog.addEventListener('click', handler);
156
+ cleanups.push(() => dialog.removeEventListener('click', handler));
157
+ });
158
+
159
+ return () => {
160
+ cleanups.forEach(fn => { try { fn(); } catch (_) {} });
161
+ };
162
+ }
163
+
164
+ function mount({ elements, onViewportChange, onDismissProfiles } = {}) {
165
+ dispose();
166
+ cachedElements = elements || {};
167
+
168
+ const cleanupViewport = setupViewportListeners(cachedElements, { onViewportChange });
169
+ activeCleanupFns.push(cleanupViewport);
170
+
171
+ const cleanupLightDismiss = setupLightDismissDialogs(document, { onDismissProfiles });
172
+ activeCleanupFns.push(cleanupLightDismiss);
173
+
174
+ if (cachedElements.btnOpenExecutionInfo) {
175
+ const onOpen = () => openExecutionInfo(cachedElements);
176
+ cachedElements.btnOpenExecutionInfo.addEventListener('click', onOpen);
177
+ activeCleanupFns.push(() => cachedElements.btnOpenExecutionInfo.removeEventListener('click', onOpen));
178
+ }
179
+ if (cachedElements.btnCloseExecutionInfo) {
180
+ const onClose = () => closeExecutionInfo(cachedElements);
181
+ cachedElements.btnCloseExecutionInfo.addEventListener('click', onClose);
182
+ activeCleanupFns.push(() => cachedElements.btnCloseExecutionInfo.removeEventListener('click', onClose));
183
+ }
184
+ if (cachedElements.btnCloseExecutionInfoFooter) {
185
+ const onCloseFooter = () => closeExecutionInfo(cachedElements);
186
+ cachedElements.btnCloseExecutionInfoFooter.addEventListener('click', onCloseFooter);
187
+ activeCleanupFns.push(() => cachedElements.btnCloseExecutionInfoFooter.removeEventListener('click', onCloseFooter));
188
+ }
189
+
190
+ return {
191
+ openExecutionInfo: () => openExecutionInfo(cachedElements),
192
+ closeExecutionInfo: () => closeExecutionInfo(cachedElements),
193
+ updateExecutionInfo: () => updateExecutionInfo(cachedElements),
194
+ updateViewportHeight: () => updateViewportHeight(document, window)
195
+ };
196
+ }
197
+
198
+ function dispose() {
199
+ activeCleanupFns.forEach(fn => { try { fn(); } catch (_) {} });
200
+ activeCleanupFns = [];
201
+ cachedElements = null;
202
+ }
203
+
204
+ return {
205
+ isHttpExecution,
206
+ updateViewportHeight,
207
+ updateExecutionInfo,
208
+ openExecutionInfo,
209
+ closeExecutionInfo,
210
+ setupViewportListeners,
211
+ setupLightDismissDialogs,
212
+ mount,
213
+ dispose
214
+ };
215
+ }));
@@ -0,0 +1,429 @@
1
+ /**
2
+ * Módulo de Interfaz de Usuario para Barra Lateral y Gestión de Sesiones de Chat.
3
+ * ZeroChat - js/ui-sidebar.js
4
+ */
5
+ (function (root, factory) {
6
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
7
+ module.exports = factory();
8
+ } else {
9
+ root.ChatUISidebar = factory();
10
+ }
11
+ })(typeof self !== 'undefined' ? self : this, function () {
12
+ 'use strict';
13
+
14
+ function resolveDep(globalName, relPath) {
15
+ if (typeof window !== 'undefined' && window[globalName]) return window[globalName];
16
+ if (typeof require !== 'undefined') { try { return require(relPath); } catch (e) { return null; } }
17
+ return null;
18
+ }
19
+
20
+ const getI18n = () => resolveDep('ChatI18n', './i18n.js');
21
+ const getMarkdown = () => resolveDep('ChatMarkdown', './markdown.js');
22
+ const getIcons = () => resolveDep('ChatIcons', './icons.js');
23
+
24
+ function t(key, params) {
25
+ const I18n = getI18n();
26
+ if (I18n && typeof I18n.t === 'function') return I18n.t(key, params);
27
+ return key;
28
+ }
29
+
30
+ function escapeHtml(str) {
31
+ const Markdown = getMarkdown();
32
+ if (Markdown && typeof Markdown.escapeHtml === 'function') {
33
+ return Markdown.escapeHtml(str);
34
+ }
35
+ return String(str || '').replace(/[&<>"']/g, (m) => {
36
+ switch (m) {
37
+ case '&': return '&amp;';
38
+ case '<': return '&lt;';
39
+ case '>': return '&gt;';
40
+ case '"': return '&quot;';
41
+ case "'": return '&#39;';
42
+ default: return m;
43
+ }
44
+ });
45
+ }
46
+
47
+ function isMobile() {
48
+ return typeof window !== 'undefined' && window.innerWidth <= 768;
49
+ }
50
+
51
+ function openSidebar(elements) {
52
+ if (!elements || !elements.chatSidebar) return;
53
+ if (elements.chatSidebar.classList) {
54
+ elements.chatSidebar.classList.remove('sidebar-hidden');
55
+ elements.chatSidebar.classList.add('sidebar-visible');
56
+ }
57
+ if (elements.chatSidebar.style) {
58
+ elements.chatSidebar.style.display = 'flex';
59
+ }
60
+ if (elements.btnToggleSidebar && elements.btnToggleSidebar.style) {
61
+ elements.btnToggleSidebar.style.display = 'none';
62
+ }
63
+ if (isMobile()) {
64
+ const chatContainer = (typeof document !== 'undefined') ? (
65
+ document.getElementById('chat-container') ||
66
+ document.querySelector('main') ||
67
+ document.querySelector('.chat-container')
68
+ ) : null;
69
+ if (chatContainer && chatContainer.setAttribute) chatContainer.setAttribute('inert', '');
70
+ const backdrop = elements?.sidebarBackdrop || ((typeof document !== 'undefined') ? document.getElementById('sidebar-backdrop') : null);
71
+ if (backdrop && backdrop.classList) backdrop.classList.add('visible');
72
+ if (typeof requestAnimationFrame === 'function' && elements.chatSidebar.querySelector) {
73
+ requestAnimationFrame(() => {
74
+ const firstFocusable = elements.chatSidebar.querySelector(
75
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
76
+ );
77
+ if (firstFocusable && typeof firstFocusable.focus === 'function') firstFocusable.focus();
78
+ });
79
+ }
80
+ }
81
+ }
82
+
83
+ function closeSidebar(elements) {
84
+ if (!elements || !elements.chatSidebar) return;
85
+ if (elements.chatSidebar.classList) {
86
+ elements.chatSidebar.classList.add('sidebar-hidden');
87
+ elements.chatSidebar.classList.remove('sidebar-visible');
88
+ }
89
+ if (elements.chatSidebar.style) {
90
+ elements.chatSidebar.style.display = 'none';
91
+ }
92
+ if (elements.btnToggleSidebar && elements.btnToggleSidebar.style) {
93
+ elements.btnToggleSidebar.style.display = 'inline-flex';
94
+ }
95
+ const chatContainer = (typeof document !== 'undefined') ? (
96
+ document.getElementById('chat-container') ||
97
+ document.querySelector('main') ||
98
+ document.querySelector('.chat-container')
99
+ ) : null;
100
+ if (chatContainer && chatContainer.removeAttribute) chatContainer.removeAttribute('inert');
101
+ const backdrop = elements?.sidebarBackdrop || ((typeof document !== 'undefined') ? document.getElementById('sidebar-backdrop') : null);
102
+ if (backdrop && backdrop.classList) backdrop.classList.remove('visible');
103
+ }
104
+
105
+ function toggleSidebar(elements) {
106
+ if (!elements || !elements.chatSidebar) return;
107
+ const isHidden = elements.chatSidebar.classList
108
+ ? elements.chatSidebar.classList.contains('sidebar-hidden')
109
+ : (elements.chatSidebar.style && (elements.chatSidebar.style.display === 'none' || !elements.chatSidebar.style.display));
110
+ if (isHidden) {
111
+ openSidebar(elements);
112
+ } else {
113
+ closeSidebar(elements);
114
+ }
115
+ }
116
+ function getSidebarMode(elements) {
117
+ const settingsView = elements?.sidebarViewSettings || (typeof document !== 'undefined' ? document.getElementById('sidebar-view-settings') : null);
118
+ if (settingsView && !settingsView.hidden && settingsView.style?.display !== 'none') {
119
+ return 'settings';
120
+ }
121
+ return 'chat';
122
+ }
123
+
124
+ function setSidebarMode(elements, mode = 'chat') {
125
+ if (!elements) return;
126
+ const chatView = elements.sidebarViewChat || (typeof document !== 'undefined' ? document.getElementById('sidebar-view-chat') : null);
127
+ const settingsView = elements.sidebarViewSettings || (typeof document !== 'undefined' ? document.getElementById('sidebar-view-settings') : null);
128
+
129
+ if (mode === 'settings') {
130
+ if (chatView) {
131
+ chatView.hidden = true;
132
+ if (chatView.style) chatView.style.display = 'none';
133
+ }
134
+ if (settingsView) {
135
+ settingsView.hidden = false;
136
+ if (settingsView.style) settingsView.style.display = 'flex';
137
+ }
138
+ if (elements.chatSidebar?.classList) {
139
+ elements.chatSidebar.classList.add('mode-settings');
140
+ }
141
+ } else {
142
+ if (settingsView) {
143
+ settingsView.hidden = true;
144
+ if (settingsView.style) settingsView.style.display = 'none';
145
+ }
146
+ if (chatView) {
147
+ chatView.hidden = false;
148
+ if (chatView.style) chatView.style.display = 'flex';
149
+ }
150
+ if (elements.chatSidebar?.classList) {
151
+ elements.chatSidebar.classList.remove('mode-settings');
152
+ }
153
+ setActiveSettingsSection(elements, '');
154
+ }
155
+ }
156
+
157
+ function setActiveSettingsSection(elements, sectionId = '') {
158
+ const items = elements?.sidebarSettingsItems || (typeof document !== 'undefined' ? document.querySelectorAll('#sidebar-settings-nav .sidebar-settings-item') : []);
159
+ items.forEach(item => {
160
+ const match = (item.dataset?.section || item.getAttribute?.('data-section')) === sectionId;
161
+ if (item.classList) {
162
+ if (match) item.classList.add('active');
163
+ else item.classList.remove('active');
164
+ }
165
+ });
166
+ }
167
+
168
+
169
+ function filterSessions(sessions, filterText = '') {
170
+ if (!Array.isArray(sessions)) return [];
171
+ const filter = String(filterText || '').toLowerCase().trim();
172
+ if (!filter) return sessions;
173
+ return sessions.filter(s => {
174
+ if (s.title && s.title.toLowerCase().includes(filter)) return true;
175
+ return false;
176
+ });
177
+ }
178
+
179
+ function getChronologicalCategory(date) {
180
+ const now = new Date();
181
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
182
+ const yesterday = today - 86400000;
183
+ const last7Days = today - (7 * 86400000);
184
+ const last30Days = today - (30 * 86400000);
185
+
186
+ const d = new Date(date).getTime();
187
+ if (d >= today) return 'today';
188
+ if (d >= yesterday) return 'yesterday';
189
+ if (d >= last7Days) return 'last7days';
190
+ if (d >= last30Days) return 'last30days';
191
+ return 'older';
192
+ }
193
+
194
+ function getCategoryLabel(category) {
195
+ switch (category) {
196
+ case 'today': return t('sidebar_group_today', 'Hoy');
197
+ case 'yesterday': return t('sidebar_group_yesterday', 'Ayer');
198
+ case 'last7days': return t('sidebar_group_last7days', 'Últimos 7 días');
199
+ case 'last30days': return t('sidebar_group_last30days', 'Últimos 30 días');
200
+ case 'older': return t('sidebar_group_older', 'Anteriores');
201
+ default: return '';
202
+ }
203
+ }
204
+
205
+ function renderSidebarChats(elements, savedSessions, currentSessionId, callbacks = {}, options = {}) {
206
+ if (!elements || !elements.sidebarChatsList) return;
207
+ elements.sidebarChatsList.innerHTML = '';
208
+
209
+ const filterText = elements.sidebarSearchInput ? elements.sidebarSearchInput.value : '';
210
+ const matching = filterSessions(savedSessions, filterText);
211
+
212
+ const doc = elements.sidebarChatsList.ownerDocument || (typeof document !== 'undefined' ? document : null);
213
+ if (!doc) return;
214
+
215
+ if (matching.length === 0) {
216
+ const emptyDiv = doc.createElement('div');
217
+ emptyDiv.className = 'sidebar-no-chats';
218
+ emptyDiv.style.cssText = 'padding: 1rem; text-align: center; color: var(--text-muted); font-size: 0.8rem;';
219
+ emptyDiv.textContent = t('sidebar_no_chats');
220
+ elements.sidebarChatsList.appendChild(emptyDiv);
221
+ return;
222
+ }
223
+
224
+ const Icons = getIcons();
225
+ const exportSvg = Icons && typeof Icons.get === 'function' ? Icons.get('download', { size: 13 }) : '<svg class="ui-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>';
226
+ const editSvg = Icons && typeof Icons.get === 'function' ? Icons.get('edit', { size: 13 }) : '<svg class="ui-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>';
227
+ const trashSvg = Icons && typeof Icons.get === 'function' ? Icons.get('trash', { size: 13 }) : '<svg class="ui-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>';
228
+
229
+ let currentCategory = null;
230
+ matching.forEach(s => {
231
+ const d = new Date(s.updatedAt || s.createdAt || Date.now());
232
+
233
+ if (options && options.groupByDate && !filterText) {
234
+ const cat = getChronologicalCategory(d);
235
+ if (cat !== currentCategory) {
236
+ currentCategory = cat;
237
+ const groupHeader = doc.createElement('div');
238
+ groupHeader.className = 'sidebar-group-header';
239
+ groupHeader.textContent = getCategoryLabel(cat);
240
+ elements.sidebarChatsList.appendChild(groupHeader);
241
+ }
242
+ }
243
+
244
+ const item = doc.createElement('div');
245
+ item.className = 'sidebar-chat-item' + (s.id === currentSessionId ? ' active' : '');
246
+ item.setAttribute('data-session-id', s.id);
247
+
248
+ const timeStr = d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
249
+ const rawTitle = s.title || t('chat_untitled') || 'Nueva conversación';
250
+ const safeTitle = escapeHtml(rawTitle);
251
+
252
+ item.innerHTML = `
253
+ <div class="sidebar-chat-info">
254
+ <span class="sidebar-chat-title" title="${safeTitle}">${safeTitle}</span>
255
+ <span class="sidebar-chat-time">${timeStr}</span>
256
+ </div>
257
+ <div class="sidebar-chat-actions">
258
+ <button type="button" class="btn-chat-action btn-export" title="${escapeHtml(t('sidebar_export_chat_title') || t('btn_export_chat_title') || 'Exportar chat')}">${exportSvg}</button>
259
+ <button type="button" class="btn-chat-action btn-rename" title="${escapeHtml(t('sidebar_rename_chat_title') || 'Renombrar chat')}">${editSvg}</button>
260
+ <button type="button" class="btn-chat-action btn-delete" title="${escapeHtml(t('sidebar_delete_chat_title') || 'Eliminar chat')}">${trashSvg}</button>
261
+ </div>
262
+ `;
263
+
264
+ item.addEventListener('click', (e) => {
265
+ if (e.target && e.target.closest && e.target.closest('.sidebar-chat-actions')) return;
266
+ if (typeof callbacks.onSwitchSession === 'function') {
267
+ callbacks.onSwitchSession(s.id);
268
+ }
269
+ });
270
+
271
+ const btnExport = item.querySelector('.btn-export');
272
+ if (btnExport) {
273
+ btnExport.addEventListener('click', (e) => {
274
+ if (e && e.stopPropagation) e.stopPropagation();
275
+ if (typeof callbacks.onExportSession === 'function') {
276
+ callbacks.onExportSession(s.id, e);
277
+ }
278
+ });
279
+ }
280
+
281
+ const btnRename = item.querySelector('.btn-rename');
282
+ if (btnRename) {
283
+ btnRename.addEventListener('click', (e) => {
284
+ if (e && e.stopPropagation) e.stopPropagation();
285
+ if (typeof callbacks.onRenameSession === 'function') {
286
+ callbacks.onRenameSession(s.id, e);
287
+ }
288
+ });
289
+ }
290
+
291
+ const btnDelete = item.querySelector('.btn-delete');
292
+ if (btnDelete) {
293
+ btnDelete.addEventListener('click', (e) => {
294
+ if (e && e.stopPropagation) e.stopPropagation();
295
+ if (typeof callbacks.onDeleteSession === 'function') {
296
+ callbacks.onDeleteSession(s.id, e);
297
+ }
298
+ });
299
+ }
300
+
301
+ elements.sidebarChatsList.appendChild(item);
302
+ });
303
+ }
304
+
305
+ let activeCleanupFns = [];
306
+ let cachedElements = null;
307
+
308
+ function mount(elements, callbacks = {}) {
309
+ dispose();
310
+ cachedElements = elements || {};
311
+ const els = cachedElements;
312
+
313
+ if (els.btnToggleSidebar) {
314
+ const onToggle = () => toggleSidebar(els);
315
+ els.btnToggleSidebar.addEventListener('click', onToggle);
316
+ activeCleanupFns.push(() => els.btnToggleSidebar.removeEventListener('click', onToggle));
317
+ }
318
+
319
+ if (els.btnCloseSidebar) {
320
+ const onClose = () => closeSidebar(els);
321
+ els.btnCloseSidebar.addEventListener('click', onClose);
322
+ activeCleanupFns.push(() => els.btnCloseSidebar.removeEventListener('click', onClose));
323
+ }
324
+
325
+ if (els.sidebarBackdrop) {
326
+ const onBackdrop = () => closeSidebar(els);
327
+ els.sidebarBackdrop.addEventListener('click', onBackdrop);
328
+ activeCleanupFns.push(() => els.sidebarBackdrop.removeEventListener('click', onBackdrop));
329
+ }
330
+
331
+ if (els.btnSidebarNewChat) {
332
+ const onNew = () => {
333
+ if (typeof callbacks.onNewSession === 'function') callbacks.onNewSession();
334
+ };
335
+ els.btnSidebarNewChat.addEventListener('click', onNew);
336
+ activeCleanupFns.push(() => els.btnSidebarNewChat.removeEventListener('click', onNew));
337
+ }
338
+
339
+ if (els.sidebarSearchInput) {
340
+ const onSearch = () => {
341
+ if (typeof callbacks.onSearchInput === 'function') {
342
+ callbacks.onSearchInput(els.sidebarSearchInput.value);
343
+ }
344
+ };
345
+ els.sidebarSearchInput.addEventListener('input', onSearch);
346
+ activeCleanupFns.push(() => els.sidebarSearchInput.removeEventListener('input', onSearch));
347
+ }
348
+
349
+ if (els.btnDeleteAllChats) {
350
+ const onDeleteAll = () => {
351
+ if (typeof callbacks.onDeleteAllSessions === 'function') callbacks.onDeleteAllSessions();
352
+ };
353
+ els.btnDeleteAllChats.addEventListener('click', onDeleteAll);
354
+ activeCleanupFns.push(() => els.btnDeleteAllChats.removeEventListener('click', onDeleteAll));
355
+ }
356
+
357
+ if (els.btnImportChatFile && els.importJsonInput) {
358
+ const onImportClick = () => els.importJsonInput.click();
359
+ els.btnImportChatFile.addEventListener('click', onImportClick);
360
+ activeCleanupFns.push(() => els.btnImportChatFile.removeEventListener('click', onImportClick));
361
+
362
+ const onImportChange = (e) => {
363
+ if (typeof callbacks.onImportFileSelected === 'function') {
364
+ callbacks.onImportFileSelected(e);
365
+ }
366
+ };
367
+ els.importJsonInput.addEventListener('change', onImportChange);
368
+ activeCleanupFns.push(() => els.importJsonInput.removeEventListener('change', onImportChange));
369
+ }
370
+ if (els.btnOpenSettings) {
371
+ const onOpenSettings = () => {
372
+ setSidebarMode(els, 'settings');
373
+ if (typeof callbacks.onOpenSettingsMode === 'function') callbacks.onOpenSettingsMode();
374
+ };
375
+ els.btnOpenSettings.addEventListener('click', onOpenSettings);
376
+ activeCleanupFns.push(() => els.btnOpenSettings.removeEventListener('click', onOpenSettings));
377
+ }
378
+
379
+ if (els.btnSidebarBackToChats) {
380
+ const onBackToChats = () => {
381
+ setSidebarMode(els, 'chat');
382
+ if (typeof callbacks.onBackToChats === 'function') callbacks.onBackToChats();
383
+ };
384
+ els.btnSidebarBackToChats.addEventListener('click', onBackToChats);
385
+ activeCleanupFns.push(() => els.btnSidebarBackToChats.removeEventListener('click', onBackToChats));
386
+ }
387
+
388
+ if (els.btnCloseSidebarSettings) {
389
+ const onCloseSettings = () => closeSidebar(els);
390
+ els.btnCloseSidebarSettings.addEventListener('click', onCloseSettings);
391
+ activeCleanupFns.push(() => els.btnCloseSidebarSettings.removeEventListener('click', onCloseSettings));
392
+ }
393
+
394
+ if (els.sidebarSettingsItems) {
395
+ els.sidebarSettingsItems.forEach(item => {
396
+ const sectionId = item.dataset?.section || item.getAttribute('data-section');
397
+ if (!sectionId) return;
398
+ const onSelect = () => {
399
+ if (typeof callbacks.onSelectSettingsSection === 'function') {
400
+ callbacks.onSelectSettingsSection(sectionId);
401
+ }
402
+ };
403
+ item.addEventListener('click', onSelect);
404
+ activeCleanupFns.push(() => item.removeEventListener('click', onSelect));
405
+ });
406
+ }
407
+ }
408
+
409
+ function dispose() {
410
+ activeCleanupFns.forEach(fn => { try { fn(); } catch (_) {} });
411
+ activeCleanupFns = [];
412
+ cachedElements = null;
413
+ }
414
+
415
+ return {
416
+ isMobile,
417
+ getSidebarMode,
418
+ setSidebarMode,
419
+ setActiveSettingsSection,
420
+ toggleSidebar,
421
+ openSidebar,
422
+ closeSidebar,
423
+ filterSessions,
424
+ getChronologicalCategory,
425
+ renderSidebarChats,
426
+ mount,
427
+ dispose
428
+ };
429
+ });