@danieltmn/tamnora 0.24.2 → 0.25.0

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 (49) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/harness/packages/server/public/app.js +831 -834
  3. package/harness/packages/server/public/appearance.js +4 -0
  4. package/harness/packages/server/public/boot.js +49 -0
  5. package/harness/packages/server/public/chrome.js +853 -852
  6. package/harness/packages/server/public/commands.js +448 -405
  7. package/harness/packages/server/public/core.js +229 -216
  8. package/harness/packages/server/public/favicon.ico +0 -0
  9. package/harness/packages/server/public/icons/icon-128x128.png +0 -0
  10. package/harness/packages/server/public/icons/icon-144x144.png +0 -0
  11. package/harness/packages/server/public/icons/icon-152x152.png +0 -0
  12. package/harness/packages/server/public/icons/icon-192x192.png +0 -0
  13. package/harness/packages/server/public/icons/icon-384x384.png +0 -0
  14. package/harness/packages/server/public/icons/icon-512x512.png +0 -0
  15. package/harness/packages/server/public/icons/icon-72x72.png +0 -0
  16. package/harness/packages/server/public/icons/icon-96x96.png +0 -0
  17. package/harness/packages/server/public/icons/logo.png +0 -0
  18. package/harness/packages/server/public/icons/logo_dark.png +0 -0
  19. package/harness/packages/server/public/icons/logo_light.png +0 -0
  20. package/harness/packages/server/public/icons/tamnora.ico +0 -0
  21. package/harness/packages/server/public/index.html +72 -101
  22. package/harness/packages/server/public/landing/boot.js +16 -0
  23. package/harness/packages/server/public/landing/index.html +123 -59
  24. package/harness/packages/server/public/landing/landing.js +11 -9
  25. package/harness/packages/server/public/logo.png +0 -0
  26. package/harness/packages/server/public/markdown.js +1 -1
  27. package/harness/packages/server/public/settings.js +1155 -1080
  28. package/harness/packages/server/public/settingsNav.js +81 -0
  29. package/harness/packages/server/public/styles.css +2807 -2525
  30. package/harness/packages/server/public/system.js +2 -2
  31. package/harness/packages/server/src/lib/appearance.js +4 -0
  32. package/harness/packages/server/src/lib/restart.js +20 -0
  33. package/harness/packages/server/src/lib/securityHeaders.js +53 -0
  34. package/harness/packages/server/src/routes/reload.js +46 -0
  35. package/harness/packages/server/src/server.js +6 -1
  36. package/harness/packages/server/test/accessibility.test.js +72 -0
  37. package/harness/packages/server/test/appearance.test.js +4 -0
  38. package/harness/packages/server/test/consoleModules.test.js +133 -57
  39. package/harness/packages/server/test/consoleTabs.test.js +228 -0
  40. package/harness/packages/server/test/docsSync.test.js +73 -0
  41. package/harness/packages/server/test/landingLogin.test.js +89 -0
  42. package/harness/packages/server/test/markdownSecurity.test.js +80 -0
  43. package/harness/packages/server/test/reload.test.js +95 -0
  44. package/harness/packages/server/test/securityHeaders.test.js +109 -0
  45. package/harness/packages/server/test/settingsNav.test.js +90 -0
  46. package/harness/packages/server/test/themeCss.js +110 -0
  47. package/harness/packages/server/test/themes.test.js +72 -0
  48. package/harness/scripts/restart.mjs +101 -0
  49. package/package.json +1 -1
@@ -8,62 +8,7 @@
8
8
  <link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
9
9
  <link rel="manifest" href="/manifest.webmanifest" />
10
10
  <meta name="theme-color" content="#231a17" />
