@danieltmn/tamnora 0.11.0 → 0.11.2
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.
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ Todos los cambios relevantes de este proyecto se documentan en este archivo.
|
|
|
5
5
|
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/)
|
|
6
6
|
y el proyecto usa [Versionado Semantico](https://semver.org/lang/es/).
|
|
7
7
|
|
|
8
|
+
## [0.11.2] - 2026-10-09
|
|
9
|
+
|
|
10
|
+
### Arreglado
|
|
11
|
+
|
|
12
|
+
- **CI en Node 22**: el backoff de `withRetry` usaba un timer `unref`, que dejaba
|
|
13
|
+
que el event loop se vaciara y `node:test` cancelara los tests de
|
|
14
|
+
`resilience.test.js` ("Promise resolution is still pending..."). Se quito el
|
|
15
|
+
`unref`: ahora el reintento mantiene el loop vivo y la suite pasa en Node 22.
|
|
16
|
+
|
|
17
|
+
## [0.11.1] - 2026-10-09
|
|
18
|
+
|
|
19
|
+
### Arreglado
|
|
20
|
+
|
|
21
|
+
- **Consola en movil**: el input del chat ahora es un campo visible en su propia
|
|
22
|
+
linea (antes flotaba sin fondo y casi no se notaba); las cards de MCP/Skills
|
|
23
|
+
(y tambien proveedores y procesos) llevan las acciones a su propia fila y la
|
|
24
|
+
descripcion se recorta a dos lineas en vez de apretarse contra los botones.
|
|
25
|
+
|
|
8
26
|
## [0.11.0] - 2026-10-09
|
|
9
27
|
|
|
10
28
|
### Quitado
|
|
@@ -26,8 +26,10 @@ export function isRetryableError(err) {
|
|
|
26
26
|
|
|
27
27
|
function sleep(ms, signal) {
|
|
28
28
|
return new Promise((resolve, reject) => {
|
|
29
|
+
// Sin `unref`: en Node 22 un timer sin referencias deja que el event loop se
|
|
30
|
+
// vacíe y `node:test` cancela los tests ("Promise resolution is still
|
|
31
|
+
// pending..."). Si abortan, el listener de abajo lo limpia.
|
|
29
32
|
const timer = setTimeout(resolve, ms);
|
|
30
|
-
timer.unref?.();
|
|
31
33
|
if (!signal) return;
|
|
32
34
|
if (signal.aborted) {
|
|
33
35
|
clearTimeout(timer);
|
|
@@ -3577,9 +3577,11 @@ function renderProviderList() {
|
|
|
3577
3577
|
)
|
|
3578
3578
|
);
|
|
3579
3579
|
li.appendChild(main);
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3580
|
+
const actions = el('div', 'pactions');
|
|
3581
|
+
actions.appendChild(button('usar', (event) => { event.stopPropagation(); useProvider(p.id); }));
|
|
3582
|
+
actions.appendChild(button('editar', (event) => { event.stopPropagation(); openProviderForm(p); }));
|
|
3583
|
+
if (p.stored) actions.appendChild(button('borrar', (event) => { event.stopPropagation(); removeProvider(p.id); }, 'btn danger'));
|
|
3584
|
+
li.appendChild(actions);
|
|
3583
3585
|
li.addEventListener('click', () => openProviderForm(p));
|
|
3584
3586
|
providerListEl.appendChild(li);
|
|
3585
3587
|
}
|
|
@@ -3779,9 +3781,11 @@ async function refreshMcp({ connect = false } = {}) {
|
|
|
3779
3781
|
}
|
|
3780
3782
|
main.append(title, el('div', 'pmeta', parts.join(' · ')));
|
|
3781
3783
|
li.appendChild(main);
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3784
|
+
const actions = el('div', 'pactions');
|
|
3785
|
+
actions.appendChild(button(s.enabled ? 'deshabilitar' : 'habilitar', (event) => { event.stopPropagation(); toggleMcp(s); }));
|
|
3786
|
+
actions.appendChild(button('editar', (event) => { event.stopPropagation(); openMcpForm(s); }));
|
|
3787
|
+
if (s.source !== 'config') actions.appendChild(button('borrar', (event) => { event.stopPropagation(); removeMcp(s.id); }, 'btn danger'));
|
|
3788
|
+
li.appendChild(actions);
|
|
3785
3789
|
li.addEventListener('click', () => openMcpForm(s));
|
|
3786
3790
|
mcpListEl.appendChild(li);
|
|
3787
3791
|
}
|
|
@@ -3895,9 +3899,11 @@ async function refreshSkills() {
|
|
|
3895
3899
|
el('div', 'pmeta', s.description || s.when || '(sin descripción)')
|
|
3896
3900
|
);
|
|
3897
3901
|
li.appendChild(main);
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3902
|
+
const actions = el('div', 'pactions');
|
|
3903
|
+
actions.appendChild(button(s.enabled ? 'deshabilitar' : 'habilitar', (event) => { event.stopPropagation(); toggleSkill(s.id); }));
|
|
3904
|
+
actions.appendChild(button('editar', (event) => { event.stopPropagation(); openSkillForm(s.id); }));
|
|
3905
|
+
if (s.removable) actions.appendChild(button('borrar', (event) => { event.stopPropagation(); removeSkill(s.id); }, 'btn danger'));
|
|
3906
|
+
li.appendChild(actions);
|
|
3901
3907
|
li.addEventListener('click', () => openSkillForm(s.id));
|
|
3902
3908
|
skillListEl.appendChild(li);
|
|
3903
3909
|
}
|
|
@@ -5173,9 +5179,11 @@ async function refreshProcs() {
|
|
|
5173
5179
|
el('div', 'pmeta', `${proc.status}${proc.port ? ` · puerto ${proc.port}` : ''}`)
|
|
5174
5180
|
);
|
|
5175
5181
|
li.appendChild(main);
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
if (proc.
|
|
5182
|
+
const actions = el('div', 'pactions');
|
|
5183
|
+
actions.appendChild(button('logs', () => { selectedProc = proc.id; refreshProcLog(); }));
|
|
5184
|
+
if (proc.port) actions.appendChild(button('preview', () => { setExplorerMode('preview'); loadPreview(`http://127.0.0.1:${proc.port}`); }));
|
|
5185
|
+
if (proc.running) actions.appendChild(button('detener', () => stopProc(proc.id), 'btn danger'));
|
|
5186
|
+
li.appendChild(actions);
|
|
5179
5187
|
procsListEl.appendChild(li);
|
|
5180
5188
|
}
|
|
5181
5189
|
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
</head>
|
|
38
38
|
<body>
|
|
39
39
|
<header class="topbar">
|
|
40
|
-
<div class="brand"><span class="logo"><img src="/icons/logo.png" alt="Tamnora" /></span> <span class="ver">v0.11.
|
|
40
|
+
<div class="brand"><span class="logo"><img src="/icons/logo.png" alt="Tamnora" /></span> <span class="ver">v0.11.2</span></div>
|
|
41
41
|
<nav class="tabs">
|
|
42
42
|
<button class="tab active" data-tab="chat">chat</button>
|
|
43
43
|
<button class="tab" data-tab="providers">proveedores</button>
|
|
@@ -1220,6 +1220,16 @@ pre.code code { background: none; border: 0; padding: 0; font-size: 0.92em; }
|
|
|
1220
1220
|
.providers .pid { font-weight: 700; }
|
|
1221
1221
|
.providers .pmeta { color: var(--muted); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1222
1222
|
.providers .grow { flex: 1; min-width: 0; }
|
|
1223
|
+
.providers .pactions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
|
|
1224
|
+
.providers li.muted {
|
|
1225
|
+
border: 0;
|
|
1226
|
+
background: none;
|
|
1227
|
+
backdrop-filter: none;
|
|
1228
|
+
box-shadow: none;
|
|
1229
|
+
cursor: default;
|
|
1230
|
+
padding-left: 2px;
|
|
1231
|
+
}
|
|
1232
|
+
.providers li.muted:hover { border: 0; }
|
|
1223
1233
|
|
|
1224
1234
|
.summary { color: var(--muted); }
|
|
1225
1235
|
.summary.ok { color: var(--ok); }
|
|
@@ -1598,17 +1608,38 @@ dialog.file-modal.preview-maximized {
|
|
|
1598
1608
|
}
|
|
1599
1609
|
.composer {
|
|
1600
1610
|
margin: 8px 10px 6px;
|
|
1601
|
-
padding:
|
|
1611
|
+
padding: 9px 10px;
|
|
1602
1612
|
border-radius: 18px;
|
|
1603
1613
|
}
|
|
1614
|
+
/* En un movil el input flotaba sin fondo y casi no se notaba: lo sacamos a su
|
|
1615
|
+
propia linea, con campo visible y 16px (evita el zoom de iOS al enfocar). */
|
|
1616
|
+
.composer-row {
|
|
1617
|
+
flex-wrap: wrap;
|
|
1618
|
+
align-items: center;
|
|
1619
|
+
gap: 8px;
|
|
1620
|
+
}
|
|
1604
1621
|
.composer textarea {
|
|
1622
|
+
order: -1;
|
|
1623
|
+
flex: 1 0 100%;
|
|
1605
1624
|
max-height: 40vh;
|
|
1625
|
+
min-height: 46px;
|
|
1626
|
+
padding: 11px 13px;
|
|
1627
|
+
border: 1px solid var(--border);
|
|
1628
|
+
border-radius: 14px;
|
|
1629
|
+
background: var(--bg);
|
|
1630
|
+
font-size: 16px;
|
|
1631
|
+
line-height: 1.45;
|
|
1632
|
+
}
|
|
1633
|
+
.composer textarea:focus {
|
|
1634
|
+
border: 1px solid var(--accent);
|
|
1635
|
+
box-shadow: 0 0 0 4px var(--accent-soft);
|
|
1606
1636
|
}
|
|
1607
1637
|
.ctrl-pill {
|
|
1608
1638
|
max-width: 46vw;
|
|
1609
1639
|
}
|
|
1610
1640
|
.model-pill {
|
|
1611
|
-
max-width:
|
|
1641
|
+
max-width: 46vw;
|
|
1642
|
+
margin-left: auto;
|
|
1612
1643
|
}
|
|
1613
1644
|
.composer-status {
|
|
1614
1645
|
flex-wrap: wrap;
|
|
@@ -1617,6 +1648,26 @@ dialog.file-modal.preview-maximized {
|
|
|
1617
1648
|
.composer-status .spacer {
|
|
1618
1649
|
display: none;
|
|
1619
1650
|
}
|
|
1651
|
+
/* MCP / skills / proveedores / procesos: el titulo se apretaba contra los
|
|
1652
|
+
botones y la descripcion quedaba cortada. Pasamos las acciones a su propia
|
|
1653
|
+
linea y dejamos que el texto respire. */
|
|
1654
|
+
.providers li {
|
|
1655
|
+
flex-wrap: wrap;
|
|
1656
|
+
align-items: flex-start;
|
|
1657
|
+
gap: 8px 10px;
|
|
1658
|
+
padding: 11px 12px;
|
|
1659
|
+
}
|
|
1660
|
+
.providers .pactions {
|
|
1661
|
+
flex: 0 0 100%;
|
|
1662
|
+
justify-content: flex-end;
|
|
1663
|
+
}
|
|
1664
|
+
.providers .grow .pmeta {
|
|
1665
|
+
white-space: normal;
|
|
1666
|
+
overflow: hidden;
|
|
1667
|
+
display: -webkit-box;
|
|
1668
|
+
-webkit-line-clamp: 2;
|
|
1669
|
+
-webkit-box-orient: vertical;
|
|
1670
|
+
}
|
|
1620
1671
|
.empty-brand {
|
|
1621
1672
|
font-size: clamp(30px, 12vw, 46px);
|
|
1622
1673
|
}
|
package/package.json
CHANGED