@danieltmn/tamnora 0.20.1 → 0.21.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.
@@ -0,0 +1,106 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ THEMES,
5
+ FONT_PRESETS,
6
+ DEFAULTS,
7
+ resolveTheme,
8
+ resolveFont,
9
+ nextTheme,
10
+ clampChatFont,
11
+ clampScale,
12
+ normalizeAppearance,
13
+ } from '../public/appearance.js';
14
+ import {
15
+ resolveThemeId,
16
+ resolveFontId,
17
+ resolveAppearance,
18
+ sanitizeAppearance,
19
+ DEFAULT_APPEARANCE,
20
+ } from '../src/lib/appearance.js';
21
+
22
+ test('los registros de tema y fuente son consistentes', () => {
23
+ const themeIds = THEMES.map((t) => t.id);
24
+ assert.equal(new Set(themeIds).size, themeIds.length, 'ids de tema únicos');
25
+ for (const theme of THEMES) {
26
+ assert.ok(['light', 'dark'].includes(theme.scheme), `scheme válido en ${theme.id}`);
27
+ assert.match(theme.metaColor, /^#[0-9a-f]{6}$/i, `metaColor de ${theme.id}`);
28
+ }
29
+ const fontIds = FONT_PRESETS.map((f) => f.id);
30
+ assert.equal(new Set(fontIds).size, fontIds.length, 'ids de fuente únicos');
31
+ assert.ok(fontIds.includes('sistema'));
32
+ const sistema = FONT_PRESETS.find((f) => f.id === 'sistema');
33
+ assert.equal(sistema.google, null, 'sistema no usa webfont');
34
+ });
35
+
36
+ test('resolveTheme mapea legacy light -> paper y cae al default', () => {
37
+ assert.equal(resolveTheme('light'), 'paper');
38
+ assert.equal(resolveTheme('nord'), 'nord');
39
+ assert.equal(resolveTheme('no-existe'), DEFAULTS.theme);
40
+ assert.equal(resolveFont('plex'), 'plex');
41
+ assert.equal(resolveFont('no-existe'), DEFAULTS.font);
42
+ });
43
+
44
+ test('nextTheme recorre todos los temas y vuelve al inicio', () => {
45
+ let id = THEMES[0].id;
46
+ const seen = new Set([id]);
47
+ for (let i = 1; i < THEMES.length; i += 1) {
48
+ id = nextTheme(id);
49
+ seen.add(id);
50
+ }
51
+ assert.equal(seen.size, THEMES.length);
52
+ assert.equal(nextTheme(id), THEMES[0].id);
53
+ });
54
+
55
+ test('normalizeAppearance acota tamaños y resuelve ids', () => {
56
+ const a = normalizeAppearance({ theme: 'dracula', font: 'inter', chatFont: 99, scale: 5 });
57
+ assert.equal(a.theme, 'dracula');
58
+ assert.equal(a.font, 'inter');
59
+ assert.equal(a.chatFont, 20);
60
+ assert.equal(a.scale, 1.3);
61
+ const b = normalizeAppearance({ theme: 'nope', chatFont: 1, scale: 0.1 });
62
+ assert.equal(b.theme, 'paper');
63
+ assert.equal(b.chatFont, 12);
64
+ assert.equal(b.scale, 0.8);
65
+ assert.equal(clampChatFont(14.3), 14.5);
66
+ assert.equal(clampScale(undefined), 1);
67
+ });
68
+
69
+ test('la validacion del server coincide con el registro del cliente', () => {
70
+ assert.deepEqual(
71
+ THEMES.map((t) => t.id).sort(),
72
+ [
73
+ 'paper',
74
+ 'dark',
75
+ 'midnight',
76
+ 'nord',
77
+ 'dracula',
78
+ 'solarized',
79
+ 'solarized-dark',
80
+ 'bosque',
81
+ 'vino',
82
+ 'vercel',
83
+ 'dark-plus',
84
+ 'github',
85
+ 'github-dark',
86
+ ].sort()
87
+ );
88
+ assert.equal(resolveThemeId('solarized-dark'), 'solarized-dark');
89
+ assert.equal(resolveThemeId('vercel'), 'vercel');
90
+ assert.equal(resolveThemeId('github-dark'), 'github-dark');
91
+ assert.equal(resolveThemeId('light'), 'paper');
92
+ assert.equal(resolveThemeId('bogus'), 'paper');
93
+ assert.equal(resolveFontId('sistema'), 'sistema');
94
+ assert.equal(resolveFontId('jetbrains'), 'jetbrains');
95
+ assert.equal(resolveFontId('bogus'), 'clasico');
96
+ });
97
+
98
+ test('resolveAppearance y sanitizeAppearance normalizan app.json', () => {
99
+ assert.deepEqual(resolveAppearance({}), DEFAULT_APPEARANCE);
100
+ const saved = resolveAppearance({ appearance: { theme: 'nord', font: 'plex', chatFont: 18, scale: 1.1 } });
101
+ assert.deepEqual(saved, { theme: 'nord', font: 'plex', chatFont: 18, scale: 1.1 });
102
+ const merged = sanitizeAppearance({ theme: 'vino' }, saved);
103
+ assert.deepEqual(merged, { theme: 'vino', font: 'plex', chatFont: 18, scale: 1.1 });
104
+ const clamped = sanitizeAppearance({ theme: 'x', font: 'y', chatFont: -5, scale: 9 });
105
+ assert.deepEqual(clamped, { theme: 'paper', font: 'clasico', chatFont: 12, scale: 1.3 });
106
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danieltmn/tamnora",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "description": "Harness local para IAs: agente CLI-first con TUI, consola web y evaluacion. Node puro, sin dependencias.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.25.0",