11
- <script>
12
- (function () {
13
- var root = document.documentElement;
14
- var THEMES = ['paper', 'dark', 'midnight', 'nord', 'dracula', 'solarized', 'solarized-dark', 'bosque', 'vino', 'vercel', 'dark-plus', 'github', 'github-dark'];
15
- var DARK = ['dark', 'midnight', 'nord', 'dracula', 'solarized-dark', 'vercel', 'dark-plus', 'github-dark'];
16
- var appearance = null;
17
- try {
18
- appearance = JSON.parse(localStorage.getItem('tamnora-console-appearance') || 'null');
19
- } catch {
20
- appearance = null;
21
- }
22
- var theme = appearance && appearance.theme;
23
- if (!theme) {
24
- try {
25
- theme = localStorage.getItem('tamnora-console-theme');
26
- } catch {
27
- theme = null;
28
- }
29
- }
30
- if (theme === 'light') theme = 'paper';
31
- if (THEMES.indexOf(theme) < 0) {
32
- theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'paper';
33
- }
34
- root.dataset.theme = theme;
35
- root.dataset.scheme = DARK.indexOf(theme) >= 0 ? 'dark' : 'light';
36
- if (!appearance) return;
37
- if (appearance.fontCss) {
38
- root.style.setProperty('--sans', appearance.fontCss.sans);
39
- root.style.setProperty('--serif', appearance.fontCss.serif);
40
- root.style.setProperty('--mono', appearance.fontCss.mono);
41
- root.style.setProperty('--font', 'var(--sans)');
42
- }
43
- var href = appearance.google ? 'https://fonts.googleapis.com/css2?' + appearance.google + '&display=swap' : null;
44
- var flink = document.getElementById('tamnora-fonts');
45
- if (!href) {
46
- if (flink) flink.remove();
47
- } else if (!flink) {
48
- flink = document.createElement('link');
49
- flink.rel = 'stylesheet';
50
- flink.id = 'tamnora-fonts';
51
- flink.href = href;
52
- document.head.appendChild(flink);
53
- } else if (flink.getAttribute('href') !== href) {
54
- flink.setAttribute('href', href);
55
- }
56
- if (appearance.chatFont) root.style.setProperty('--chat-font', appearance.chatFont + 'px');
57
- if (appearance.scale) root.style.zoom = String(appearance.scale);
58
- })();
59
- (function () {
60
- // La consola resuelve el acceso con /api/auth/me; mientras tanto, oculta.
61
- var style = document.createElement('style');
62
- style.textContent = "html[data-auth='pending'] body { visibility: hidden }";
63
- document.head.appendChild(style);
64
- document.documentElement.dataset.auth = 'pending';
65
- })();
66
- </script>
11
+ <script src="/boot.js"></script>
67
12
  <link rel="preconnect" href="https://fonts.googleapis.com" />
68
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
69
14
  <link
@@ -75,7 +20,7 @@
75
20
  </head>
76
21
  <body>
77
22
  <header class="topbar">
78
- <div class="brand"><span class="logo"><img src="/icons/logo.png" alt="Tamnora" /></span> <button id="back-chat" type="button" class="back-chat" title="volver al chat" aria-label="volver al chat" hidden><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg><span>chat</span></button> <span id="topbar-section" class="topbar-section">chat</span> <span class="ver">v0.24.2</span></div>
23
+ <div class="brand"><span class="logo"><img src="/icons/logo.png" alt="Tamnora" /></span> <button id="back-chat" type="button" class="back-chat" title="volver al chat" aria-label="volver al chat" hidden><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg><span>chat</span></button> <span id="topbar-section" class="topbar-section">chat</span> <span class="ver">v0.25.0</span></div>
79
24
  <div class="settings">
80
25
  <button id="new-session-top" type="button" class="btn topbar-new" title="nueva sesión" aria-label="nueva sesión">
81
26
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true">
@@ -90,9 +35,11 @@
90
35
  </svg>
91
36
  </button>
92
37
  <div class="menu">
93
- <button id="more-tab" type="button" class="btn icon" title="herramientas" aria-haspopup="menu" aria-controls="more-menu" aria-expanded="false" aria-label="herramientas">
94
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
95
- <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
38
+ <button id="more-tab" type="button" class="btn icon" title="más opciones" aria-haspopup="menu" aria-controls="more-menu" aria-expanded="false" aria-label="más opciones">
39
+ <svg viewBox="0 0 24 24" fill="currentColor" stroke="none" aria-hidden="true">
40
+ <circle cx="12" cy="5" r="1.7" />
41
+ <circle cx="12" cy="12" r="1.7" />
42
+ <circle cx="12" cy="19" r="1.7" />
96
43
  </svg>
97
44
  </button>
98
45
  <div id="more-menu" class="menu-pop" role="menu" hidden>
@@ -104,7 +51,7 @@
104
51
  <button type="button" data-tab="runs" role="menuitem">runs</button>
105
52
  </div>
106
53
  </div>
107
- <button id="settings-toggle" type="button" class="btn icon" title="modelo, modo y auto" aria-label="ajustes del agente">
54
+ <button id="settings-toggle" type="button" class="btn icon" title="modelo, modo y auto (ventana rápida)" aria-label="modelo y modo del agente">
108
55
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
109
56
  <path d="M21 4h-7M10 4H3M21 12h-9M8 12H3M21 20h-5M12 20H3" />
110
57
  <path d="M14 2v4M8 10v4M16 18v4" />
@@ -251,19 +198,21 @@
251
198
  <span id="model-pill-label">—</span>
252
199
  <svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
253
200
  </button>
