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,144 @@
1
+ /**
2
+ * Shared IndexedDB connection and schema for ZeroChat.
3
+ * Persistent application data lives in one database so modules never compete
4
+ * with different database versions or upgrade handlers.
5
+ */
6
+ (function (root, factory) {
7
+ if (typeof exports === 'object' && typeof module !== 'undefined') {
8
+ module.exports = factory();
9
+ } else {
10
+ root.ZeroChatDB = factory();
11
+ }
12
+ })(typeof self !== 'undefined' ? self : this, function () {
13
+ 'use strict';
14
+
15
+ const DB_NAME = 'ZeroChatDB';
16
+ const DB_VERSION = 4;
17
+ const STORES = Object.freeze({
18
+ conversations: 'conversations',
19
+ messages: 'messages',
20
+ attachments: 'attachments',
21
+ ragBranches: 'rag_branches',
22
+ ragDocuments: 'rag_documents',
23
+ ragImages: 'rag_images',
24
+ ragChunks: 'rag_chunks',
25
+ ragMeta: 'rag_meta'
26
+ });
27
+
28
+ let dbPromise = null;
29
+
30
+ function isAvailable() {
31
+ try {
32
+ return typeof indexedDB !== 'undefined' && indexedDB !== null;
33
+ } catch (_) {
34
+ return false;
35
+ }
36
+ }
37
+
38
+ function createIndex(store, name, keyPath, options) {
39
+ if (!store.indexNames.contains(name)) store.createIndex(name, keyPath, options);
40
+ }
41
+
42
+ function ensureStore(db, tx, name, options) {
43
+ return db.objectStoreNames.contains(name)
44
+ ? tx.objectStore(name)
45
+ : db.createObjectStore(name, options);
46
+ }
47
+
48
+ function upgradeSchema(db, transaction) {
49
+ let store = ensureStore(db, transaction, STORES.conversations, { keyPath: 'id' });
50
+ createIndex(store, 'by_updatedAt', 'updatedAt', { unique: false });
51
+ createIndex(store, 'by_createdAt', 'createdAt', { unique: false });
52
+
53
+ store = ensureStore(db, transaction, STORES.messages, { keyPath: 'id' });
54
+ createIndex(store, 'by_conversationId', 'conversationId', { unique: false });
55
+ createIndex(store, 'by_createdAt', 'createdAt', { unique: false });
56
+ createIndex(store, 'by_role', 'role', { unique: false });
57
+
58
+ store = ensureStore(db, transaction, STORES.attachments, { keyPath: 'id' });
59
+ createIndex(store, 'by_conversationId', 'conversationId', { unique: false });
60
+ createIndex(store, 'by_messageId', 'messageId', { unique: false });
61
+
62
+ store = ensureStore(db, transaction, STORES.ragBranches, { keyPath: 'id' });
63
+ createIndex(store, 'by_createdAt', 'createdAt', { unique: false });
64
+
65
+ store = ensureStore(db, transaction, STORES.ragDocuments, { keyPath: 'id' });
66
+ createIndex(store, 'by_branchId', 'branchId', { unique: false });
67
+ createIndex(store, 'by_createdAt', 'createdAt', { unique: false });
68
+
69
+ if (db.objectStoreNames.contains('rag_files')) {
70
+ db.deleteObjectStore('rag_files');
71
+ }
72
+
73
+ store = ensureStore(db, transaction, STORES.ragImages, { keyPath: 'documentId' });
74
+ createIndex(store, 'by_branchId', 'branchId', { unique: false });
75
+
76
+ store = ensureStore(db, transaction, STORES.ragChunks, { keyPath: 'id' });
77
+ createIndex(store, 'by_branchId', 'branchId', { unique: false });
78
+ createIndex(store, 'by_documentId', 'documentId', { unique: false });
79
+ createIndex(store, 'by_createdAt', 'createdAt', { unique: false });
80
+
81
+ if (!db.objectStoreNames.contains(STORES.ragMeta)) {
82
+ db.createObjectStore(STORES.ragMeta, { keyPath: 'key' });
83
+ }
84
+ }
85
+
86
+ function openDatabase() {
87
+ if (!isAvailable()) return Promise.resolve(null);
88
+ if (dbPromise) return dbPromise;
89
+
90
+ dbPromise = new Promise((resolve) => {
91
+ let request;
92
+ try {
93
+ request = indexedDB.open(DB_NAME, DB_VERSION);
94
+ } catch (error) {
95
+ console.warn('[ZeroChatDB] IndexedDB no está disponible:', error);
96
+ resolve(null);
97
+ return;
98
+ }
99
+ request.onupgradeneeded = (event) => upgradeSchema(event.target.result, event.target.transaction);
100
+ request.onsuccess = (event) => {
101
+ const db = event.target.result;
102
+ db.onversionchange = () => { db.close(); dbPromise = null; };
103
+ resolve(db);
104
+ };
105
+ request.onerror = () => {
106
+ console.warn('[ZeroChatDB] No se pudo abrir IndexedDB:', request.error);
107
+ dbPromise = null;
108
+ resolve(null);
109
+ };
110
+ request.onblocked = () => {
111
+ console.warn('[ZeroChatDB] La actualización está bloqueada por otra pestaña.');
112
+ dbPromise = null;
113
+ resolve(null);
114
+ };
115
+ });
116
+ return dbPromise;
117
+ }
118
+
119
+ async function closeDatabase() {
120
+ if (!dbPromise) return;
121
+ const db = await dbPromise;
122
+ if (db) db.close();
123
+ dbPromise = null;
124
+ }
125
+
126
+ async function deleteOriginDatabases() {
127
+ if (!isAvailable()) return;
128
+ await closeDatabase();
129
+ // Do not enumerate the origin: under file:// Chromium can group unrelated
130
+ // file URLs in the same storage bucket. ZeroChat owns this database; WebLLM
131
+ // model artifacts are removed separately from Cache Storage.
132
+ await new Promise((resolve, reject) => {
133
+ const request = indexedDB.deleteDatabase(DB_NAME);
134
+ const timer = setTimeout(() => reject(new Error('ZeroChat IndexedDB deletion timed out.')), 10000);
135
+ request.onsuccess = () => { clearTimeout(timer); resolve(); };
136
+ request.onerror = () => { clearTimeout(timer); reject(request.error || new Error('ZeroChat IndexedDB deletion failed.')); };
137
+ // A connection may receive its versionchange event just after this request.
138
+ // Keep waiting for success instead of treating that transient event as failure.
139
+ request.onblocked = () => {};
140
+ });
141
+ }
142
+
143
+ return { DB_NAME, DB_VERSION, STORES, isAvailable, openDatabase, closeDatabase, deleteOriginDatabases };
144
+ });
@@ -0,0 +1,330 @@
1
+ /** Renderer genérico: cada tool declara su propia vista con iconos vectoriales SVG. */
2
+ (function (root, factory) {
3
+ if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = factory();
4
+ else root.ChatToolCards = factory();
5
+ }(typeof self !== 'undefined' ? self : this, function () {
6
+ const safeEscapeHtml = value => String(value || '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
7
+ const getMarkdown = () => (typeof window !== 'undefined' && window.ChatMarkdown) || (typeof window !== 'undefined' && window.ChatUtils) || { escapeHtml: safeEscapeHtml };
8
+ const t = (key, params) => (typeof window !== 'undefined' && window.ChatI18n?.t) ? window.ChatI18n.t(key, params) : key;
9
+ const normalizeName = name => String(name || '').trim().toLowerCase().replace(/_/g, '');
10
+ const getView = name => (typeof window !== 'undefined' && window.ChatAgentCore?.registry?.getTool) ? window.ChatAgentCore.registry.getTool(name)?.view : null;
11
+
12
+ const SPINNER_SVG = '<svg class="ui-icon ui-icon-spin" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M21 12a9 9 0 1 1-6.219-8.56"></path></svg>';
13
+ const CHECK_SVG = '<svg class="ui-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg>';
14
+ const ERROR_SVG = '<svg class="ui-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>';
15
+ const CHEVRON_SVG = '<svg class="ui-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"></polyline></svg>';
16
+ const SHIELD_SVG = '<svg class="ui-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>';
17
+ const DEFAULT_TOOL_ICON = '<svg class="ui-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>';
18
+
19
+ function createCardWrapper(ui, extraClass = '') {
20
+ const doc = ui?.document || (typeof document !== 'undefined' ? document : null);
21
+ if (!doc) return null;
22
+ const cardDiv = doc.createElement('div');
23
+ cardDiv.className = extraClass ? `tool-card-wrapper ${extraClass}` : 'tool-card-wrapper';
24
+ return cardDiv;
25
+ }
26
+
27
+ const context = () => ({
28
+ document: typeof document === 'undefined' ? null : document,
29
+ markdown: getMarkdown(),
30
+ charts: typeof window !== 'undefined' ? window.ChatCharts : null,
31
+ icons: typeof window !== 'undefined' ? window.ChatIcons : null,
32
+ t,
33
+ createCardWrapper: (extraClass) => createCardWrapper(context(), extraClass),
34
+ SPINNER_SVG,
35
+ CHECK_SVG,
36
+ ERROR_SVG,
37
+ CHEVRON_SVG
38
+ });
39
+
40
+ const resolveToolDisplayMode = name => {
41
+ const view = getView(name);
42
+ if (view?.displayMode) return view.displayMode;
43
+ if (typeof window !== 'undefined' && window.ChatAgentCore?.registry?.getTool) {
44
+ const tool = window.ChatAgentCore.registry.getTool(name);
45
+ return tool?.displayMode || tool?.view?.displayMode || null;
46
+ }
47
+ return null;
48
+ };
49
+
50
+ function collapseCard(card) {
51
+ if (!card) return;
52
+ const cardEl = card.querySelector?.('.tool-execution-card, .web-request-card, .web-search-card, .chat-chart-card')
53
+ || (card.matches?.('.tool-execution-card, .web-request-card, .web-search-card, .chat-chart-card') ? card : null);
54
+ if (cardEl) {
55
+ cardEl.classList.add('collapsed');
56
+ const btn = cardEl.querySelector('.btn-tool-collapse');
57
+ if (btn) btn.title = t('tool_btn_expand') || 'Expandir herramienta';
58
+ }
59
+ }
60
+
61
+ function fallback(name, args, isCollapsed = false) {
62
+ if (typeof document === 'undefined') return null;
63
+ const card = document.createElement('div'); card.className = 'tool-card-wrapper';
64
+ const hasArgs = args && typeof args === 'object' && Object.keys(args).length > 0;
65
+ const tool = (typeof window !== 'undefined' && window.ChatAgentCore?.registry?.getTool) ? window.ChatAgentCore.registry.getTool(name) : null;
66
+ const icon = (typeof window !== 'undefined' && window.ChatIcons?.has(name))
67
+ ? window.ChatIcons.get(name, { size: 14 })
68
+ : (tool?.metadata?.iconSvg || DEFAULT_TOOL_ICON);
69
+ const badgeClass = isCollapsed ? 'tool-card-badge status-success' : 'tool-card-badge status-loading';
70
+ const badgeContent = isCollapsed
71
+ ? `${CHECK_SVG} <span>${t('tool_status_success') || 'Completado'}</span>`
72
+ : `${SPINNER_SVG} <span>${t('tool_badge_executing') || 'Ejecutando...'}</span>`;
73
+ const collapseBtnTitle = isCollapsed ? (t('tool_btn_expand') || 'Expandir herramienta') : (t('tool_btn_collapse') || 'Minimizar');
74
+ const collapseBtn = hasArgs
75
+ ? `<button type="button" class="btn-tool-collapse" title="${collapseBtnTitle}">${CHEVRON_SVG}</button>`
76
+ : '';
77
+ const bodyHtml = hasArgs
78
+ ? `<div class="tool-card-collapsible-body"><div class="tool-card-result"><pre class="tool-card-code"><code>${getMarkdown().escapeHtml(JSON.stringify(args, null, 2))}</code></pre></div></div>`
79
+ : '';
80
+ const cardClass = isCollapsed ? 'tool-execution-card collapsed' : 'tool-execution-card';
81
+ card.innerHTML = `<div class="${cardClass}"><div class="tool-card-header"><div class="tool-card-title"><span>${icon}</span><span>${getMarkdown().escapeHtml(name)}</span></div><div class="tool-card-header-actions"><span class="${badgeClass}">${badgeContent}</span>${collapseBtn}</div></div>${bodyHtml}</div>`;
82
+ return card;
83
+ }
84
+
85
+ function createLiveToolCard(name, args = {}) { if (typeof document === 'undefined') return null; const view = getView(name); return view?.createLiveCard ? view.createLiveCard(args, context()) : fallback(name, args, false); }
86
+ function updateLiveToolCard(card, name, args = {}, result = {}, elapsedMs = 0, options = {}) {
87
+ const view = getView(name);
88
+ if (view?.updateLiveCard) {
89
+ view.updateLiveCard(card, args, result, elapsedMs, context());
90
+ } else {
91
+ const badge = card?.querySelector('.tool-card-badge');
92
+ if (badge) {
93
+ const isSuccess = result?.success !== false && !result?.error;
94
+ badge.className = `tool-card-badge ${isSuccess ? 'status-success' : 'status-error'}`;
95
+ badge.innerHTML = isSuccess
96
+ ? `${CHECK_SVG} <span>${t('tool_status_success') || 'Completado'} (${elapsedMs}ms)</span>`
97
+ : `${ERROR_SVG} <span>${t('tool_status_error', { ms: elapsedMs }) || `Error (${elapsedMs}ms)`}</span>`;
98
+ }
99
+ }
100
+ const displayMode = options?.displayMode
101
+ || result?.displayMode
102
+ || result?.outcome?.meta?.displayMode
103
+ || view?.displayMode
104
+ || resolveToolDisplayMode(name)
105
+ || 'collapsed';
106
+
107
+ if (displayMode === 'collapsed') {
108
+ collapseCard(card);
109
+ }
110
+ }
111
+ function renderHistoricalToolCard(call, message) {
112
+ if (!call?.function || typeof document === 'undefined') return null;
113
+ let args = {};
114
+ try {
115
+ args = typeof call.function.arguments === 'object' ? call.function.arguments : JSON.parse(call.function.arguments || '{}');
116
+ } catch (e) {
117
+ args = { input: call.function.arguments || '' };
118
+ }
119
+ const toolName = call.function.name;
120
+ const view = getView(toolName);
121
+ const displayMode = view?.displayMode || resolveToolDisplayMode(toolName) || 'collapsed';
122
+ const card = view?.renderHistoricalCard
123
+ ? view.renderHistoricalCard(args, message, context())
124
+ : fallback(toolName, args, displayMode === 'collapsed');
125
+ if (displayMode === 'collapsed') {
126
+ collapseCard(card);
127
+ }
128
+ return card;
129
+ }
130
+
131
+ /**
132
+ * Muestra la petición interactiva de autorización en la tarjeta de la herramienta y espera la decisión del usuario.
133
+ *
134
+ * @param {HTMLElement} card - Elemento DOM de la tarjeta en vivo.
135
+ * @param {object} toolCall - Objeto de llamada de herramienta.
136
+ * @param {object} [options={}] - Opciones adicionales (serverName, args, signal).
137
+ * @returns {Promise<'allow_once'|'allow_always'|'deny'>}
138
+ */
139
+ function promptToolAuthorization(card, toolCall, options = {}) {
140
+ if (!card || typeof document === 'undefined') {
141
+ return Promise.resolve('deny');
142
+ }
143
+
144
+ const tFn = (key, params) => t(key, params);
145
+ const esc = getMarkdown().escapeHtml;
146
+ const toolName = toolCall?.function?.name || options.toolName || 'tool';
147
+ const serverName = options.serverName || '';
148
+ const signal = options.signal;
149
+
150
+ // Asegurar que la tarjeta esté expandida para que el usuario visualice la petición
151
+ const cardEl = card.querySelector?.('.tool-execution-card, .mcp-card, .tool-card-wrapper') || card;
152
+ if (cardEl && cardEl.classList) {
153
+ cardEl.classList.remove('collapsed');
154
+ }
155
+
156
+ // Actualizar badge a pendiente de autorización
157
+ const badge = card.querySelector?.('.tool-card-badge');
158
+ if (badge) {
159
+ badge.className = 'tool-card-badge status-pending-auth';
160
+ badge.innerHTML = `${SHIELD_SVG} <span>${tFn('tool_auth_badge') || 'Requiere Autorización'}</span>`;
161
+ }
162
+
163
+ // Crear o insertar el bloque de autorización dentro del cuerpo de la tarjeta
164
+ const bodyEl = card.querySelector?.('.tool-card-collapsible-body') || cardEl;
165
+ let authPromptEl = card.querySelector?.('.tool-card-auth-prompt');
166
+ if (!authPromptEl) {
167
+ authPromptEl = document.createElement('div');
168
+ authPromptEl.className = 'tool-card-auth-prompt';
169
+ if (bodyEl) {
170
+ bodyEl.prepend(authPromptEl);
171
+ } else {
172
+ card.appendChild(authPromptEl);
173
+ }
174
+ }
175
+
176
+ const parsedArgs = options.args || {};
177
+ const cmdArg = parsedArgs.command || parsedArgs.cmd || parsedArgs.script;
178
+ const pathArg = parsedArgs.path || parsedArgs.filepath || parsedArgs.file;
179
+
180
+ let contextualButtonsHtml = '';
181
+ let baseCmd = '';
182
+ if (typeof cmdArg === 'string' && cmdArg.trim()) {
183
+ baseCmd = cmdArg.trim().split(/\s+/)[0];
184
+ if (baseCmd) {
185
+ contextualButtonsHtml = `
186
+ <button type="button" class="btn-auth-action btn-auth-allow-cmd" title="${esc(tFn('tool_auth_allow_cmd_title', { cmd: baseCmd }))}">${SHIELD_SVG} <span>${esc(tFn('tool_auth_allow_cmd_btn', { cmd: baseCmd + ' *' }))}</span></button>
187
+ `;
188
+ }
189
+ } else if (typeof pathArg === 'string' && pathArg.trim()) {
190
+ contextualButtonsHtml = `
191
+ <button type="button" class="btn-auth-action btn-auth-allow-path" title="${esc(tFn('tool_auth_allow_path_title'))}">${SHIELD_SVG} <span>${esc(tFn('tool_auth_allow_path_btn'))}</span></button>
192
+ `;
193
+ }
194
+
195
+ const serverTag = serverName ? `<span class="mcp-card-server-tag">${esc(serverName)}</span>` : '';
196
+ authPromptEl.innerHTML = `
197
+ <div class="tool-auth-header">
198
+ <div class="tool-auth-title-row">
199
+ <span class="tool-auth-shield-icon">${SHIELD_SVG}</span>
200
+ <strong class="tool-auth-title">${tFn('tool_auth_title') || 'Autorización de Ejecución'}</strong>
201
+ ${serverTag}
202
+ </div>
203
+ <p class="tool-auth-desc">${tFn('tool_auth_desc') || 'Esta herramienta MCP requiere tu confirmación antes de interactuar con el sistema:'}</p>
204
+ </div>
205
+ <div class="tool-auth-actions">
206
+ <button type="button" class="btn-auth-action btn-auth-allow-once" title="${esc(tFn('tool_auth_allow_once') || 'Permitir una vez')}">${CHECK_SVG} <span>${tFn('tool_auth_allow_once') || 'Permitir una vez'}</span></button>
207
+ ${contextualButtonsHtml}
208
+ <button type="button" class="btn-auth-action btn-auth-allow-always" title="${esc(tFn('tool_auth_allow_always') || 'Permitir siempre este tool')}">${SHIELD_SVG} <span>${tFn('tool_auth_allow_always') || 'Permitir todo'}</span></button>
209
+ <button type="button" class="btn-auth-action btn-auth-deny" title="${esc(tFn('tool_auth_deny') || 'Denegar')}">${ERROR_SVG} <span>${tFn('tool_auth_deny') || 'Denegar'}</span></button>
210
+ </div>
211
+ `;
212
+
213
+ return new Promise((resolve) => {
214
+ let resolved = false;
215
+
216
+ const cleanup = () => {
217
+ if (authPromptEl && authPromptEl.parentNode) {
218
+ authPromptEl.remove();
219
+ }
220
+ if (signal && abortHandler) {
221
+ signal.removeEventListener('abort', abortHandler);
222
+ }
223
+ };
224
+
225
+ const handleDecision = (decision) => {
226
+ if (resolved) return;
227
+ resolved = true;
228
+ cleanup();
229
+
230
+ const decisionType = (typeof decision === 'object' && decision !== null) ? decision.decision : decision;
231
+
232
+ if (decisionType === 'deny') {
233
+ if (badge) {
234
+ badge.className = 'tool-card-badge status-error';
235
+ badge.innerHTML = `${ERROR_SVG} <span>${tFn('tool_auth_denied_badge') || 'Denegado'}</span>`;
236
+ }
237
+ const resEl = card.querySelector?.('.tool-card-result');
238
+ if (resEl) {
239
+ resEl.innerHTML = `<div class="tool-auth-denied-notice">${esc(tFn('tool_auth_denied_msg') || 'Ejecución denegada por el usuario.')}</div>`;
240
+ }
241
+ } else {
242
+ // 'allow_once' o 'allow_always': restaurar badge a ejecutando
243
+ if (badge) {
244
+ badge.className = 'tool-card-badge status-loading';
245
+ badge.innerHTML = `${SPINNER_SVG} <span>${tFn('tool_badge_executing') || 'Ejecutando...'}</span>`;
246
+ }
247
+ }
248
+
249
+ resolve(decision);
250
+ };
251
+
252
+ const btnAllowOnce = authPromptEl.querySelector('.btn-auth-allow-once');
253
+ const btnAllowCmd = authPromptEl.querySelector('.btn-auth-allow-cmd');
254
+ const btnAllowPath = authPromptEl.querySelector('.btn-auth-allow-path');
255
+ const btnAllowAlways = authPromptEl.querySelector('.btn-auth-allow-always');
256
+ const btnDeny = authPromptEl.querySelector('.btn-auth-deny');
257
+
258
+ btnAllowOnce?.addEventListener('click', (e) => {
259
+ e.stopPropagation();
260
+ handleDecision('allow_once');
261
+ });
262
+
263
+ btnAllowCmd?.addEventListener('click', (e) => {
264
+ e.stopPropagation();
265
+ const baseNameOnly = baseCmd.includes('/') ? baseCmd.split('/').pop() : baseCmd;
266
+ const prefixes = Array.from(new Set([baseCmd + ' ', baseCmd, baseNameOnly + ' ', baseNameOnly]));
267
+ handleDecision({
268
+ decision: 'allow_always',
269
+ constraints: {
270
+ command: {
271
+ allowedPrefixes: prefixes,
272
+ allowChaining: false,
273
+ allowPipes: true
274
+ }
275
+ }
276
+ });
277
+ });
278
+
279
+ btnAllowPath?.addEventListener('click', (e) => {
280
+ e.stopPropagation();
281
+ handleDecision({
282
+ decision: 'allow_always',
283
+ constraints: {
284
+ path: {
285
+ allowedDirectories: ['./'],
286
+ preventTraversal: true
287
+ }
288
+ }
289
+ });
290
+ });
291
+
292
+ btnAllowAlways?.addEventListener('click', (e) => {
293
+ e.stopPropagation();
294
+ handleDecision('allow_always');
295
+ });
296
+
297
+ btnDeny?.addEventListener('click', (e) => {
298
+ e.stopPropagation();
299
+ handleDecision('deny');
300
+ });
301
+
302
+ let abortHandler = null;
303
+ if (signal) {
304
+ abortHandler = () => handleDecision('deny');
305
+ if (signal.aborted) {
306
+ handleDecision('deny');
307
+ } else {
308
+ signal.addEventListener('abort', abortHandler, { once: true });
309
+ }
310
+ }
311
+ });
312
+ }
313
+
314
+ return {
315
+ normalizeName,
316
+ resolveToolView: getView,
317
+ resolveToolDisplayMode,
318
+ createCardWrapper,
319
+ createLiveToolCard,
320
+ updateLiveToolCard,
321
+ renderHistoricalToolCard,
322
+ promptToolAuthorization,
323
+ collapseCard,
324
+ SPINNER_SVG,
325
+ CHECK_SVG,
326
+ ERROR_SVG,
327
+ CHEVRON_SVG,
328
+ SHIELD_SVG
329
+ };
330
+ }));