@getparallel/parx 0.0.0-stage → 0.4.1
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 +32 -0
- package/LICENSE +12 -0
- package/README.md +138 -2
- package/dist/actualizar.js +112 -0
- package/dist/agente.js +231 -0
- package/dist/api.js +95 -0
- package/dist/carriles.js +44 -0
- package/dist/cli.js +700 -0
- package/dist/config.js +112 -0
- package/dist/consejos.js +54 -0
- package/dist/cuenta.js +261 -0
- package/dist/diff.js +80 -0
- package/dist/herramientas.js +498 -0
- package/dist/imagenes.js +94 -0
- package/dist/informe.js +65 -0
- package/dist/marca.js +200 -0
- package/dist/mision.js +16 -0
- package/dist/modelos.js +28 -0
- package/dist/notificar.js +112 -0
- package/dist/qr.js +272 -0
- package/dist/registro.js +24 -0
- package/dist/seguridad.js +164 -0
- package/dist/shell.js +108 -0
- package/dist/texto.js +165 -0
- package/dist/textos.js +273 -0
- package/dist/tui.js +1198 -0
- package/dist/ui.js +287 -0
- package/package.json +60 -4
package/dist/marca.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { usarPuntosAscii } from "./texto.js";
|
|
2
|
+
export function detectarCapacidades(env = process.env, salida = process.stdout, plataforma = process.platform) {
|
|
3
|
+
const ancho = salida.columns && salida.columns > 20 ? salida.columns : 80;
|
|
4
|
+
let color = 0;
|
|
5
|
+
if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== '0') {
|
|
6
|
+
color = env.FORCE_COLOR === '1' ? 2 : 3;
|
|
7
|
+
}
|
|
8
|
+
else if (env.NO_COLOR === undefined && salida.isTTY && env.TERM !== 'dumb') {
|
|
9
|
+
const term = env.TERM ?? '';
|
|
10
|
+
if (env.COLORTERM === 'truecolor' || env.COLORTERM === '24bit' || env.WT_SESSION || env.TERM_PROGRAM === 'iTerm.app' || env.TERM_PROGRAM === 'vscode' || env.TERM_PROGRAM === 'Apple_Terminal' || plataforma === 'win32') {
|
|
11
|
+
color = 3;
|
|
12
|
+
}
|
|
13
|
+
else if (/256/.test(term)) {
|
|
14
|
+
color = 2;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
color = 1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const unicode = env.PARALLEL_ASCII ? false : plataforma !== 'win32' || Boolean(env.WT_SESSION) || env.TERM_PROGRAM === 'vscode' || Boolean(env.TERM);
|
|
21
|
+
return { color, unicode, ancho };
|
|
22
|
+
}
|
|
23
|
+
let caps = detectarCapacidades();
|
|
24
|
+
usarPuntosAscii(!caps.unicode);
|
|
25
|
+
export function capacidades() {
|
|
26
|
+
return caps;
|
|
27
|
+
}
|
|
28
|
+
export function fijarCapacidades(c) {
|
|
29
|
+
caps = { ...caps, ...c };
|
|
30
|
+
usarPuntosAscii(!caps.unicode);
|
|
31
|
+
}
|
|
32
|
+
const PALETA = {
|
|
33
|
+
violeta: [109, 74, 255],
|
|
34
|
+
violetaClaro: [139, 112, 255],
|
|
35
|
+
violetaTexto: [174, 155, 255],
|
|
36
|
+
gris: [165, 159, 186],
|
|
37
|
+
ok: [139, 112, 255],
|
|
38
|
+
aviso: [245, 166, 35],
|
|
39
|
+
error: [240, 82, 82],
|
|
40
|
+
verdeDiff: [80, 200, 120],
|
|
41
|
+
rojoDiff: [240, 100, 100],
|
|
42
|
+
peligro: [255, 69, 58],
|
|
43
|
+
};
|
|
44
|
+
const ANSI256 = {
|
|
45
|
+
violeta: 99,
|
|
46
|
+
violetaClaro: 141,
|
|
47
|
+
violetaTexto: 147,
|
|
48
|
+
gris: 146,
|
|
49
|
+
ok: 141,
|
|
50
|
+
aviso: 214,
|
|
51
|
+
error: 203,
|
|
52
|
+
verdeDiff: 78,
|
|
53
|
+
rojoDiff: 203,
|
|
54
|
+
peligro: 196,
|
|
55
|
+
};
|
|
56
|
+
const ANSI16 = {
|
|
57
|
+
violeta: 35,
|
|
58
|
+
violetaClaro: 95,
|
|
59
|
+
violetaTexto: 95,
|
|
60
|
+
gris: 90,
|
|
61
|
+
ok: 95,
|
|
62
|
+
aviso: 33,
|
|
63
|
+
error: 31,
|
|
64
|
+
verdeDiff: 32,
|
|
65
|
+
rojoDiff: 31,
|
|
66
|
+
peligro: 91,
|
|
67
|
+
};
|
|
68
|
+
function pintar(nombre, texto) {
|
|
69
|
+
const { color } = caps;
|
|
70
|
+
if (color === 0)
|
|
71
|
+
return texto;
|
|
72
|
+
if (color === 3) {
|
|
73
|
+
const [r, g, b] = PALETA[nombre];
|
|
74
|
+
return `\x1b[38;2;${r};${g};${b}m${texto}\x1b[39m`;
|
|
75
|
+
}
|
|
76
|
+
if (color === 2)
|
|
77
|
+
return `\x1b[38;5;${ANSI256[nombre]}m${texto}\x1b[39m`;
|
|
78
|
+
return `\x1b[${ANSI16[nombre]}m${texto}\x1b[39m`;
|
|
79
|
+
}
|
|
80
|
+
export const c = {
|
|
81
|
+
violeta: (t) => pintar('violeta', t),
|
|
82
|
+
claro: (t) => pintar('violetaClaro', t),
|
|
83
|
+
marca: (t) => pintar('violetaTexto', t),
|
|
84
|
+
gris: (t) => pintar('gris', t),
|
|
85
|
+
ok: (t) => pintar('ok', t),
|
|
86
|
+
aviso: (t) => pintar('aviso', t),
|
|
87
|
+
error: (t) => pintar('error', t),
|
|
88
|
+
mas: (t) => pintar('verdeDiff', t),
|
|
89
|
+
menos: (t) => pintar('rojoDiff', t),
|
|
90
|
+
peligro: (t) => pintar('peligro', t),
|
|
91
|
+
negrita: (t) => (caps.color ? `\x1b[1m${t}\x1b[22m` : t),
|
|
92
|
+
tenue: (t) => (caps.color ? `\x1b[2m${t}\x1b[22m` : t),
|
|
93
|
+
};
|
|
94
|
+
export { sinColor } from "./texto.js";
|
|
95
|
+
export function logo() {
|
|
96
|
+
const filas = caps.unicode
|
|
97
|
+
? [' ▄█▀ ▄█▀', ' ▄█▀ ▄█▀ ', ' ▄█▀ ▄█▀ ', ' ▄█▀ ▄█▀ ']
|
|
98
|
+
: [' // // ', ' // // ', ' // // ', ' // // '];
|
|
99
|
+
const tonos = [c.marca, c.claro, c.claro, c.violeta];
|
|
100
|
+
return filas.map((f, i) => tonos[i](f));
|
|
101
|
+
}
|
|
102
|
+
export const ANCHO_DE_PAR = 6;
|
|
103
|
+
export function cabezaDePar() {
|
|
104
|
+
return caps.unicode ? c.claro('▗▄▄▄▄▖') : c.claro(' .--. ');
|
|
105
|
+
}
|
|
106
|
+
export function caraDePar(gesto = 'quieto') {
|
|
107
|
+
const u = caps.unicode;
|
|
108
|
+
const ojos = gesto === 'parpadeo'
|
|
109
|
+
? u ? ' ── ' : ' -- '
|
|
110
|
+
: gesto === 'pregunta'
|
|
111
|
+
? u ? ' •• ' : ' oo '
|
|
112
|
+
: gesto === 'error'
|
|
113
|
+
? u ? ' ×× ' : ' xx '
|
|
114
|
+
: typeof gesto === 'number'
|
|
115
|
+
?
|
|
116
|
+
(u ? ['╱╱ ', ' ╱╱ ', ' ╱╱', ' ╱╱ '] : ['// ', ' // ', ' //', ' // '])[gesto]
|
|
117
|
+
: u ? ' ╱╱ ' : ' // ';
|
|
118
|
+
if (caps.color) {
|
|
119
|
+
const fondo = caps.color === 3 ? '\x1b[48;2;139;112;255m' : caps.color === 2 ? '\x1b[48;5;141m' : '\x1b[45m';
|
|
120
|
+
return `${fondo}\x1b[1;97m ${ojos} \x1b[22;39;49m`;
|
|
121
|
+
}
|
|
122
|
+
return u ? `▐${ojos}▌` : `[${ojos}]`;
|
|
123
|
+
}
|
|
124
|
+
export const ANCHO_DE_ANIMACION = 8;
|
|
125
|
+
export function animacion(tipo, paso) {
|
|
126
|
+
const u = caps.unicode;
|
|
127
|
+
const L = ANCHO_DE_ANIMACION;
|
|
128
|
+
const p = Math.max(0, Math.floor(paso));
|
|
129
|
+
const tenue = (x) => c.tenue(c.gris(x));
|
|
130
|
+
switch (tipo) {
|
|
131
|
+
case 'ruta': {
|
|
132
|
+
const pos = Math.min(L - 1, p % 12);
|
|
133
|
+
return `${c.violeta((u ? '━' : '=').repeat(pos))}${c.claro(u ? '●' : 'o')}${tenue((u ? '┄' : '-').repeat(L - 1 - pos))}`;
|
|
134
|
+
}
|
|
135
|
+
case 'tren': {
|
|
136
|
+
const cabeza = p % (L + 3);
|
|
137
|
+
let out = '';
|
|
138
|
+
for (let i = 0; i < L; i++) {
|
|
139
|
+
if (i === cabeza)
|
|
140
|
+
out += c.claro(u ? '▸' : '>');
|
|
141
|
+
else if (i === cabeza - 1 || i === cabeza - 2)
|
|
142
|
+
out += c.violeta(u ? '▰' : '=');
|
|
143
|
+
else
|
|
144
|
+
out += tenue(u ? '─' : '-');
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
case 'lectura': {
|
|
149
|
+
const ciclo = (L - 1) * 2;
|
|
150
|
+
const q = p % ciclo;
|
|
151
|
+
const pos = q < L ? q : ciclo - q;
|
|
152
|
+
let out = '';
|
|
153
|
+
for (let i = 0; i < L; i++) {
|
|
154
|
+
if (i === pos)
|
|
155
|
+
out += c.claro(u ? '╪' : '#');
|
|
156
|
+
else if (Math.abs(i - pos) === 1)
|
|
157
|
+
out += c.violeta(u ? '═' : '=');
|
|
158
|
+
else
|
|
159
|
+
out += tenue(u ? '═' : '=');
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
case 'tendido': {
|
|
164
|
+
const n = Math.min(L, p % 12);
|
|
165
|
+
let out = '';
|
|
166
|
+
for (let i = 0; i < L; i++)
|
|
167
|
+
out += i < n ? c.violeta(i % 2 === 0 ? (u ? '╪' : '+') : u ? '═' : '=') : tenue(u ? '·' : '.');
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export function signo() {
|
|
173
|
+
return caps.unicode ? '╱╱' : '//';
|
|
174
|
+
}
|
|
175
|
+
export function carril(ancho) {
|
|
176
|
+
return (caps.unicode ? '═' : '=').repeat(Math.max(0, ancho));
|
|
177
|
+
}
|
|
178
|
+
export function sep() {
|
|
179
|
+
return caps.unicode ? ' · ' : ' - ';
|
|
180
|
+
}
|
|
181
|
+
export const SIMBOLOS = {
|
|
182
|
+
get punto() {
|
|
183
|
+
return caps.unicode ? '●' : '*';
|
|
184
|
+
},
|
|
185
|
+
get hecho() {
|
|
186
|
+
return caps.unicode ? '✓' : 'v';
|
|
187
|
+
},
|
|
188
|
+
get falla() {
|
|
189
|
+
return caps.unicode ? '✗' : 'x';
|
|
190
|
+
},
|
|
191
|
+
get flecha() {
|
|
192
|
+
return caps.unicode ? '›' : '>';
|
|
193
|
+
},
|
|
194
|
+
get raya() {
|
|
195
|
+
return caps.unicode ? '─' : '-';
|
|
196
|
+
},
|
|
197
|
+
get candado() {
|
|
198
|
+
return caps.unicode ? '⏺' : '!';
|
|
199
|
+
},
|
|
200
|
+
};
|
package/dist/mision.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const MAX_OBJETIVO = 600;
|
|
2
|
+
export function objetivoDeMision(meta, diario) {
|
|
3
|
+
const ultima = [...diario].reverse().find((d) => d.pedido.trim());
|
|
4
|
+
const que = (meta.trim() || ultima?.pedido.trim() || '').replace(/\s+/g, ' ');
|
|
5
|
+
if (que.length < 4)
|
|
6
|
+
return null;
|
|
7
|
+
const ficheros = [...new Set(diario.flatMap((d) => d.ficheros))].slice(0, 6);
|
|
8
|
+
const contexto = ultima
|
|
9
|
+
? ` Context from the terminal (parx): ${ficheros.length ? `changed ${ficheros.join(', ')}. ` : ''}${ultima.respuesta ? `Last result: ${ultima.respuesta.replace(/\s+/g, ' ')}` : ''}`
|
|
10
|
+
: '';
|
|
11
|
+
const base = que.length > MAX_OBJETIVO ? `${que.slice(0, MAX_OBJETIVO - 1)}…` : que;
|
|
12
|
+
const sitio = MAX_OBJETIVO - base.length;
|
|
13
|
+
if (!contexto.trim() || sitio < 40)
|
|
14
|
+
return base;
|
|
15
|
+
return `${base}${contexto.length > sitio ? `${contexto.slice(0, sitio - 1)}…` : contexto}`;
|
|
16
|
+
}
|
package/dist/modelos.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const MODELOS = {
|
|
2
|
+
swift: { id: 'swift', nombre: 'Swift', version: '1.0', servidor: 'rapido', descripcion: 'Fast, for simple things. Spends less.' },
|
|
3
|
+
stride: { id: 'stride', nombre: 'Stride', version: '1.0', servidor: 'potente', descripcion: 'The balance. The default.' },
|
|
4
|
+
summit: { id: 'summit', nombre: 'Summit', version: '1.0', servidor: 'maximo', descripcion: 'Most capable, for the hardest work. Spends more.' },
|
|
5
|
+
};
|
|
6
|
+
export const ORDEN_DE_MODELOS = ['swift', 'stride', 'summit'];
|
|
7
|
+
export const MODELO_POR_DEFECTO = 'stride';
|
|
8
|
+
export function nombreDeModelo(m) {
|
|
9
|
+
const f = MODELOS[m];
|
|
10
|
+
return `${f.nombre} ${f.version}`;
|
|
11
|
+
}
|
|
12
|
+
export function modeloDe(texto) {
|
|
13
|
+
const v = (texto ?? '').trim().toLowerCase().replace(/\s*\d+(\.\d+)?$/, '');
|
|
14
|
+
const tabla = {
|
|
15
|
+
swift: 'swift',
|
|
16
|
+
fast: 'swift',
|
|
17
|
+
rapido: 'swift',
|
|
18
|
+
'rápido': 'swift',
|
|
19
|
+
stride: 'stride',
|
|
20
|
+
powerful: 'stride',
|
|
21
|
+
potente: 'stride',
|
|
22
|
+
summit: 'summit',
|
|
23
|
+
max: 'summit',
|
|
24
|
+
maximo: 'summit',
|
|
25
|
+
'máximo': 'summit',
|
|
26
|
+
};
|
|
27
|
+
return tabla[v] ?? null;
|
|
28
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { carpetaDeConfiguracion } from "./config.js";
|
|
5
|
+
export const TAREA_LARGA_MS = 45_000;
|
|
6
|
+
export function debeAvisar(enfocada, ms) {
|
|
7
|
+
if (enfocada === false)
|
|
8
|
+
return true;
|
|
9
|
+
if (enfocada === null)
|
|
10
|
+
return ms >= TAREA_LARGA_MS;
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
export function sonidoDeParallel() {
|
|
14
|
+
const hz = 44_100;
|
|
15
|
+
const dur = 0.62;
|
|
16
|
+
const n = Math.floor(hz * dur);
|
|
17
|
+
const datos = Buffer.alloc(n * 2);
|
|
18
|
+
const notas = [
|
|
19
|
+
[659.25, 0],
|
|
20
|
+
[987.77, 0.09],
|
|
21
|
+
];
|
|
22
|
+
for (let i = 0; i < n; i++) {
|
|
23
|
+
const t = i / hz;
|
|
24
|
+
let v = 0;
|
|
25
|
+
for (const [f, desde] of notas) {
|
|
26
|
+
if (t < desde)
|
|
27
|
+
continue;
|
|
28
|
+
const x = t - desde;
|
|
29
|
+
const entrada = Math.min(1, x / 0.012);
|
|
30
|
+
const caida = Math.exp(-x * 6.5);
|
|
31
|
+
v += Math.sin(2 * Math.PI * f * x) * entrada * caida * 0.28 + Math.sin(4 * Math.PI * f * x) * entrada * caida * 0.04;
|
|
32
|
+
}
|
|
33
|
+
datos.writeInt16LE(Math.max(-32767, Math.min(32767, Math.round(v * 32767))), i * 2);
|
|
34
|
+
}
|
|
35
|
+
const cab = Buffer.alloc(44);
|
|
36
|
+
cab.write('RIFF', 0);
|
|
37
|
+
cab.writeUInt32LE(36 + datos.length, 4);
|
|
38
|
+
cab.write('WAVE', 8);
|
|
39
|
+
cab.write('fmt ', 12);
|
|
40
|
+
cab.writeUInt32LE(16, 16);
|
|
41
|
+
cab.writeUInt16LE(1, 20);
|
|
42
|
+
cab.writeUInt16LE(1, 22);
|
|
43
|
+
cab.writeUInt32LE(hz, 24);
|
|
44
|
+
cab.writeUInt32LE(hz * 2, 28);
|
|
45
|
+
cab.writeUInt16LE(2, 32);
|
|
46
|
+
cab.writeUInt16LE(16, 34);
|
|
47
|
+
cab.write('data', 36);
|
|
48
|
+
cab.writeUInt32LE(datos.length, 40);
|
|
49
|
+
return Buffer.concat([cab, datos]);
|
|
50
|
+
}
|
|
51
|
+
export function rutaDelSonido(dir = carpetaDeConfiguracion()) {
|
|
52
|
+
const ruta = join(dir, 'par.wav');
|
|
53
|
+
try {
|
|
54
|
+
if (!existsSync(ruta)) {
|
|
55
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
56
|
+
writeFileSync(ruta, sonidoDeParallel(), { mode: 0o600 });
|
|
57
|
+
}
|
|
58
|
+
return ruta;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function existe(programa) {
|
|
65
|
+
return spawnSync(process.platform === 'win32' ? 'where' : 'which', [programa], { stdio: 'ignore' }).status === 0;
|
|
66
|
+
}
|
|
67
|
+
function lanzar(programa, args, env) {
|
|
68
|
+
try {
|
|
69
|
+
const h = spawn(programa, args, { stdio: 'ignore', detached: true, windowsHide: true, env: env ? { ...process.env, ...env } : process.env });
|
|
70
|
+
h.on('error', () => { });
|
|
71
|
+
h.unref();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function ordenesDeAviso(a, plataforma, sonido, hay = existe) {
|
|
77
|
+
const texto = a.texto.replace(/\s+/g, ' ').slice(0, 180);
|
|
78
|
+
if (plataforma === 'darwin') {
|
|
79
|
+
const out = [{ programa: 'osascript', args: ['-e', 'on run argv', '-e', 'display notification (item 2 of argv) with title (item 1 of argv)', '-e', 'end run', a.titulo, texto] }];
|
|
80
|
+
if (sonido)
|
|
81
|
+
out.push({ programa: 'afplay', args: [sonido] });
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
if (plataforma === 'win32') {
|
|
85
|
+
const ps = [
|
|
86
|
+
'[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null',
|
|
87
|
+
'$x = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)',
|
|
88
|
+
'$x.GetElementsByTagName("text")[0].AppendChild($x.CreateTextNode($env:PARX_AVISO_TITULO)) > $null',
|
|
89
|
+
'$x.GetElementsByTagName("text")[1].AppendChild($x.CreateTextNode($env:PARX_AVISO_TEXTO)) > $null',
|
|
90
|
+
'$a = "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe"',
|
|
91
|
+
'[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($a).Show([Windows.UI.Notifications.ToastNotification]::new($x))',
|
|
92
|
+
'if ($env:PARX_AVISO_SONIDO) { (New-Object Media.SoundPlayer $env:PARX_AVISO_SONIDO).PlaySync() }',
|
|
93
|
+
].join('; ');
|
|
94
|
+
return [{ programa: 'powershell.exe', args: ['-NoProfile', '-NonInteractive', '-WindowStyle', 'Hidden', '-Command', ps], env: { PARX_AVISO_TITULO: a.titulo, PARX_AVISO_TEXTO: texto, PARX_AVISO_SONIDO: sonido ?? '' } }];
|
|
95
|
+
}
|
|
96
|
+
const out = [];
|
|
97
|
+
if (hay('notify-send'))
|
|
98
|
+
out.push({ programa: 'notify-send', args: ['--app-name=parx', a.titulo, texto] });
|
|
99
|
+
if (sonido) {
|
|
100
|
+
if (hay('paplay'))
|
|
101
|
+
out.push({ programa: 'paplay', args: [sonido] });
|
|
102
|
+
else if (hay('aplay'))
|
|
103
|
+
out.push({ programa: 'aplay', args: ['-q', sonido] });
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
export function avisarEnElEscritorio(a) {
|
|
108
|
+
if (process.env.PARX_NO_NOTIFY || process.env.CI)
|
|
109
|
+
return;
|
|
110
|
+
for (const o of ordenesDeAviso(a, process.platform, rutaDelSonido()))
|
|
111
|
+
lanzar(o.programa, o.args, o.env);
|
|
112
|
+
}
|
package/dist/qr.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
const ECC_POR_BLOQUE_M = [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26];
|
|
2
|
+
const BLOQUES_M = [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5];
|
|
3
|
+
const BITS_DE_FORMATO_M = 0;
|
|
4
|
+
function modulosDeDatos(ver) {
|
|
5
|
+
let r = (16 * ver + 128) * ver + 64;
|
|
6
|
+
if (ver >= 2) {
|
|
7
|
+
const n = Math.floor(ver / 7) + 2;
|
|
8
|
+
r -= (25 * n - 10) * n - 55;
|
|
9
|
+
if (ver >= 7)
|
|
10
|
+
r -= 36;
|
|
11
|
+
}
|
|
12
|
+
return r;
|
|
13
|
+
}
|
|
14
|
+
function palabrasDeDatos(ver) {
|
|
15
|
+
return Math.floor(modulosDeDatos(ver) / 8) - ECC_POR_BLOQUE_M[ver] * BLOQUES_M[ver];
|
|
16
|
+
}
|
|
17
|
+
function mul(x, y) {
|
|
18
|
+
let z = 0;
|
|
19
|
+
for (let i = 7; i >= 0; i--) {
|
|
20
|
+
z = (z << 1) ^ ((z >>> 7) * 0x11d);
|
|
21
|
+
z ^= ((y >>> i) & 1) * x;
|
|
22
|
+
}
|
|
23
|
+
return z & 0xff;
|
|
24
|
+
}
|
|
25
|
+
function divisor(grado) {
|
|
26
|
+
const r = new Array(grado).fill(0);
|
|
27
|
+
r[grado - 1] = 1;
|
|
28
|
+
let raiz = 1;
|
|
29
|
+
for (let i = 0; i < grado; i++) {
|
|
30
|
+
for (let j = 0; j < r.length; j++) {
|
|
31
|
+
r[j] = mul(r[j], raiz);
|
|
32
|
+
if (j + 1 < r.length)
|
|
33
|
+
r[j] ^= r[j + 1];
|
|
34
|
+
}
|
|
35
|
+
raiz = mul(raiz, 0x02);
|
|
36
|
+
}
|
|
37
|
+
return r;
|
|
38
|
+
}
|
|
39
|
+
function resto(datos, div) {
|
|
40
|
+
const r = div.map(() => 0);
|
|
41
|
+
for (const b of datos) {
|
|
42
|
+
const f = b ^ r.shift();
|
|
43
|
+
r.push(0);
|
|
44
|
+
div.forEach((c, i) => (r[i] ^= mul(c, f)));
|
|
45
|
+
}
|
|
46
|
+
return r;
|
|
47
|
+
}
|
|
48
|
+
function posicionesDeAlineacion(ver) {
|
|
49
|
+
if (ver === 1)
|
|
50
|
+
return [];
|
|
51
|
+
const n = Math.floor(ver / 7) + 2;
|
|
52
|
+
const paso = Math.ceil((ver * 4 + 4) / (n * 2 - 2)) * 2;
|
|
53
|
+
const r = [6];
|
|
54
|
+
for (let pos = ver * 4 + 17 - 7; r.length < n; pos -= paso)
|
|
55
|
+
r.splice(1, 0, pos);
|
|
56
|
+
return r;
|
|
57
|
+
}
|
|
58
|
+
export function matrizQR(texto) {
|
|
59
|
+
const bytes = [...Buffer.from(texto, 'utf8')];
|
|
60
|
+
let ver = 1;
|
|
61
|
+
for (; ver <= 10; ver++) {
|
|
62
|
+
const bitsCuenta = ver < 10 ? 8 : 16;
|
|
63
|
+
if (4 + bitsCuenta + bytes.length * 8 <= palabrasDeDatos(ver) * 8)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
if (ver > 10)
|
|
67
|
+
throw new Error('QR: text too long');
|
|
68
|
+
const capacidad = palabrasDeDatos(ver) * 8;
|
|
69
|
+
const bits = [];
|
|
70
|
+
const poner = (v, n) => {
|
|
71
|
+
for (let i = n - 1; i >= 0; i--)
|
|
72
|
+
bits.push((v >>> i) & 1);
|
|
73
|
+
};
|
|
74
|
+
poner(0b0100, 4);
|
|
75
|
+
poner(bytes.length, ver < 10 ? 8 : 16);
|
|
76
|
+
for (const b of bytes)
|
|
77
|
+
poner(b, 8);
|
|
78
|
+
poner(0, Math.min(4, capacidad - bits.length));
|
|
79
|
+
poner(0, (8 - (bits.length % 8)) % 8);
|
|
80
|
+
for (let p = 0xec; bits.length < capacidad; p ^= 0xec ^ 0x11)
|
|
81
|
+
poner(p, 8);
|
|
82
|
+
const datos = [];
|
|
83
|
+
for (let i = 0; i < bits.length; i += 8)
|
|
84
|
+
datos.push(bits.slice(i, i + 8).reduce((a, b) => (a << 1) | b, 0));
|
|
85
|
+
const nBloques = BLOQUES_M[ver];
|
|
86
|
+
const eccLen = ECC_POR_BLOQUE_M[ver];
|
|
87
|
+
const brutas = Math.floor(modulosDeDatos(ver) / 8);
|
|
88
|
+
const cortos = nBloques - (brutas % nBloques);
|
|
89
|
+
const largoCorto = Math.floor(brutas / nBloques);
|
|
90
|
+
const div = divisor(eccLen);
|
|
91
|
+
const bloques = [];
|
|
92
|
+
for (let i = 0, k = 0; i < nBloques; i++) {
|
|
93
|
+
const dat = datos.slice(k, k + largoCorto - eccLen + (i < cortos ? 0 : 1));
|
|
94
|
+
k += dat.length;
|
|
95
|
+
const ecc = resto(dat, div);
|
|
96
|
+
if (i < cortos)
|
|
97
|
+
dat.push(0);
|
|
98
|
+
bloques.push(dat.concat(ecc));
|
|
99
|
+
}
|
|
100
|
+
const final = [];
|
|
101
|
+
for (let i = 0; i < bloques[0].length; i++) {
|
|
102
|
+
bloques.forEach((b, j) => {
|
|
103
|
+
if (i !== largoCorto - eccLen || j >= cortos)
|
|
104
|
+
final.push(b[i]);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const n = ver * 4 + 17;
|
|
108
|
+
const m = Array.from({ length: n }, () => new Array(n).fill(false));
|
|
109
|
+
const fn = Array.from({ length: n }, () => new Array(n).fill(false));
|
|
110
|
+
const fijar = (x, y, v) => {
|
|
111
|
+
m[y][x] = v;
|
|
112
|
+
fn[y][x] = true;
|
|
113
|
+
};
|
|
114
|
+
for (let i = 0; i < n; i++) {
|
|
115
|
+
fijar(6, i, i % 2 === 0);
|
|
116
|
+
fijar(i, 6, i % 2 === 0);
|
|
117
|
+
}
|
|
118
|
+
for (const [cx, cy] of [
|
|
119
|
+
[3, 3],
|
|
120
|
+
[n - 4, 3],
|
|
121
|
+
[3, n - 4],
|
|
122
|
+
]) {
|
|
123
|
+
for (let dy = -4; dy <= 4; dy++) {
|
|
124
|
+
for (let dx = -4; dx <= 4; dx++) {
|
|
125
|
+
const d = Math.max(Math.abs(dx), Math.abs(dy));
|
|
126
|
+
const x = cx + dx;
|
|
127
|
+
const y = cy + dy;
|
|
128
|
+
if (x >= 0 && x < n && y >= 0 && y < n)
|
|
129
|
+
fijar(x, y, d !== 2 && d !== 4);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const al = posicionesDeAlineacion(ver);
|
|
134
|
+
al.forEach((a, i) => al.forEach((b, j) => {
|
|
135
|
+
if ((i === 0 && j === 0) || (i === 0 && j === al.length - 1) || (i === al.length - 1 && j === 0))
|
|
136
|
+
return;
|
|
137
|
+
for (let dy = -2; dy <= 2; dy++)
|
|
138
|
+
for (let dx = -2; dx <= 2; dx++)
|
|
139
|
+
fijar(a + dx, b + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
|
|
140
|
+
}));
|
|
141
|
+
const formato = (mascara) => {
|
|
142
|
+
const d = (BITS_DE_FORMATO_M << 3) | mascara;
|
|
143
|
+
let r = d;
|
|
144
|
+
for (let i = 0; i < 10; i++)
|
|
145
|
+
r = (r << 1) ^ ((r >>> 9) * 0x537);
|
|
146
|
+
const b = ((d << 10) | r) ^ 0x5412;
|
|
147
|
+
const bit = (i) => ((b >>> i) & 1) !== 0;
|
|
148
|
+
for (let i = 0; i <= 5; i++)
|
|
149
|
+
fijar(8, i, bit(i));
|
|
150
|
+
fijar(8, 7, bit(6));
|
|
151
|
+
fijar(8, 8, bit(7));
|
|
152
|
+
fijar(7, 8, bit(8));
|
|
153
|
+
for (let i = 9; i < 15; i++)
|
|
154
|
+
fijar(14 - i, 8, bit(i));
|
|
155
|
+
for (let i = 0; i < 8; i++)
|
|
156
|
+
fijar(n - 1 - i, 8, bit(i));
|
|
157
|
+
for (let i = 8; i < 15; i++)
|
|
158
|
+
fijar(8, n - 15 + i, bit(i));
|
|
159
|
+
fijar(8, n - 8, true);
|
|
160
|
+
};
|
|
161
|
+
formato(0);
|
|
162
|
+
if (ver >= 7) {
|
|
163
|
+
let r = ver;
|
|
164
|
+
for (let i = 0; i < 12; i++)
|
|
165
|
+
r = (r << 1) ^ ((r >>> 11) * 0x1f25);
|
|
166
|
+
const b = (ver << 12) | r;
|
|
167
|
+
for (let i = 0; i < 18; i++) {
|
|
168
|
+
const v = ((b >>> i) & 1) !== 0;
|
|
169
|
+
const a = n - 11 + (i % 3);
|
|
170
|
+
const c = Math.floor(i / 3);
|
|
171
|
+
fijar(a, c, v);
|
|
172
|
+
fijar(c, a, v);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
let i = 0;
|
|
176
|
+
for (let derecha = n - 1; derecha >= 1; derecha -= 2) {
|
|
177
|
+
if (derecha === 6)
|
|
178
|
+
derecha = 5;
|
|
179
|
+
for (let v = 0; v < n; v++) {
|
|
180
|
+
for (let j = 0; j < 2; j++) {
|
|
181
|
+
const x = derecha - j;
|
|
182
|
+
const y = ((derecha + 1) & 2) === 0 ? n - 1 - v : v;
|
|
183
|
+
if (!fn[y][x] && i < final.length * 8) {
|
|
184
|
+
m[y][x] = ((final[i >>> 3] >>> (7 - (i & 7))) & 1) !== 0;
|
|
185
|
+
i++;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const MASCARAS = [
|
|
191
|
+
(x, y) => (x + y) % 2 === 0,
|
|
192
|
+
(_x, y) => y % 2 === 0,
|
|
193
|
+
(x) => x % 3 === 0,
|
|
194
|
+
(x, y) => (x + y) % 3 === 0,
|
|
195
|
+
(x, y) => (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0,
|
|
196
|
+
(x, y) => ((x * y) % 2) + ((x * y) % 3) === 0,
|
|
197
|
+
(x, y) => (((x * y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
198
|
+
(x, y) => (((x + y) % 2) + ((x * y) % 3)) % 2 === 0,
|
|
199
|
+
];
|
|
200
|
+
const aplicar = (k) => {
|
|
201
|
+
for (let y = 0; y < n; y++)
|
|
202
|
+
for (let x = 0; x < n; x++)
|
|
203
|
+
if (!fn[y][x] && MASCARAS[k](x, y))
|
|
204
|
+
m[y][x] = !m[y][x];
|
|
205
|
+
};
|
|
206
|
+
const penalizacion = () => {
|
|
207
|
+
let p = 0;
|
|
208
|
+
for (let a = 0; a < n; a++) {
|
|
209
|
+
for (const fila of [true, false]) {
|
|
210
|
+
let racha = 1;
|
|
211
|
+
for (let b = 1; b <= n; b++) {
|
|
212
|
+
const igual = b < n && (fila ? m[a][b] === m[a][b - 1] : m[b]?.[a] === m[b - 1][a]);
|
|
213
|
+
if (igual)
|
|
214
|
+
racha++;
|
|
215
|
+
else {
|
|
216
|
+
if (racha >= 5)
|
|
217
|
+
p += racha - 2;
|
|
218
|
+
racha = 1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
for (let y = 0; y < n - 1; y++)
|
|
224
|
+
for (let x = 0; x < n - 1; x++)
|
|
225
|
+
if (m[y][x] === m[y][x + 1] && m[y][x] === m[y + 1][x] && m[y][x] === m[y + 1][x + 1])
|
|
226
|
+
p += 3;
|
|
227
|
+
const oscuros = m.flat().filter(Boolean).length;
|
|
228
|
+
p += Math.floor(Math.abs(oscuros * 20 - n * n * 10) / (n * n)) * 10;
|
|
229
|
+
return p;
|
|
230
|
+
};
|
|
231
|
+
let mejor = 0;
|
|
232
|
+
let minimo = Infinity;
|
|
233
|
+
for (let k = 0; k < 8; k++) {
|
|
234
|
+
aplicar(k);
|
|
235
|
+
formato(k);
|
|
236
|
+
const p = penalizacion();
|
|
237
|
+
if (p < minimo) {
|
|
238
|
+
minimo = p;
|
|
239
|
+
mejor = k;
|
|
240
|
+
}
|
|
241
|
+
aplicar(k);
|
|
242
|
+
}
|
|
243
|
+
aplicar(mejor);
|
|
244
|
+
formato(mejor);
|
|
245
|
+
return m;
|
|
246
|
+
}
|
|
247
|
+
export function qrEnTexto(texto, opciones) {
|
|
248
|
+
if (!opciones.unicode)
|
|
249
|
+
return null;
|
|
250
|
+
const m = matrizQR(texto);
|
|
251
|
+
const margen = 2;
|
|
252
|
+
const n = m.length + margen * 2;
|
|
253
|
+
const oscuro = (x, y) => {
|
|
254
|
+
const xx = x - margen;
|
|
255
|
+
const yy = y - margen;
|
|
256
|
+
return yy >= 0 && yy < m.length && xx >= 0 && xx < m.length ? m[yy][xx] : false;
|
|
257
|
+
};
|
|
258
|
+
const lineas = [];
|
|
259
|
+
for (let y = 0; y < n; y += 2) {
|
|
260
|
+
let l = '';
|
|
261
|
+
for (let x = 0; x < n; x++) {
|
|
262
|
+
const arriba = oscuro(x, y);
|
|
263
|
+
const abajo = y + 1 < n ? oscuro(x, y + 1) : false;
|
|
264
|
+
if (opciones.color)
|
|
265
|
+
l += arriba && abajo ? '█' : arriba ? '▀' : abajo ? '▄' : ' ';
|
|
266
|
+
else
|
|
267
|
+
l += !arriba && !abajo ? '█' : !arriba ? '▀' : !abajo ? '▄' : ' ';
|
|
268
|
+
}
|
|
269
|
+
lineas.push(opciones.color ? `\x1b[30;107m${l}\x1b[39;49m` : l);
|
|
270
|
+
}
|
|
271
|
+
return lineas;
|
|
272
|
+
}
|
package/dist/registro.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { carpetaDeConfiguracion } from "./config.js";
|
|
4
|
+
export class Registro {
|
|
5
|
+
ruta;
|
|
6
|
+
sesion;
|
|
7
|
+
constructor(sesion, dir = join(carpetaDeConfiguracion(), 'registro')) {
|
|
8
|
+
this.sesion = sesion;
|
|
9
|
+
const dia = new Date().toISOString().slice(0, 10);
|
|
10
|
+
this.ruta = join(dir, `${dia}.jsonl`);
|
|
11
|
+
try {
|
|
12
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
apuntar(tipo, datos = {}) {
|
|
18
|
+
try {
|
|
19
|
+
appendFileSync(this.ruta, `${JSON.stringify({ t: new Date().toISOString(), sesion: this.sesion, tipo, ...datos })}\n`, { mode: 0o600 });
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|