254
- <button class="send-btn" type="submit" aria-label="enviar" title="enviar">
255
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12 7-7 7 7" /><path d="M12 19V5" /></svg>
256
- </button>
257
- <button class="add-btn interrupt-btn" type="button" id="interrupt-btn" title="Interrumpir al agente y enviar este mensaje (Ctrl+Enter)" aria-label="interrumpir y enviar" hidden>
258
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></svg>
259
- </button>
260
- <button class="add-btn" type="button" id="stop-btn" title="Detener la respuesta" aria-label="detener" hidden>
261
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>
262
- </button>
201
+ <div class="composer-actions">
202
+ <button class="send-btn" type="submit" aria-label="enviar" title="enviar">
203
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 12 7-7 7 7" /><path d="M12 19V5" /></svg>
204
+ </button>
205
+ <button class="add-btn interrupt-btn" type="button" id="interrupt-btn" title="Interrumpir al agente y enviar este mensaje (Ctrl+Enter)" aria-label="interrumpir y enviar" hidden>
206
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></svg>
207
+ </button>
208
+ <button class="add-btn" type="button" id="stop-btn" title="Detener la respuesta" aria-label="detener" hidden>
209
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>
210
+ </button>
211
+ </div>
263
212
  </div>
264
213
 
265
214
  <div id="statusbar" class="composer-status" title="estado del run" role="button" tabindex="0">
266
- <span id="sb-activity" class="sb-activity" hidden></span>
215
+ <span id="sb-activity" class="sb-activity" role="status" hidden></span>
267
216
  <span id="sb-sync" class="sb-channel retrying" hidden title="sin sincronía con el server"></span>
268
217
  <span id="sb-channel" class="sb-channel" hidden title="canal de eventos entre dispositivos"></span>
269
218
  <span id="sb-rounds">listo</span>
@@ -507,24 +456,45 @@
507
456
  </section>
508
457
 
509
458
  <section id="view-ajustes" class="view">
510
- <div class="ajustes-wrap">
511
- <nav class="ajustes-tabs" role="tablist" aria-label="secciones de ajustes">
512
- <button type="button" class="ajustes-tab active" data-panel="agente" role="tab">Agente</button>
513
- <button type="button" class="ajustes-tab" data-panel="perfil" role="tab">Perfil</button>
514
- <button type="button" class="ajustes-tab" data-panel="sesiones" role="tab">Sesiones</button>
515
- <button type="button" class="ajustes-tab" data-panel="mcp" role="tab">MCP</button>
516
- <button type="button" class="ajustes-tab" data-panel="skills" role="tab">Skills</button>
517
- <button type="button" class="ajustes-tab" data-panel="memoria" role="tab">Memoria</button>
518
- <button type="button" class="ajustes-tab" data-panel="tareas" role="tab">Tareas</button>
519
- <button type="button" class="ajustes-tab" data-panel="telegram" role="tab">Telegram</button>
520
- <button type="button" class="ajustes-tab" data-panel="voz" role="tab">Voz</button>
521
- <button type="button" class="ajustes-tab" data-panel="asesor" role="tab">Asesor</button>
522
- <button type="button" class="ajustes-tab" data-panel="transcripcion" role="tab">Transcripción</button>
523
- <button type="button" class="ajustes-tab" data-panel="limites" role="tab">Límites</button>
524
- <button type="button" class="ajustes-tab" data-panel="apariencia" role="tab">Apariencia</button>
525
- </nav>
459
+ <div class="ajustes-wrap" data-level="list">
460
+ <aside class="ajustes-side">
461
+ <input id="ajustes-search" class="ajustes-search" type="search" placeholder="buscar en ajustes…" aria-label="buscar en ajustes" autocomplete="off" spellcheck="false" />
462
+ <nav class="ajustes-tabs" role="tablist" aria-orientation="vertical" aria-label="secciones de ajustes">
463
+ <div class="ajustes-group" data-group="trabajo" role="presentation">
464
+ <span class="ajustes-group-title" aria-hidden="true">Trabajo</span>
465
+ <button type="button" class="ajustes-tab active" id="ajustes-tab-agente" data-panel="agente" role="tab" aria-selected="true" aria-controls="ajustes-panel-agente">Agente</button>
466
+ <button type="button" class="ajustes-tab" id="ajustes-tab-sesiones" data-panel="sesiones" role="tab" aria-selected="false" aria-controls="ajustes-panel-sesiones">Sesiones</button>
467
+ <button type="button" class="ajustes-tab" id="ajustes-tab-tareas" data-panel="tareas" role="tab" aria-selected="false" aria-controls="ajustes-panel-tareas">Tareas</button>
468
+ <button type="button" class="ajustes-tab" id="ajustes-tab-limites" data-panel="limites" role="tab" aria-selected="false" aria-controls="ajustes-panel-limites">Límites</button>
469
+ </div>
470
+ <div class="ajustes-group" data-group="contexto" role="presentation">
471
+ <span class="ajustes-group-title" aria-hidden="true">Contexto</span>
472
+ <button type="button" class="ajustes-tab" id="ajustes-tab-perfil" data-panel="perfil" role="tab" aria-selected="false" aria-controls="ajustes-panel-perfil">Perfil</button>
473
+ <button type="button" class="ajustes-tab" id="ajustes-tab-memoria" data-panel="memoria" role="tab" aria-selected="false" aria-controls="ajustes-panel-memoria">Memoria</button>
474
+ <button type="button" class="ajustes-tab" id="ajustes-tab-skills" data-panel="skills" role="tab" aria-selected="false" aria-controls="ajustes-panel-skills">Skills</button>
475
+ <button type="button" class="ajustes-tab" id="ajustes-tab-mcp" data-panel="mcp" role="tab" aria-selected="false" aria-controls="ajustes-panel-mcp">MCP</button>
476
+ </div>
477
+ <div class="ajustes-group" data-group="canales" role="presentation">
478
+ <span class="ajustes-group-title" aria-hidden="true">Voz y canales</span>
479
+ <button type="button" class="ajustes-tab" id="ajustes-tab-voz" data-panel="voz" role="tab" aria-selected="false" aria-controls="ajustes-panel-voz">Voz</button>
480
+ <button type="button" class="ajustes-tab" id="ajustes-tab-transcripcion" data-panel="transcripcion" role="tab" aria-selected="false" aria-controls="ajustes-panel-transcripcion">Transcripción</button>
481
+ <button type="button" class="ajustes-tab" id="ajustes-tab-asesor" data-panel="asesor" role="tab" aria-selected="false" aria-controls="ajustes-panel-asesor">Asesor</button>
482
+ <button type="button" class="ajustes-tab" id="ajustes-tab-telegram" data-panel="telegram" role="tab" aria-selected="false" aria-controls="ajustes-panel-telegram">Telegram</button>
483
+ </div>
484
+ <div class="ajustes-group" data-group="interfaz" role="presentation">
485
+ <span class="ajustes-group-title" aria-hidden="true">Interfaz</span>
486
+ <button type="button" class="ajustes-tab" id="ajustes-tab-apariencia" data-panel="apariencia" role="tab" aria-selected="false" aria-controls="ajustes-panel-apariencia">Apariencia</button>
487
+ </div>
488
+ </nav>
489
+ <p id="ajustes-empty" class="ajustes-empty muted" hidden>sin resultados</p>
490
+ </aside>
491
+ <div class="ajustes-main">
492
+ <button type="button" id="ajustes-back" class="ajustes-back" aria-label="volver a la lista de ajustes">
493
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg>
494
+ <span>ajustes</span>
495
+ </button>
526
496
 
