@getparallel/parx 0.5.0 → 0.7.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.
- package/CHANGELOG.md +15 -0
- package/README.md +11 -5
- package/dist/actualizar.js +2 -1
- package/dist/agente.js +82 -2
- package/dist/api.js +17 -0
- package/dist/cli.js +351 -35
- package/dist/config.js +6 -0
- package/dist/estimacion.js +118 -0
- package/dist/firmas.js +55 -0
- package/dist/marca.js +56 -19
- package/dist/mision.js +4 -3
- package/dist/par.js +355 -0
- package/dist/remoto.js +295 -0
- package/dist/servicio.js +191 -0
- package/dist/tar.js +99 -0
- package/dist/textos.js +68 -7
- package/dist/tui.js +56 -10
- package/dist/ui.js +45 -2
- package/dist/versiones.js +341 -0
- package/dist/vista.js +133 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,16 +6,20 @@ import { basename, resolve } from 'node:path';
|
|
|
6
6
|
import { parseArgs } from 'node:util';
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
8
|
import { ALIAS_COMANDO, ALIAS_SI_NO, COMANDOS, t, USO } from "./textos.js";
|
|
9
|
-
import { c, colorDeModo, fijarCapacidades, sep, signo, SIMBOLOS } from "./marca.js";
|
|
9
|
+
import { c, capacidades, colorDeModo, fijarCapacidades, sep, signo, sinColor, SIMBOLOS } from "./marca.js";
|
|
10
10
|
import { guardarAjustes, leerAjustes, migrarCarpetaVieja, VERSION } from "./config.js";
|
|
11
11
|
import { MODELO_POR_DEFECTO, MODELOS, modeloDe, nombreDeModelo } from "./modelos.js";
|
|
12
|
-
import { cicloDeMision, compartirMision, correoVisible, crearMision, ErrorDeParallel, leerBandeja, leerConexiones, leerCuenta, leerMisionDeLaCuenta, leerMisiones, leerPlantillas, quienEs, responderBandeja, verMision, } from "./api.js";
|
|
12
|
+
import { cicloDeMision, compartirMision, correoVisible, crearMision, equipo, ErrorDeParallel, leerBandeja, leerConexiones, leerCuenta, leerMisionDeLaCuenta, leerMisiones, leerPlantillas, quienEs, responderBandeja, verMision, } from "./api.js";
|
|
13
13
|
import { abrirNavegador, comoHasEntrado, credencialesActivas, entrar, formaDeLaOpcion, salir } from "./cuenta.js";
|
|
14
14
|
import { accionesDeUnaMision, filtrarPorTitulo, hace } from "./comandos.js";
|
|
15
|
-
import { hacerTarea, mensajeDeError, nuevaSesion } from "./agente.js";
|
|
15
|
+
import { hacerTarea, mensajeDeError, nuevaSesion, reiniciarConversacion } from "./agente.js";
|
|
16
16
|
import { deshacerUltimo, permitirCarpeta } from "./herramientas.js";
|
|
17
17
|
import { Registro } from "./registro.js";
|
|
18
18
|
import { Pantalla } from "./ui.js";
|
|
19
|
+
import { Remoto } from "./remoto.js";
|
|
20
|
+
import { VistaPrevia } from "./vista.js";
|
|
21
|
+
import { anadirCarpeta, carpetasDelServicio, instalarServicio, quitarCarpeta, quitarServicio, reiniciarServicio, rutaDelRegistro, servicioEnMarcha, servicioInstalado, servir } from "./servicio.js";
|
|
22
|
+
import { qrEnTexto } from "./qr.js";
|
|
19
23
|
import { acciones, bloqueDeBienvenida, bloqueDeLaPersona, bloqueDeTabla, duracion, Superficie } from "./tui.js";
|
|
20
24
|
import { CONSEJOS, cambiarConsejos, consejo, elegirConsejos, ordenDeConsejos } from "./consejos.js";
|
|
21
25
|
import { anchoDe, recortarMedio } from "./texto.js";
|
|
@@ -24,9 +28,9 @@ import { avisarEnElEscritorio, debeAvisar } from "./notificar.js";
|
|
|
24
28
|
import { copiarAlPortapapeles, escribirInforme, textoParaPegar } from "./informe.js";
|
|
25
29
|
import { objetivoDeMision } from "./mision.js";
|
|
26
30
|
import { ejecutarCarriles, MAX_CARRILES } from "./carriles.js";
|
|
27
|
-
import { spawnSync } from 'node:child_process';
|
|
28
31
|
import { ejecutarBash, textoParaElAgente } from "./bash.js";
|
|
29
|
-
import { comprobarDeFondo, esMasNueva, ordenDeActualizar, rutaDelCli, ultimaPublicada, versionNuevaConocida } from "./actualizar.js";
|
|
32
|
+
import { comprobarDeFondo, ENTRE_COMPROBACIONES_MS, esMasNueva, ordenDeActualizar, rutaDelCli, ultimaPublicada, versionNuevaConocida } from "./actualizar.js";
|
|
33
|
+
import { autoactualizarApagada, confirmarArranque, gestorPermiteAutoactualizar, lanzarLaMasNueva, prepararVersion } from "./versiones.js";
|
|
30
34
|
function opciones() {
|
|
31
35
|
return parseArgs({
|
|
32
36
|
allowPositionals: true,
|
|
@@ -46,6 +50,10 @@ function opciones() {
|
|
|
46
50
|
'no-mouse': { type: 'boolean' },
|
|
47
51
|
'no-animation': { type: 'boolean' },
|
|
48
52
|
animation: { type: 'boolean' },
|
|
53
|
+
remote: { type: 'boolean' },
|
|
54
|
+
serve: { type: 'boolean' },
|
|
55
|
+
'remote-child': { type: 'boolean' },
|
|
56
|
+
origen: { type: 'string' },
|
|
49
57
|
version: { type: 'boolean', short: 'v' },
|
|
50
58
|
help: { type: 'boolean', short: 'h' },
|
|
51
59
|
browser: { type: 'boolean' },
|
|
@@ -70,15 +78,38 @@ function rutaCorta(ruta, max = 48) {
|
|
|
70
78
|
const corta = ruta.startsWith(casa) ? `~${ruta.slice(casa.length)}` : ruta;
|
|
71
79
|
return recortarMedio(corta, max);
|
|
72
80
|
}
|
|
81
|
+
let lineaDeVersiones = null;
|
|
82
|
+
function novedadParaLaPantalla() {
|
|
83
|
+
if (lineaDeVersiones)
|
|
84
|
+
return lineaDeVersiones;
|
|
85
|
+
if (!autoactualizarApagada())
|
|
86
|
+
return undefined;
|
|
87
|
+
const nueva = versionNuevaConocida();
|
|
88
|
+
return nueva ? t('update.disponible', { version: nueva }) : undefined;
|
|
89
|
+
}
|
|
73
90
|
function cabeceraCorta(lineas = []) {
|
|
74
91
|
process.stdout.write(`\n ${c.violeta(signo())} ${c.negrita('parx')} ${c.gris(VERSION)}\n`);
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
lineas = [c.gris(
|
|
92
|
+
const novedad = novedadParaLaPantalla();
|
|
93
|
+
if (novedad)
|
|
94
|
+
lineas = [c.gris(novedad), ...lineas];
|
|
78
95
|
for (const l of lineas)
|
|
79
96
|
process.stdout.write(` ${l}\n`);
|
|
80
97
|
process.stdout.write('\n');
|
|
81
98
|
}
|
|
99
|
+
async function mantenerAlDia(registro) {
|
|
100
|
+
try {
|
|
101
|
+
const nueva = await comprobarDeFondo();
|
|
102
|
+
if (!nueva || autoactualizarApagada() || !gestorPermiteAutoactualizar(ordenDeActualizar(rutaDelCli()).gestor))
|
|
103
|
+
return;
|
|
104
|
+
const r = await prepararVersion(nueva);
|
|
105
|
+
if (!r.ok)
|
|
106
|
+
registro?.apuntar('actualizacion', { version: nueva, motivo: r.motivo });
|
|
107
|
+
else if (!r.yaEstaba)
|
|
108
|
+
registro?.apuntar('actualizacion', { version: nueva, preparada: true });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
}
|
|
112
|
+
}
|
|
82
113
|
export function nombreDeModo(m) {
|
|
83
114
|
return t(`modo.${m}`);
|
|
84
115
|
}
|
|
@@ -114,7 +145,7 @@ async function actualizar() {
|
|
|
114
145
|
process.stdout.write(`${t('update.npx')}\n`);
|
|
115
146
|
return 0;
|
|
116
147
|
}
|
|
117
|
-
if (gestor === 'desarrollo'
|
|
148
|
+
if (gestor === 'desarrollo') {
|
|
118
149
|
process.stdout.write(`${t('update.desarrollo')}\n`);
|
|
119
150
|
return 0;
|
|
120
151
|
}
|
|
@@ -127,14 +158,13 @@ async function actualizar() {
|
|
|
127
158
|
process.stdout.write(`${t('update.al_dia', { version: VERSION })}\n`);
|
|
128
159
|
return 0;
|
|
129
160
|
}
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
process.stderr.write(`${c.error('✗')} ${t('update.fallo', { orden: texto })}\n`);
|
|
161
|
+
const aMano = (orden ?? ['npm', 'install', '-g', '@getparallel/parx@latest']).map((p) => (/\s/.test(p) ? `"${p}"` : p)).join(' ');
|
|
162
|
+
const r = await prepararVersion(ultima);
|
|
163
|
+
if (!r.ok) {
|
|
164
|
+
process.stderr.write(`${c.error('✗')} ${t(r.motivo === 'firma' ? 'update.firma' : 'update.no_se_pudo', { version: ultima, orden: aMano })}\n`);
|
|
135
165
|
return 1;
|
|
136
166
|
}
|
|
137
|
-
process.stdout.write(`${c.violeta('✓')} ${t('update.
|
|
167
|
+
process.stdout.write(`${c.violeta('✓')} ${t(r.yaEstaba ? 'update.ya_preparada' : 'update.preparada', { version: ultima })}${r.novedad ? c.gris(`${sep()}${r.novedad}`) : ''}\n`);
|
|
138
168
|
return 0;
|
|
139
169
|
}
|
|
140
170
|
async function principal() {
|
|
@@ -152,6 +182,9 @@ async function principal() {
|
|
|
152
182
|
process.stdout.write(`parx ${VERSION}\n`);
|
|
153
183
|
return 0;
|
|
154
184
|
}
|
|
185
|
+
const estreno = confirmarArranque();
|
|
186
|
+
if (estreno)
|
|
187
|
+
lineaDeVersiones = estreno.novedad ? t('update.actualizado_con', { version: estreno.version, novedad: estreno.novedad }) : t('update.actualizado', { version: estreno.version });
|
|
155
188
|
if (v.help) {
|
|
156
189
|
cabeceraCorta();
|
|
157
190
|
process.stdout.write(`${USO}\n`);
|
|
@@ -162,7 +195,7 @@ async function principal() {
|
|
|
162
195
|
const solo = positionals.length === 1 && !v.lanes;
|
|
163
196
|
if (solo && ['update', 'upgrade'].includes(primero))
|
|
164
197
|
return actualizar();
|
|
165
|
-
void
|
|
198
|
+
void mantenerAlDia();
|
|
166
199
|
if (solo && ['login', 'entrar', 'switch'].includes(primero)) {
|
|
167
200
|
cabeceraCorta();
|
|
168
201
|
await entrar((l) => pantalla.escribir(l), { forma: formaPedida(v) });
|
|
@@ -194,6 +227,62 @@ async function principal() {
|
|
|
194
227
|
pantalla.escribir();
|
|
195
228
|
return 0;
|
|
196
229
|
}
|
|
230
|
+
if (v.serve) {
|
|
231
|
+
const c0 = credencialesActivas();
|
|
232
|
+
if (!c0) {
|
|
233
|
+
console.log(t('cuenta.sin_sesion'));
|
|
234
|
+
return 1;
|
|
235
|
+
}
|
|
236
|
+
return servir(c0);
|
|
237
|
+
}
|
|
238
|
+
if (primero === 'service' || primero === 'servicio') {
|
|
239
|
+
const accion = (positionals[1] ?? 'status').toLowerCase();
|
|
240
|
+
const ruta = positionals.slice(2).join(' ') || process.cwd();
|
|
241
|
+
const lista = () => carpetasDelServicio().map((x) => x.nombre).join(', ') || t('servicio.ninguna');
|
|
242
|
+
if (accion === 'add') {
|
|
243
|
+
const r = anadirCarpeta(ruta);
|
|
244
|
+
pantalla.escribir(r ? t('servicio.anadida', { ruta: rutaCorta(r, 60) }) : t('servicio.no_anadida', { ruta }));
|
|
245
|
+
if (r)
|
|
246
|
+
reiniciarServicio();
|
|
247
|
+
return r ? 0 : 1;
|
|
248
|
+
}
|
|
249
|
+
if (accion === 'remove') {
|
|
250
|
+
const ok = quitarCarpeta(positionals.slice(2).join(' '));
|
|
251
|
+
pantalla.escribir(ok ? t('servicio.quitada', { ruta: positionals.slice(2).join(' ') }) : t('servicio.no_quitada', { ruta: positionals.slice(2).join(' ') }));
|
|
252
|
+
if (ok)
|
|
253
|
+
reiniciarServicio();
|
|
254
|
+
return ok ? 0 : 1;
|
|
255
|
+
}
|
|
256
|
+
if (accion === 'on') {
|
|
257
|
+
if (process.platform !== 'darwin') {
|
|
258
|
+
pantalla.error(t('servicio.solo_mac'));
|
|
259
|
+
return 1;
|
|
260
|
+
}
|
|
261
|
+
if (!credencialesActivas()) {
|
|
262
|
+
pantalla.escribir(t('cuenta.sin_sesion'));
|
|
263
|
+
return 1;
|
|
264
|
+
}
|
|
265
|
+
if (!carpetasDelServicio().length && !anadirCarpeta(process.cwd())) {
|
|
266
|
+
pantalla.escribir(t('servicio.sin_carpetas'));
|
|
267
|
+
return 1;
|
|
268
|
+
}
|
|
269
|
+
instalarServicio();
|
|
270
|
+
pantalla.escribir(t('servicio.on', { carpetas: lista() }));
|
|
271
|
+
pantalla.escribir(c.gris(t('servicio.registro', { ruta: rutaDelRegistro() })));
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
if (accion === 'off') {
|
|
275
|
+
quitarServicio();
|
|
276
|
+
pantalla.escribir(t('servicio.off'));
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
if (accion === 'status') {
|
|
280
|
+
pantalla.escribir(t('servicio.estado', { estado: servicioInstalado() && servicioEnMarcha() ? t('servicio.en_marcha') : t('servicio.parado'), lista: lista() }));
|
|
281
|
+
return 0;
|
|
282
|
+
}
|
|
283
|
+
pantalla.escribir(t('servicio.uso'));
|
|
284
|
+
return 2;
|
|
285
|
+
}
|
|
197
286
|
const modoPedido = (v.mode ?? v.modo);
|
|
198
287
|
const pedido = modoDe(modoPedido);
|
|
199
288
|
if (pedido === 'bypass') {
|
|
@@ -242,6 +331,8 @@ async function principal() {
|
|
|
242
331
|
lecturas: [],
|
|
243
332
|
jaula: Boolean(v.sandbox),
|
|
244
333
|
});
|
|
334
|
+
if (cuenta.tarifa)
|
|
335
|
+
sesion.tarifas = cuenta.tarifa;
|
|
245
336
|
for (const f of v['add-folder'] ?? []) {
|
|
246
337
|
const ok = permitirCarpeta(sesion.ctx, f);
|
|
247
338
|
if (!ok)
|
|
@@ -270,6 +361,26 @@ async function principal() {
|
|
|
270
361
|
let control = new AbortController();
|
|
271
362
|
let ocupado = false;
|
|
272
363
|
let superficie = null;
|
|
364
|
+
let remoto = null;
|
|
365
|
+
let deFueraPendientes = 0;
|
|
366
|
+
let sugeridaMision = false;
|
|
367
|
+
let vistaPrevia = new VistaPrevia();
|
|
368
|
+
const actualizarVista = async (forzar = false) => {
|
|
369
|
+
const r0 = remoto;
|
|
370
|
+
if (!r0?.encendido || !r0.id)
|
|
371
|
+
return null;
|
|
372
|
+
try {
|
|
373
|
+
const r = await vistaPrevia.actualizar({ servidor: cred.servidor, token: cred.token, remoto: r0.id, raiz });
|
|
374
|
+
if (!r)
|
|
375
|
+
return null;
|
|
376
|
+
if (r.cambiados > 0 || forzar)
|
|
377
|
+
r0.evento('vista', { url: r.url, version: r.version, archivos: r.cambiados, carpeta: r.carpeta });
|
|
378
|
+
return { url: r.url };
|
|
379
|
+
}
|
|
380
|
+
catch (e) {
|
|
381
|
+
return { error: e instanceof ErrorDeParallel ? e.codigo : 'red' };
|
|
382
|
+
}
|
|
383
|
+
};
|
|
273
384
|
let bienvenida;
|
|
274
385
|
let consejosDeEntrada = [];
|
|
275
386
|
const confirmarNuevaEnMarcha = async () => {
|
|
@@ -283,15 +394,7 @@ async function principal() {
|
|
|
283
394
|
control.abort();
|
|
284
395
|
};
|
|
285
396
|
const empezarDeNuevo = () => {
|
|
286
|
-
sesion
|
|
287
|
-
sesion.diario = [];
|
|
288
|
-
sesion.id = randomUUID();
|
|
289
|
-
sesion.ultimaTarea = undefined;
|
|
290
|
-
sesion.ctx.hechos = { ficheros: [], comandos: [] };
|
|
291
|
-
sesion.ctx.permitidos.clear();
|
|
292
|
-
sesion.ctx.deshacer.length = 0;
|
|
293
|
-
if (sesion.ctx.lecturas)
|
|
294
|
-
sesion.ctx.lecturas.length = 0;
|
|
397
|
+
reiniciarConversacion(sesion);
|
|
295
398
|
registro.apuntar('nueva', {});
|
|
296
399
|
pantalla.reiniciar();
|
|
297
400
|
if (superficie)
|
|
@@ -307,6 +410,14 @@ async function principal() {
|
|
|
307
410
|
superficie.terminar(despedida());
|
|
308
411
|
else
|
|
309
412
|
pantalla.escribir(despedida());
|
|
413
|
+
if (remoto?.encendido) {
|
|
414
|
+
const salida = setTimeout(() => process.exit(0), 1500);
|
|
415
|
+
void remoto.cerrar().finally(() => {
|
|
416
|
+
clearTimeout(salida);
|
|
417
|
+
process.exit(0);
|
|
418
|
+
});
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
310
421
|
process.exit(0);
|
|
311
422
|
};
|
|
312
423
|
const alCtrlC = () => {
|
|
@@ -348,6 +459,13 @@ async function principal() {
|
|
|
348
459
|
superficie?.trabajar(() => control.abort());
|
|
349
460
|
const inicio = Date.now();
|
|
350
461
|
let seguir = true;
|
|
462
|
+
if (remoto?.encendido) {
|
|
463
|
+
remoto.fijarModo(nombreDeModo(sesion.ctx.modo), nombreDeModelo(sesion.modelo));
|
|
464
|
+
remoto.evento('tu', { texto: texto.replace(/^\u2060/, ''), desde: deFueraPendientes > 0 ? 'movil' : 'ordenador' });
|
|
465
|
+
if (deFueraPendientes > 0)
|
|
466
|
+
deFueraPendientes--;
|
|
467
|
+
remoto.fijarEstado('trabajando', texto.replace(/^\u2060/, ''));
|
|
468
|
+
}
|
|
351
469
|
try {
|
|
352
470
|
seguir = await hacerTarea(sesion, texto, control.signal, imagenes);
|
|
353
471
|
if (sesion.disponibles !== undefined && sesion.disponibles !== null)
|
|
@@ -356,10 +474,100 @@ async function principal() {
|
|
|
356
474
|
finally {
|
|
357
475
|
ocupado = false;
|
|
358
476
|
superficie?.descansar();
|
|
477
|
+
remoto?.fijarEstado('libre', null);
|
|
478
|
+
}
|
|
479
|
+
if (remoto?.encendido)
|
|
480
|
+
void actualizarVista();
|
|
481
|
+
if (!sugeridaMision && sesion.diario.some((d) => d.ficheros.length) && superficie) {
|
|
482
|
+
sugeridaMision = true;
|
|
483
|
+
soloAqui(() => pantalla.escribir(c.gris(t('mision.sugerencia'))));
|
|
359
484
|
}
|
|
360
485
|
quizaAvisar(t('aviso.termino', { tarea: texto.replace(/\s+/g, ' ').slice(0, 80) }), Date.now() - inicio);
|
|
361
486
|
return seguir;
|
|
362
487
|
};
|
|
488
|
+
const encenderRemoto = async (enseñarQR = true) => {
|
|
489
|
+
if (!superficie) {
|
|
490
|
+
pantalla.escribir(t('remoto.solo_interactiva'));
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (remoto?.encendido && remoto.url) {
|
|
494
|
+
const url = remoto.url;
|
|
495
|
+
soloAqui(() => enseñarEnlace(url, enseñarQR));
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const nuevo = new Remoto({
|
|
499
|
+
servidor: cred.servidor,
|
|
500
|
+
token: cred.token,
|
|
501
|
+
alMensaje: (texto) => {
|
|
502
|
+
soloAqui(() => pantalla.escribir(c.gris(`${t('remoto.del_movil')}:`)));
|
|
503
|
+
deFueraPendientes++;
|
|
504
|
+
superficie?.mandarDesdeFuera(texto);
|
|
505
|
+
},
|
|
506
|
+
alParar: () => {
|
|
507
|
+
if (!ocupado)
|
|
508
|
+
return;
|
|
509
|
+
control.abort();
|
|
510
|
+
pantalla.aviso(t('remoto.parado'));
|
|
511
|
+
},
|
|
512
|
+
alApagarse: (motivo) => {
|
|
513
|
+
pantalla.espejo = null;
|
|
514
|
+
remoto = null;
|
|
515
|
+
pantalla.aviso(motivo === 'web' ? t('remoto.cortado_web') : motivo === 'sesion' ? t('remoto.sesion') : t('remoto.no_disponible'));
|
|
516
|
+
superficie?.pintar();
|
|
517
|
+
},
|
|
518
|
+
});
|
|
519
|
+
try {
|
|
520
|
+
const r = await nuevo.abrir({ equipo: equipo().equipo, version: equipo().version, carpeta: basename(raiz), modelo: nombreDeModelo(sesion.modelo), modo: nombreDeModo(sesion.ctx.modo) });
|
|
521
|
+
remoto = nuevo;
|
|
522
|
+
vistaPrevia = new VistaPrevia();
|
|
523
|
+
registro.apuntar('remoto', { encendido: true });
|
|
524
|
+
enseñarEnlace(r.url, enseñarQR);
|
|
525
|
+
pantalla.espejo = nuevo;
|
|
526
|
+
}
|
|
527
|
+
catch (e) {
|
|
528
|
+
if (e instanceof ErrorDeParallel) {
|
|
529
|
+
if (e.codigo === 'sin_acceso')
|
|
530
|
+
pantalla.error(t('remoto.no_disponible'));
|
|
531
|
+
else if (e.codigo === 'sesion')
|
|
532
|
+
pantalla.error(t('remoto.sesion'));
|
|
533
|
+
else if (e.detalle.includes('demasiados'))
|
|
534
|
+
pantalla.error(t('remoto.demasiados'));
|
|
535
|
+
else
|
|
536
|
+
pantalla.error(t('remoto.sin_red', { motivo: e.codigo === 'red' ? 'no connection' : e.detalle || e.codigo }));
|
|
537
|
+
}
|
|
538
|
+
else
|
|
539
|
+
throw e;
|
|
540
|
+
}
|
|
541
|
+
superficie?.pintar();
|
|
542
|
+
};
|
|
543
|
+
const soloAqui = (f) => {
|
|
544
|
+
const e = pantalla.espejo;
|
|
545
|
+
pantalla.espejo = null;
|
|
546
|
+
try {
|
|
547
|
+
f();
|
|
548
|
+
}
|
|
549
|
+
finally {
|
|
550
|
+
pantalla.espejo = e;
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
const enseñarEnlace = (url, conQR) => {
|
|
554
|
+
pantalla.escribir(t('remoto.on', { url: c.marca(url) }));
|
|
555
|
+
pantalla.escribir(c.gris(t('remoto.detalle')));
|
|
556
|
+
const caps = capacidades();
|
|
557
|
+
const qr = conQR ? qrEnTexto(url, { color: caps.color > 0, unicode: caps.unicode }) : null;
|
|
558
|
+
if (qr && caps.ancho >= sinColor(qr[0]).length + 4) {
|
|
559
|
+
pantalla.escribir(c.gris(t('remoto.escanea')));
|
|
560
|
+
pantalla.bloque(() => ['', ...qr.map((l) => ` ${l}`), '']);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
const apagarRemoto = async () => {
|
|
564
|
+
const r = remoto;
|
|
565
|
+
remoto = null;
|
|
566
|
+
pantalla.espejo = null;
|
|
567
|
+
if (r)
|
|
568
|
+
await r.cerrar();
|
|
569
|
+
registro.apuntar('remoto', { encendido: false });
|
|
570
|
+
};
|
|
363
571
|
const carriles = async (tareas) => {
|
|
364
572
|
if (tareas.length < 2) {
|
|
365
573
|
pantalla.escribir(t('carriles.min'));
|
|
@@ -407,6 +615,63 @@ async function principal() {
|
|
|
407
615
|
quizaAvisar(t('carriles.hecho', { n: tareas.length }), ms);
|
|
408
616
|
return r.ok;
|
|
409
617
|
};
|
|
618
|
+
if (v['remote-child']) {
|
|
619
|
+
const cola = [];
|
|
620
|
+
let despertar = null;
|
|
621
|
+
let cortada = false;
|
|
622
|
+
const r = new Remoto({
|
|
623
|
+
servidor: cred.servidor,
|
|
624
|
+
token: cred.token,
|
|
625
|
+
alMensaje: (texto) => {
|
|
626
|
+
cola.push(texto);
|
|
627
|
+
despertar?.();
|
|
628
|
+
},
|
|
629
|
+
alParar: () => {
|
|
630
|
+
if (ocupado)
|
|
631
|
+
control.abort();
|
|
632
|
+
},
|
|
633
|
+
alApagarse: () => {
|
|
634
|
+
cortada = true;
|
|
635
|
+
if (ocupado)
|
|
636
|
+
control.abort();
|
|
637
|
+
despertar?.();
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
const e = equipo();
|
|
641
|
+
try {
|
|
642
|
+
await r.abrir({ equipo: e.equipo, version: e.version, carpeta: basename(raiz), modelo: nombreDeModelo(sesion.modelo), modo: nombreDeModo(sesion.ctx.modo), ...(typeof v.origen === 'string' ? { origen: v.origen } : {}) });
|
|
643
|
+
}
|
|
644
|
+
catch {
|
|
645
|
+
return 1;
|
|
646
|
+
}
|
|
647
|
+
remoto = r;
|
|
648
|
+
pantalla.espejo = r;
|
|
649
|
+
if (tarea) {
|
|
650
|
+
deFueraPendientes++;
|
|
651
|
+
await hacer(tarea);
|
|
652
|
+
}
|
|
653
|
+
const INACTIVA_MS = 30 * 60 * 1000;
|
|
654
|
+
while (!cortada) {
|
|
655
|
+
const siguiente = cola.shift();
|
|
656
|
+
if (siguiente) {
|
|
657
|
+
deFueraPendientes++;
|
|
658
|
+
await hacer(siguiente);
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
const hubo = await new Promise((res) => {
|
|
662
|
+
const reloj = setTimeout(() => res(false), INACTIVA_MS);
|
|
663
|
+
despertar = () => {
|
|
664
|
+
clearTimeout(reloj);
|
|
665
|
+
res(true);
|
|
666
|
+
};
|
|
667
|
+
});
|
|
668
|
+
despertar = null;
|
|
669
|
+
if (!hubo)
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
await r.cerrar();
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
410
675
|
if (tarea) {
|
|
411
676
|
cabeceraCorta([c.gris([nombreDeModo(modo), nombreDeModelo(modelo), cuenta.plan, rutaCorta(raiz)].filter(Boolean).join(sep()))]);
|
|
412
677
|
if (quiereBypass && (await confirmarBypass()))
|
|
@@ -507,15 +772,14 @@ async function principal() {
|
|
|
507
772
|
quien: quien.includes('@') ? quien : (quien.split(/\s+/)[0] ?? ''),
|
|
508
773
|
carpeta: rutaCorta(raiz, 60),
|
|
509
774
|
plan: cuenta.plan,
|
|
510
|
-
novedad: (
|
|
511
|
-
const nueva = versionNuevaConocida();
|
|
512
|
-
return nueva ? t('update.disponible', { version: nueva }) : undefined;
|
|
513
|
-
})(),
|
|
775
|
+
novedad: novedadParaLaPantalla(),
|
|
514
776
|
peligro: () => sesion.ctx.modo === 'bypass',
|
|
515
777
|
});
|
|
516
778
|
superficie.iniciar(bienvenida, consejosDeEntrada);
|
|
517
779
|
if (quiereBypass)
|
|
518
780
|
await confirmarBypass();
|
|
781
|
+
if (v.remote || ajustes.remoto)
|
|
782
|
+
void encenderRemoto(Boolean(v.remote));
|
|
519
783
|
const mirarBandeja = async () => {
|
|
520
784
|
if (ocupado)
|
|
521
785
|
return;
|
|
@@ -536,6 +800,11 @@ async function principal() {
|
|
|
536
800
|
relojBandeja.unref();
|
|
537
801
|
void mirarBandeja();
|
|
538
802
|
void cargarConexiones();
|
|
803
|
+
const relojVersiones = setInterval(() => {
|
|
804
|
+
if (!ocupado)
|
|
805
|
+
void mantenerAlDia(registro);
|
|
806
|
+
}, ENTRE_COMPROBACIONES_MS);
|
|
807
|
+
relojVersiones.unref();
|
|
539
808
|
}
|
|
540
809
|
const leerLinea = async (ejemplo = null) => {
|
|
541
810
|
if (superficie)
|
|
@@ -962,7 +1231,7 @@ async function principal() {
|
|
|
962
1231
|
break;
|
|
963
1232
|
}
|
|
964
1233
|
case 'mission': {
|
|
965
|
-
const objetivo = objetivoDeMision(resto, sesion.diario);
|
|
1234
|
+
const objetivo = objetivoDeMision(resto, sesion.diario, vistaPrevia.url);
|
|
966
1235
|
if (!objetivo) {
|
|
967
1236
|
pantalla.escribir(t('mision.nada'));
|
|
968
1237
|
break;
|
|
@@ -1053,6 +1322,47 @@ async function principal() {
|
|
|
1053
1322
|
pantalla.escribir(pantalla.animar ? t('animacion.on') : t('animacion.off'));
|
|
1054
1323
|
break;
|
|
1055
1324
|
}
|
|
1325
|
+
case 'remote': {
|
|
1326
|
+
if (arg === 'off' || ALIAS_SI_NO[arg] === 'no' || arg === 'never') {
|
|
1327
|
+
await apagarRemoto();
|
|
1328
|
+
if (leerAjustes().remoto)
|
|
1329
|
+
guardarAjustes({ remoto: false });
|
|
1330
|
+
pantalla.escribir(t('remoto.off'));
|
|
1331
|
+
superficie?.pintar();
|
|
1332
|
+
break;
|
|
1333
|
+
}
|
|
1334
|
+
if (arg === 'always' || arg === 'siempre') {
|
|
1335
|
+
guardarAjustes({ remoto: true });
|
|
1336
|
+
await encenderRemoto(true);
|
|
1337
|
+
pantalla.escribir(c.gris(t('remoto.siempre')));
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1340
|
+
await encenderRemoto(true);
|
|
1341
|
+
break;
|
|
1342
|
+
}
|
|
1343
|
+
case 'preview': {
|
|
1344
|
+
if (!remoto?.encendido) {
|
|
1345
|
+
pantalla.escribir(t('vista.sin_remoto'));
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
const r = await actualizarVista(true);
|
|
1349
|
+
if (!r)
|
|
1350
|
+
pantalla.escribir(t('vista.sin_web'));
|
|
1351
|
+
else if ('error' in r)
|
|
1352
|
+
pantalla.error(t('vista.no_subida', { motivo: r.error }));
|
|
1353
|
+
else
|
|
1354
|
+
pantalla.escribir(t('vista.lista', { url: c.marca(r.url) }));
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
case 'autoupdate': {
|
|
1358
|
+
const si = ALIAS_SI_NO[arg] ?? (autoactualizarApagada() ? 'si' : 'no');
|
|
1359
|
+
guardarAjustes({ autoactualizar: si === 'si' });
|
|
1360
|
+
registro.apuntar('autoactualizar', { encendido: si === 'si' });
|
|
1361
|
+
pantalla.escribir(si === 'si' ? t('autoupdate.on') : t('autoupdate.off'));
|
|
1362
|
+
if (si === 'si')
|
|
1363
|
+
void mantenerAlDia(registro);
|
|
1364
|
+
break;
|
|
1365
|
+
}
|
|
1056
1366
|
case 'undo': {
|
|
1057
1367
|
const r2 = deshacerUltimo(sesion.ctx);
|
|
1058
1368
|
pantalla.escribir(r2 ? t('repl.deshecho', { ruta: r2 }) : t('repl.nada_que_deshacer'));
|
|
@@ -1112,10 +1422,16 @@ async function principal() {
|
|
|
1112
1422
|
return 0;
|
|
1113
1423
|
}
|
|
1114
1424
|
if (!process.env.PARX_PRUEBAS) {
|
|
1115
|
-
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1425
|
+
lanzarLaMasNueva().then((lanzamiento) => {
|
|
1426
|
+
if (lanzamiento.lanzada)
|
|
1427
|
+
return;
|
|
1428
|
+
if (lanzamiento.retirada)
|
|
1429
|
+
lineaDeVersiones = t('update.no_arranco', { version: lanzamiento.retirada, actual: VERSION });
|
|
1430
|
+
principal().then((codigo) => process.exit(codigo), (e) => {
|
|
1431
|
+
if (e instanceof ErrorDeParallel && e.codigo === 'interrumpido')
|
|
1432
|
+
process.exit(130);
|
|
1433
|
+
process.stderr.write(`${c.error('✗')} ${e instanceof ErrorDeParallel ? mensajeDeError(e) : e instanceof Error ? e.message : String(e)}\n`);
|
|
1434
|
+
process.exit(1);
|
|
1435
|
+
});
|
|
1120
1436
|
});
|
|
1121
1437
|
}
|
package/dist/config.js
CHANGED
|
@@ -96,6 +96,12 @@ export function leerAjustes(dir = carpetaDeConfiguracion()) {
|
|
|
96
96
|
out.raton = a.raton;
|
|
97
97
|
if (typeof a.animacion === 'boolean')
|
|
98
98
|
out.animacion = a.animacion;
|
|
99
|
+
if (typeof a.autoactualizar === 'boolean')
|
|
100
|
+
out.autoactualizar = a.autoactualizar;
|
|
101
|
+
if (typeof a.remoto === 'boolean')
|
|
102
|
+
out.remoto = a.remoto;
|
|
103
|
+
if (Array.isArray(a.carpetasRemotas))
|
|
104
|
+
out.carpetasRemotas = a.carpetasRemotas.filter((x) => typeof x === 'string').slice(0, 20);
|
|
99
105
|
const k = a.consejos;
|
|
100
106
|
if (k && typeof k === 'object') {
|
|
101
107
|
const n = (x) => (typeof x === 'number' && Number.isFinite(x) && x >= 0 ? Math.floor(x) : 0);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { carpetaDeConfiguracion } from "./config.js";
|
|
4
|
+
import { MODELOS, ORDEN_DE_MODELOS, nombreDeModelo } from "./modelos.js";
|
|
5
|
+
import { t } from "./textos.js";
|
|
6
|
+
export const PERFILES = {
|
|
7
|
+
pregunta: { vueltas: 2, crecimiento: 700, salidaPorVuelta: 80, salidaFinal: 350 },
|
|
8
|
+
pequena: { vueltas: 4, crecimiento: 900, salidaPorVuelta: 350, salidaFinal: 200 },
|
|
9
|
+
media: { vueltas: 8, crecimiento: 1200, salidaPorVuelta: 550, salidaFinal: 250 },
|
|
10
|
+
grande: { vueltas: 16, crecimiento: 1500, salidaPorVuelta: 650, salidaFinal: 350 },
|
|
11
|
+
};
|
|
12
|
+
const GRANDE = /\b(refactor|refactoriz|migrat|migra[r]?\b|rewrite|reescrib|rework|whole (project|app|codebase|repo)|entire|todo el (proyecto|código|repo)|toda la (app|aplicación)|all (the )?files|todos los ficheros|architecture|arquitectura|from scratch|desde cero|full[- ]stack|authentication|autenticaci|database|base de datos|deploy|despliega|integrat|integra[r]?\b|test suite|end[- ]to[- ]end|e2e|multi[- ]?page|varias páginas|dashboard|backend|api rest|microservic)/i;
|
|
13
|
+
const CREA = /\b(create|build|make|write|generate|implement|crea[r]?|construye|monta|escribe|genera|implementa|haz(me)?|new|nuev[oa])\b/i;
|
|
14
|
+
const SUSTANCIAL = /\b(page|página|pagina|website|web ?site|site|web|app|form|formulario|component|componente|feature|funcionalidad|endpoint|screen|pantalla|module|módulo|modulo|api|script|server|servidor|service|servicio|table|tabla|model|modelo|view|vista)\b/i;
|
|
15
|
+
const PEQUENA = /\b(typo|errata|rename|renombra|one[- ]line|una línea|small|pequeñ|minor|mínim|quick|rápid|simple|sencill|tiny|just|solo|sólo|only|fix the|arregla el|arregla la|change the|cambia el|cambia la|add a |añade un|añade una|remove the|quita el|quita la|update the|actualiza el)\b/i;
|
|
16
|
+
const PREGUNTA = /^(what|why|how|where|which|who|when|is|are|does|do|can|could|should|explain|describe|tell me|show me|list|qué|que|por qué|cómo|como|dónde|donde|cuál|cual|quién|quien|cuándo|explica|describe|dime|enséñame|lista|hay)\b/i;
|
|
17
|
+
function palabras(s) {
|
|
18
|
+
return s.trim().split(/\s+/).filter(Boolean).length;
|
|
19
|
+
}
|
|
20
|
+
export function clasificarTarea(pedido) {
|
|
21
|
+
const s = pedido.replace(/\s+/g, ' ').trim();
|
|
22
|
+
const n = palabras(s);
|
|
23
|
+
if (!s)
|
|
24
|
+
return 'pequena';
|
|
25
|
+
if (GRANDE.test(s) || n > 90)
|
|
26
|
+
return 'grande';
|
|
27
|
+
const pregunta = PREGUNTA.test(s) || (s.endsWith('?') && !CREA.test(s));
|
|
28
|
+
if (pregunta && !CREA.test(s))
|
|
29
|
+
return 'pregunta';
|
|
30
|
+
const creaAlgo = CREA.test(s) || SUSTANCIAL.test(s);
|
|
31
|
+
if (n <= 10 && !creaAlgo)
|
|
32
|
+
return 'pequena';
|
|
33
|
+
if (PEQUENA.test(s) && !creaAlgo)
|
|
34
|
+
return 'pequena';
|
|
35
|
+
return 'media';
|
|
36
|
+
}
|
|
37
|
+
export function tokensDe(texto) {
|
|
38
|
+
const chars = typeof texto === 'number' ? texto : texto.length;
|
|
39
|
+
return Math.ceil(chars / 3.8);
|
|
40
|
+
}
|
|
41
|
+
export function accionesEnBruto(clase, baseTokens, tarifa) {
|
|
42
|
+
const p = PERFILES[clase];
|
|
43
|
+
let entrada = 0;
|
|
44
|
+
let salida = 0;
|
|
45
|
+
for (let i = 0; i < p.vueltas; i++) {
|
|
46
|
+
entrada += baseTokens + i * p.crecimiento;
|
|
47
|
+
salida += i === p.vueltas - 1 ? p.salidaFinal : p.salidaPorVuelta;
|
|
48
|
+
}
|
|
49
|
+
return (entrada * tarifa.entrada + salida * tarifa.salida) / 1000;
|
|
50
|
+
}
|
|
51
|
+
export function redondear(n) {
|
|
52
|
+
if (n < 1)
|
|
53
|
+
return 1;
|
|
54
|
+
if (n < 10)
|
|
55
|
+
return Math.round(n);
|
|
56
|
+
const magnitud = 10 ** (Math.floor(Math.log10(n)) - 1);
|
|
57
|
+
return Math.round(n / magnitud) * magnitud;
|
|
58
|
+
}
|
|
59
|
+
export function estimarTarea(e) {
|
|
60
|
+
const clase = clasificarTarea(e.pedido);
|
|
61
|
+
const base = tokensDe(e.contextoChars) + tokensDe(e.pedido);
|
|
62
|
+
const acciones = {};
|
|
63
|
+
for (const m of ORDEN_DE_MODELOS) {
|
|
64
|
+
const bruto = accionesEnBruto(clase, base, e.tarifas[MODELOS[m].servidor]);
|
|
65
|
+
acciones[m] = redondear(bruto * factorDeCalibracion(e.calibracion, clase, m));
|
|
66
|
+
}
|
|
67
|
+
return { clase, acciones };
|
|
68
|
+
}
|
|
69
|
+
export function lineaDeEstimacion(est, modelo) {
|
|
70
|
+
const actual = est.acciones[modelo];
|
|
71
|
+
let sugerido = null;
|
|
72
|
+
if (modelo === 'summit' && est.clase !== 'grande')
|
|
73
|
+
sugerido = 'stride';
|
|
74
|
+
if ((modelo === 'summit' || modelo === 'stride') && (est.clase === 'pregunta' || est.clase === 'pequena'))
|
|
75
|
+
sugerido = 'swift';
|
|
76
|
+
if (sugerido && est.acciones[sugerido] <= actual * 0.6 && actual >= 5) {
|
|
77
|
+
return t('estimacion.con', { n: actual.toLocaleString('en-US'), modelo: nombreDeModelo(sugerido).replace(/ \d+(\.\d+)?$/, ''), otro: est.acciones[sugerido].toLocaleString('en-US') });
|
|
78
|
+
}
|
|
79
|
+
return t('estimacion.linea', { n: actual.toLocaleString('en-US') });
|
|
80
|
+
}
|
|
81
|
+
const FICHERO = 'estimaciones.json';
|
|
82
|
+
const PESO = 0.3;
|
|
83
|
+
export function leerCalibracion(dir = carpetaDeConfiguracion()) {
|
|
84
|
+
try {
|
|
85
|
+
const c = JSON.parse(readFileSync(join(dir, FICHERO), 'utf8'));
|
|
86
|
+
return c && typeof c === 'object' ? c : {};
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function guardarCalibracion(c, dir) {
|
|
93
|
+
try {
|
|
94
|
+
if (!existsSync(dir))
|
|
95
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
96
|
+
writeFileSync(join(dir, FICHERO), JSON.stringify(c, null, 2), { mode: 0o600 });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function factorDeCalibracion(c, clase, modelo) {
|
|
102
|
+
const f = c?.[clase]?.[modelo]?.factor;
|
|
103
|
+
if (typeof f !== 'number' || !Number.isFinite(f) || f <= 0)
|
|
104
|
+
return 1;
|
|
105
|
+
return Math.min(2, Math.max(0.5, f));
|
|
106
|
+
}
|
|
107
|
+
export function aprenderDeLaTarea(o) {
|
|
108
|
+
const dir = o.dir ?? carpetaDeConfiguracion();
|
|
109
|
+
const c = o.calibracion ?? leerCalibracion(dir);
|
|
110
|
+
if (!(o.estimada > 0) || !(o.real > 0))
|
|
111
|
+
return c;
|
|
112
|
+
const ratio = Math.min(4, Math.max(0.25, o.real / o.estimada));
|
|
113
|
+
const antes = c[o.clase]?.[o.modelo];
|
|
114
|
+
const factor = antes ? antes.factor * (1 - PESO) + ratio * PESO : ratio;
|
|
115
|
+
c[o.clase] = { ...(c[o.clase] ?? {}), [o.modelo]: { factor: Number(factor.toFixed(3)), n: (antes?.n ?? 0) + 1 } };
|
|
116
|
+
guardarCalibracion(c, dir);
|
|
117
|
+
return c;
|
|
118
|
+
}
|