527
- <div class="panel ajustes-panel active" data-panel="agente">
497
+ <div class="panel ajustes-panel active" id="ajustes-panel-agente" data-panel="agente" role="tabpanel" aria-labelledby="ajustes-tab-agente">
528
498
  <div class="row between">
529
499
  <h2>Agente</h2>
530
500
  </div>
@@ -556,7 +526,7 @@
556
526
  </div>
557
527
  </div>
558
528
 
559
- <div class="panel ajustes-panel" data-panel="perfil">
529
+ <div class="panel ajustes-panel" id="ajustes-panel-perfil" data-panel="perfil" role="tabpanel" aria-labelledby="ajustes-tab-perfil">
560
530
  <div class="row between">
561
531
  <h2>Perfil</h2>
562
532
  <span id="perfil-status" class="summary">cargando…</span>
@@ -588,7 +558,7 @@
588
558
  </div>
589
559
  </div>
590
560
 
591
- <div class="panel ajustes-panel" data-panel="sesiones">
561
+ <div class="panel ajustes-panel" id="ajustes-panel-sesiones" data-panel="sesiones" role="tabpanel" aria-labelledby="ajustes-tab-sesiones">
592
562
  <div class="row between">
593
563
  <h2>Sesiones</h2>
594
564
  </div>
@@ -607,7 +577,7 @@
607
577
  </div>
608
578
  </div>
609
579
 
610
- <div class="panel ajustes-panel" data-panel="mcp">
580
+ <div class="panel ajustes-panel" id="ajustes-panel-mcp" data-panel="mcp" role="tabpanel" aria-labelledby="ajustes-tab-mcp">
611
581
  <div class="row between">
612
582
  <h2>Servidores MCP</h2>
613
583
  <div class="row">
@@ -650,7 +620,7 @@
650
620
  </details>
651
621
  </div>
652
622
 
653
- <div class="panel ajustes-panel" data-panel="skills">
623
+ <div class="panel ajustes-panel" id="ajustes-panel-skills" data-panel="skills" role="tabpanel" aria-labelledby="ajustes-tab-skills">
654
624
  <div class="row between">
655
625
  <h2>Skills</h2>
656
626
  <button id="skill-new" class="btn">+ nueva</button>
@@ -676,7 +646,7 @@
676
646
  </details>
677
647
  </div>
678
648
 
679
- <div class="panel ajustes-panel" data-panel="memoria">
649
+ <div class="panel ajustes-panel" id="ajustes-panel-memoria" data-panel="memoria" role="tabpanel" aria-labelledby="ajustes-tab-memoria">
680
650
  <div class="row between">
681
651
  <h2>Memoria</h2>
682
652
  <button id="memory-new" class="btn">+ tema</button>
@@ -695,7 +665,7 @@
695
665
  <ul id="memory-list" class="providers"></ul>
696
666
  </div>
697
667
 
698
- <div class="panel ajustes-panel" data-panel="tareas">
668
+ <div class="panel ajustes-panel" id="ajustes-panel-tareas" data-panel="tareas" role="tabpanel" aria-labelledby="ajustes-tab-tareas">
699
669
  <div class="row between">
700
670
  <h2>Tareas</h2>
701
671
  <button id="schedule-new" class="btn">+ tarea</button>
@@ -708,7 +678,7 @@
708
678
  <ul id="schedule-list" class="providers"></ul>
709
679
  </div>
710
680
 
711
- <div class="panel ajustes-panel" data-panel="telegram">
681
+ <div class="panel ajustes-panel" id="ajustes-panel-telegram" data-panel="telegram" role="tabpanel" aria-labelledby="ajustes-tab-telegram">
712
682
  <div class="row between">
713
683
  <h2>Telegram</h2>
714
684
  <span id="tg-status" class="summary">cargando…</span>
@@ -768,7 +738,7 @@
768
738
  </div>
769
739
  </div>
770
740
 
771
- <div class="panel ajustes-panel" data-panel="voz">
741
+ <div class="panel ajustes-panel" id="ajustes-panel-voz" data-panel="voz" role="tabpanel" aria-labelledby="ajustes-tab-voz">
772
742
  <div class="row between">
773
743
  <h2>Voz</h2>
774
744
  <span id="voz-status" class="summary">cargando…</span>
@@ -828,7 +798,7 @@
828
798
  </div>
829
799
  </div>
830
800
 
831
- <div class="panel ajustes-panel" data-panel="asesor">
801
+ <div class="panel ajustes-panel" id="ajustes-panel-asesor" data-panel="asesor" role="tabpanel" aria-labelledby="ajustes-tab-asesor">
832
802
  <div class="row between">
833
803
  <h2>Asesor</h2>
834
804
  <span id="asesor-status" class="summary">cargando…</span>
@@ -877,7 +847,7 @@
877
847
  </div>
878
848
  </div>
879
849
 
880
- <div class="panel ajustes-panel" data-panel="transcripcion">
850
+ <div class="panel ajustes-panel" id="ajustes-panel-transcripcion" data-panel="transcripcion" role="tabpanel" aria-labelledby="ajustes-tab-transcripcion">
881
851
  <div class="row between">
882
852
  <h2>Transcripción</h2>
883
853
  <span id="tr-status" class="summary">cargando…</span>
@@ -933,7 +903,7 @@
933
903
  <p id="tr-test-result" class="summary"></p>
934
904
  </div>
935
905
 
936
- <div class="panel ajustes-panel" data-panel="limites">
906
+ <div class="panel ajustes-panel" id="ajustes-panel-limites" data-panel="limites" role="tabpanel" aria-labelledby="ajustes-tab-limites">
937
907
  <div class="row between">
938
908
  <h2>Límites del agente</h2>
939
909
  </div>
@@ -962,7 +932,7 @@
962
932
  </div>
963
933
  </div>
964
934
 
965
- <div class="panel ajustes-panel" data-panel="apariencia">
935
+ <div class="panel ajustes-panel" id="ajustes-panel-apariencia" data-panel="apariencia" role="tabpanel" aria-labelledby="ajustes-tab-apariencia">
966
936
  <div class="row between">
967
937
  <h2>Apariencia</h2>
968
938
  </div>
@@ -995,6 +965,7 @@
995
965
  <span id="apariencia-msg" class="summary"></span>
996
966
  </div>
997
967
  </div>
968
+ </div>
998
969
  </div>
999
970
  </section>
1000
971
 
@@ -1058,7 +1029,7 @@
1058
1029
  <dialog id="settings-modal" class="modal settings-modal">
1059
1030
  <div class="modal-card">
1060
1031
  <div class="row between">
1061
- <h3>ajustes del agente</h3>
1032
+ <h3>modelo y modo del agente</h3>
1062
1033
  <button type="button" id="settings-close" class="btn icon" title="cerrar" aria-label="cerrar">
1063
1034
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
1064
1035
  <path d="M18 6 6 18M6 6l12 12" />
@@ -0,0 +1,16 @@
1
+ (function () {
2
+ var THEMES = ['paper', 'dark', 'midnight', 'nord', 'dracula', 'solarized', 'solarized-dark', 'bosque', 'vino', 'arena', 'hielo', 'vercel', 'dark-plus', 'github', 'github-dark', 'mocha', 'ebano'];
3
+ var DARK = ['dark', 'midnight', 'nord', 'dracula', 'solarized-dark', 'vercel', 'dark-plus', 'github-dark', 'mocha', 'ebano'];
4
+ var theme = null;
5
+ try {
6
+ theme = localStorage.getItem('tamnora-console-theme');
7
+ } catch {
8
+ theme = null;
9
+ }
10
+ if (theme === 'light') theme = 'paper';
11
+ if (THEMES.indexOf(theme) < 0) {
12
+ theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'paper';
13
+ }
14
+ document.documentElement.dataset.theme = theme;
15
+ document.documentElement.dataset.scheme = DARK.indexOf(theme) >= 0 ? 'dark' : 'light';
16
+ })();
@@ -8,24 +8,7 @@
8
8
  <link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
9
9
  <link rel="manifest" href="/manifest.webmanifest" />
10
10
  <meta name="theme-color" content="#231a17" />
11
- <script>
12
- (function () {
13
- var THEMES = ['paper', 'dark', 'midnight', 'nord', 'dracula', 'solarized', 'solarized-dark', 'bosque', 'vino', 'vercel', 'dark-plus', 'github', 'github-dark'];
14
- var DARK = ['dark', 'midnight', 'nord', 'dracula', 'solarized-dark', 'vercel', 'dark-plus', 'github-dark'];
15
- var theme = null;
16
- try {
17
- theme = localStorage.getItem('tamnora-console-theme');
18
- } catch {
19
- theme = null;
20
- }
21
- if (theme === 'light') theme = 'paper';
22
- if (THEMES.indexOf(theme) < 0) {
23
- theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'paper';
24
- }
25
- document.documentElement.dataset.theme = theme;
26
- document.documentElement.dataset.scheme = DARK.indexOf(theme) >= 0 ? 'dark' : 'light';
27
- })();
28
- </script>
11
+ <script src="/landing/boot.js"></script>
29
12
  <link rel="preconnect" href="https://fonts.googleapis.com" />
30
13
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
31
14
  <link
@@ -400,6 +383,118 @@
400
383
  --page-tint: linear-gradient(180deg, rgba(13, 17, 23, 0.4), rgba(22, 27, 34, 0.4));
401
384
  }
402
385
 
386
+ html[data-theme='arena'] {
387
+ color-scheme: light;
388
+ --paper: #f6efdd;
389
+ --paper-2: #ece2c9;
390
+ --ink: #2c2419;
391
+ --muted: #6b5c42;
392
+ --line: rgba(44, 36, 25, 0.16);
393
+ --border-strong: rgba(44, 36, 25, 0.35);
394
+ --accent: #9c5c22;
395
+ --accent-dark: #7e4718;
396
+ --glass: rgba(250, 245, 232, 0.75);
397
+ --nav: #4c4335;
398
+ --copy: #574c3a;
399
+ --hint: #77684c;
400
+ --label: #5f5544;
401
+ --kicker: #6b5c42;
402
+ --surface: rgba(250, 245, 232, 0.58);
403
+ --surface-strong: rgba(250, 245, 232, 0.8);
404
+ --field-bg: rgba(255, 252, 244, 0.72);
405
+ --btn-bg: var(--ink);
406
+ --btn-fg: #fbf6ea;
407
+ --btn-hover: #3c3226;
408
+ --footer: rgba(76, 67, 53, 0.62);
409
+ --page-outer: #d9d2c2;
410
+ --page-bg: linear-gradient(90deg, rgba(250, 245, 232, 0.74) 0%, rgba(250, 245, 232, 0.42) 43%, rgba(250, 245, 232, 0.12) 100%), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
411
+ --page-tint: linear-gradient(180deg, rgba(246, 239, 221, 0.24), rgba(226, 216, 194, 0.24));
412
+ }
413
+
414
+ html[data-theme='hielo'] {
415
+ color-scheme: light;
416
+ --paper: #edf3f7;
417
+ --paper-2: #dae6ee;
418
+ --ink: #1c2a35;
419
+ --muted: #51626e;
420
+ --line: rgba(28, 42, 53, 0.16);
421
+ --border-strong: rgba(28, 42, 53, 0.35);
422
+ --accent: #2b6a8c;
423
+ --accent-dark: #1f5470;
424
+ --glass: rgba(240, 246, 250, 0.75);
425
+ --nav: #35434e;
426
+ --copy: #46545e;
427
+ --hint: #5b6c78;
428
+ --label: #4c5a66;
429
+ --kicker: #51626e;
430
+ --surface: rgba(240, 246, 250, 0.58);
431
+ --surface-strong: rgba(240, 246, 250, 0.8);
432
+ --field-bg: rgba(252, 254, 255, 0.72);
433
+ --btn-bg: var(--ink);
434
+ --btn-fg: #f2f8fc;
435
+ --btn-hover: #2c3b46;
436
+ --footer: rgba(53, 67, 78, 0.62);
437
+ --page-outer: #ccd8e0;
438
+ --page-bg: linear-gradient(90deg, rgba(240, 246, 250, 0.74) 0%, rgba(240, 246, 250, 0.42) 43%, rgba(240, 246, 250, 0.12) 100%), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
439
+ --page-tint: linear-gradient(180deg, rgba(221, 232, 240, 0.24), rgba(202, 218, 230, 0.24));
440
+ }
441
+
442
+ html[data-theme='mocha'] {
443
+ color-scheme: dark;
444
+ --paper: #211912;
445
+ --paper-2: #2b2116;
446
+ --ink: #f0e5d2;
447
+ --muted: #b3a288;
448
+ --line: rgba(240, 229, 210, 0.16);
449
+ --border-strong: rgba(240, 229, 210, 0.3);
450
+ --accent: #e0a878;
451
+ --accent-dark: #c98d5f;
452
+ --glass: rgba(38, 29, 20, 0.8);
453
+ --nav: #cfc2ac;
454
+ --copy: #bfae94;
455
+ --hint: #a89679;
456
+ --label: #b8a88e;
457
+ --kicker: #b3a288;
458
+ --surface: rgba(240, 229, 210, 0.07);
459
+ --surface-strong: rgba(240, 229, 210, 0.15);
460
+ --field-bg: rgba(240, 229, 210, 0.06);
461
+ --btn-bg: var(--accent);
462
+ --btn-fg: #241a10;
463
+ --btn-hover: #c98d5f;
464
+ --footer: rgba(224, 205, 180, 0.5);
465
+ --page-outer: #15100a;
466
+ --page-bg: linear-gradient(90deg, rgba(24, 18, 11, 0.82) 0%, rgba(24, 18, 11, 0.6) 43%, rgba(24, 18, 11, 0.32) 100%), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
467
+ --page-tint: linear-gradient(180deg, rgba(33, 25, 18, 0.32), rgba(42, 32, 22, 0.32));
468
+ }
469
+
470
+ html[data-theme='ebano'] {
471
+ color-scheme: dark;
472
+ --paper: #14191f;
473
+ --paper-2: #1c242c;
474
+ --ink: #e3ebf2;
475
+ --muted: #93a2ae;
476
+ --line: rgba(227, 235, 242, 0.14);
477
+ --border-strong: rgba(227, 235, 242, 0.28);
478
+ --accent: #6fa8c9;
479
+ --accent-dark: #5489a7;
480
+ --glass: rgba(21, 27, 34, 0.8);
481
+ --nav: #c3d0da;
482
+ --copy: #adbac6;
483
+ --hint: #8b9aa6;
484
+ --label: #9fadb9;
485
+ --kicker: #93a2ae;
486
+ --surface: rgba(227, 235, 242, 0.07);
487
+ --surface-strong: rgba(227, 235, 242, 0.15);
488
+ --field-bg: rgba(227, 235, 242, 0.05);
489
+ --btn-bg: var(--accent);
490
+ --btn-fg: #10161c;
491
+ --btn-hover: #5489a7;
492
+ --footer: rgba(215, 226, 235, 0.5);
493
+ --page-outer: #0c1014;
494
+ --page-bg: linear-gradient(90deg, rgba(12, 16, 20, 0.85) 0%, rgba(12, 16, 20, 0.6) 43%, rgba(12, 16, 20, 0.32) 100%), url("/img/fondo-agentes.webp") center/cover fixed no-repeat;
495
+ --page-tint: linear-gradient(180deg, rgba(20, 25, 31, 0.32), rgba(28, 36, 44, 0.32));
496
+ }
497
+
403
498
  * { box-sizing: border-box; }
404
499
 
405
500
  html, body {
@@ -439,10 +534,10 @@
439
534
  .logo { display: flex; align-items: center; gap: 13px; text-decoration: none; color: var(--ink); }
440
535
 
441
536
  .logo-mark {
442
- width: 39px;
443
- height: 39px;
444
- border: 1px solid var(--border-strong);
445
- border-radius: 11px;
537
+ width: 45px;
538
+ height: 45px;
539
+ /* border: 1px solid var(--border-strong); */
540
+ /* border-radius: 11px; */
446
541
  display: grid;
447
542
  place-items: center;
448
543
  overflow: hidden;
@@ -462,7 +557,8 @@
462
557
  .logo-text small {
463
558
  display: block;
464
559
  margin-top: 2px;
465
- font: 500 8px var(--mono);
560
+ padding-left: 5px;
561
+ font: 500 9px var(--mono);
466
562
  letter-spacing: 0.24em;
467
563
  color: var(--hint);
468
564
  text-transform: uppercase;
@@ -509,7 +605,7 @@
509
605
  grid-template-columns: 1.08fr 0.92fr;
510
606
  align-items: center;
511
607
  gap: 70px;
512
- padding: 42px 0 80px;
608
+ padding: 42px 0 40px;
513
609
  }
514
610
 
515
611
  .kicker {
@@ -745,8 +841,6 @@
745
841
  </a>
746
842
 
747
843
  <nav>
748
- <a href="#inicio">Inicio</a>
749
- <a href="#caracteristicas">Características</a>
750
844
  <button type="button" id="theme-toggle" class="nav-icon" title="cambiar tema" aria-label="cambiar tema">
751
845
  <svg class="ico-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
752
846
  <circle cx="12" cy="12" r="4" />
@@ -756,13 +850,12 @@
756
850
  <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
757
851
  </svg>
758
852
  </button>
759
- <a href="#acceso" class="nav-login">Ingresar</a>
760
853
  </nav>
761
854
  </header>
762
855
 
763
856
  <main class="hero" id="inicio">
764
857
  <section>
765
- <div class="kicker">Harness de agentes IA</div>
858
+ <!-- <div class="kicker">Harness de agentes IA</div> -->
766
859
 
767
860
  <h1>Tamnora<br /><span>Harness</span></h1>
768
861
 
@@ -772,37 +865,8 @@
772
865
  navegador headless, narra su progreso y hace trazable cada corrida.
773
866
  </p>
774
867
 
775
- <div class="actions">
776
- <a href="#acceso" class="btn btn-primary">Ingresar al sistema</a>
777
- <a href="#caracteristicas" class="btn btn-secondary">Conocer más</a>
778
- </div>
779
-
780
- <div class="features" id="caracteristicas">
781
- <div class="feature">
782
- <div class="feature-icon">◈</div>
783
- <div><b>Local</b><span>Corre en tu máquina; el estado vive en tu casa.</span></div>
784
- </div>
785
- <div class="feature">
786
- <div class="feature-icon">↗</div>
787
- <div><b>Accesible</b><span>Consola web, TUI y Telegram; túnel con QR.</span></div>
788
- </div>
789
- <div class="feature">
790
- <div class="feature-icon">✓</div>
791
- <div><b>Control</b><span>Permisos allow/ask/deny y runs trazables.</span></div>
792
- </div>
793
- <div class="feature">
794
- <div class="feature-icon">◎</div>
795
- <div><b>Navegador</b><span>Screenshot y errores de consola de una página.</span></div>
796
- </div>
797
- <div class="feature">
798
- <div class="feature-icon">♪</div>
799
- <div><b>Voz</b><span>Narra el progreso y manda audio bajo pedido.</span></div>
800
- </div>
801
- <div class="feature">
802
- <div class="feature-icon">⌘</div>
803
- <div><b>Multi-modelo</b><span>OpenRouter, OpenAI, Claude, Gemini y Ollama.</span></div>
804
- </div>
805
- </div>
868
+
869
+
806
870
  </section>
807
871
 
808
872
  <section class="login-wrap" id="acceso">
@@ -11,15 +11,17 @@ const forgot = document.getElementById('forgot');
11
11
  const enterDirect = document.getElementById('enter-direct');
12
12
  const themeToggle = document.getElementById('theme-toggle');
13
13
 
14
- themeToggle.addEventListener('click', () => {
15
- const next = nextTheme(document.documentElement.dataset.theme);
16
- document.documentElement.dataset.theme = next;
17
- try {
18
- localStorage.setItem('tamnora-console-theme', next);
19
- } catch {
20
- // storage unavailable
21
- }
22
- });
14
+ if (themeToggle) {
15
+ themeToggle.addEventListener('click', () => {
16
+ const next = nextTheme(document.documentElement.dataset.theme);
17
+ document.documentElement.dataset.theme = next;
18
+ try {
19
+ localStorage.setItem('tamnora-console-theme', next);
20
+ } catch {
21
+ // storage unavailable
22
+ }
23
+ });
24
+ }
23
25
 
24
26
  function showToast(text) {
25
27
  toast.textContent = text;
@@ -110,7 +110,7 @@ export function highlight(code, lang) {
110
110
  }
111
111
 
112
112
  function inline(text) {
113
- let out = escapeHtml(text);
113
+ let out = escapeHtml(text).replace(/\uE000/g, '');
114
114
  const codes = [];
115
115
  out = out.replace(/`([^`]+)`/g, (_, code) => {
116
116
  codes.push(code);