@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/textos.js
CHANGED
|
@@ -206,19 +206,62 @@ export const TEXTOS = {
|
|
|
206
206
|
'salir.entorno': 'You are signed in with PARALLEL_API_KEY: remove it from your environment to sign out.',
|
|
207
207
|
'salir.todas': 'Signed out on {n} terminals. API keys stay active.',
|
|
208
208
|
'nombre.nuevo': 'parallel-code is now called parx. Type “parx”.',
|
|
209
|
+
'estimacion.linea': '~{n} Actions (estimate)',
|
|
210
|
+
'estimacion.con': '~{n} Actions (estimate) · with {modelo}: ~{otro}',
|
|
209
211
|
'update.disponible': 'parx {version} available · run `parx update`',
|
|
210
212
|
'update.al_dia': 'parx {version} is the latest version.',
|
|
211
213
|
'update.sin_red': 'Could not reach npm to check for a new version. Try again later.',
|
|
212
|
-
'update.lanzando': 'Updating with: {orden}',
|
|
213
|
-
'update.hecho': 'Done. parx is now up to date.',
|
|
214
|
-
'update.fallo': 'The update did not finish. Run it yourself: {orden}',
|
|
215
214
|
'update.npx': 'You are running parx through npx. Use `npx @getparallel/parx@latest` to always get the latest version.',
|
|
216
215
|
'update.desarrollo': 'This is a development copy of parx (not installed from npm). Update it with git pull.',
|
|
216
|
+
'update.actualizado': 'parx updated to {version}',
|
|
217
|
+
'update.actualizado_con': 'parx updated to {version} · {novedad}',
|
|
218
|
+
'update.preparada': 'parx {version} is ready · it runs the next time you open parx',
|
|
219
|
+
'update.ya_preparada': 'parx {version} is already downloaded · it runs the next time you open parx',
|
|
220
|
+
'update.no_arranco': 'parx {version} did not start · back on {actual}',
|
|
221
|
+
'update.firma': 'parx {version} is on npm but its signature could not be verified, so it was not installed. Update by hand: {orden}',
|
|
222
|
+
'update.no_se_pudo': 'parx {version} could not be downloaded or checked. Update by hand: {orden}',
|
|
223
|
+
'autoupdate.on': 'parx keeps itself up to date: new versions are downloaded in the background and start with the next session.',
|
|
224
|
+
'autoupdate.off': 'parx will not update itself. You will see a line when there is a new version; `parx update` installs it. /autoupdate on to turn it back on.',
|
|
225
|
+
'remoto.abriendo': 'Turning on remote control…',
|
|
226
|
+
'remoto.on': 'Remote control is on. Open this on your phone or any browser: {url}',
|
|
227
|
+
'remoto.escanea': 'Or scan it with your phone:',
|
|
228
|
+
'remoto.detalle': 'Everything still runs on this computer. Credentials and Bypass are only answered here.',
|
|
229
|
+
'remoto.siempre': 'Remote control will turn on every time parx opens on this computer. /remote off to stop.',
|
|
230
|
+
'remoto.off': 'Remote control is off on this computer.',
|
|
231
|
+
'remoto.no_disponible': 'Remote control is not available for your account yet.',
|
|
232
|
+
'remoto.sin_red': 'Could not turn on remote control: {motivo}. Try /remote again.',
|
|
233
|
+
'remoto.cortado_web': 'Remote control was turned off from the web.',
|
|
234
|
+
'remoto.sesion': 'Remote control stopped: sign in again with parx login.',
|
|
235
|
+
'remoto.demasiados': 'You already have 12 parx sessions with remote control open. Close one and try again.',
|
|
236
|
+
'remoto.del_movil': 'From your phone',
|
|
237
|
+
'remoto.desde_el_movil': 'from your phone',
|
|
238
|
+
'remoto.parado': 'Stopped from your phone.',
|
|
239
|
+
'remoto.solo_interactiva': 'Remote control works in an interactive session: run parx and then /remote.',
|
|
240
|
+
'mision.sugerencia': 'Next: /mission send it to my client · or announce it, or charge for it. It asks before sending anything.',
|
|
241
|
+
'vista.lista': 'Preview on your phone (updates after each task): {url}',
|
|
242
|
+
'vista.sin_remoto': 'Turn on /remote first: the preview opens from your phone.',
|
|
243
|
+
'vista.sin_web': 'No web to preview: there is no index.html here or in dist/, build/ or out/.',
|
|
244
|
+
'vista.no_subida': 'The preview could not be uploaded: {motivo}.',
|
|
245
|
+
'servicio.on': 'Your Mac is ready. From Sessions on your phone you can start a task in: {carpetas}. It starts again every time you log in.',
|
|
246
|
+
'servicio.off': 'The service is off. Your phone can no longer start tasks on this Mac.',
|
|
247
|
+
'servicio.anadida': 'Added {ruta}. Your phone can start tasks there.',
|
|
248
|
+
'servicio.no_anadida': '{ruta} cannot be added: it must be an existing folder, and not your whole home folder.',
|
|
249
|
+
'servicio.quitada': 'Removed {ruta}.',
|
|
250
|
+
'servicio.no_quitada': '{ruta} was not in the list.',
|
|
251
|
+
'servicio.estado': 'Service: {estado}. Folders: {lista}.',
|
|
252
|
+
'servicio.en_marcha': 'running',
|
|
253
|
+
'servicio.parado': 'off',
|
|
254
|
+
'servicio.ninguna': 'none',
|
|
255
|
+
'servicio.sin_carpetas': 'Add a folder first: go to a project folder and run parx service add.',
|
|
256
|
+
'servicio.solo_mac': 'The service is only for macOS for now.',
|
|
257
|
+
'servicio.registro': 'Log: {ruta}',
|
|
258
|
+
'servicio.uso': 'parx service on | off | add [folder] | remove <folder> | status',
|
|
217
259
|
'error.sin_saldo': 'You are out of Actions. Top up or upgrade at getparallel.net/settings/billing',
|
|
218
260
|
'error.sin_acceso': 'Your account does not have parx yet: it is in testing.',
|
|
219
261
|
'error.sesion': 'Your session expired. Run: parx login',
|
|
220
262
|
'error.red': 'Could not reach Parallel: {detalle}',
|
|
221
263
|
'error.servidor': 'Parallel could not answer right now ({detalle}). Try again.',
|
|
264
|
+
'error.ia': 'Parallel’s AI is temporarily unavailable. Your Actions weren’t charged. Try again in a minute.',
|
|
222
265
|
'error.demasiado': 'This conversation is too long. Type /new to start another one.',
|
|
223
266
|
'repl.adios': 'See you.',
|
|
224
267
|
'repl.registro': 'Log of this session: {ruta}',
|
|
@@ -300,6 +343,8 @@ export const COMANDOS = [
|
|
|
300
343
|
['model', 'Swift, Stride or Summit'],
|
|
301
344
|
['folder', 'Let parx work in another folder'],
|
|
302
345
|
['lanes', 'Run 2 or 3 tasks at once'],
|
|
346
|
+
['remote', 'Control this parx from your phone'],
|
|
347
|
+
['preview', 'See the web it is building on your phone'],
|
|
303
348
|
['mission', 'Keep it running on Parallel, phone alert when done'],
|
|
304
349
|
['missions', 'Pick a mission and control it from here'],
|
|
305
350
|
['inbox', 'Answer what your missions are waiting for'],
|
|
@@ -315,6 +360,7 @@ export const COMANDOS = [
|
|
|
315
360
|
['tips', 'Tips when it opens: on or off'],
|
|
316
361
|
['mouse', 'Clicks and wheel in parx: on or off'],
|
|
317
362
|
['animation', 'Answers written out as they arrive: on or off'],
|
|
363
|
+
['autoupdate', 'New versions install themselves: on or off'],
|
|
318
364
|
['log', 'Where the log of what it does is kept'],
|
|
319
365
|
['exit', 'Leave parx'],
|
|
320
366
|
];
|
|
@@ -325,6 +371,8 @@ export const ALIAS_COMANDO = {
|
|
|
325
371
|
strength: 'model',
|
|
326
372
|
folder: 'folder', 'add-folder': 'folder', carpeta: 'folder', dir: 'folder',
|
|
327
373
|
lanes: 'lanes', carriles: 'lanes',
|
|
374
|
+
remote: 'remote', 'remote-control': 'remote', rc: 'remote', remoto: 'remote', phone: 'remote',
|
|
375
|
+
preview: 'preview', vista: 'preview', previa: 'preview',
|
|
328
376
|
mission: 'mission', mision: 'mission', misión: 'mission',
|
|
329
377
|
missions: 'missions', misiones: 'missions',
|
|
330
378
|
inbox: 'inbox', bandeja: 'inbox', approvals: 'inbox', waiting: 'inbox',
|
|
@@ -333,6 +381,7 @@ export const ALIAS_COMANDO = {
|
|
|
333
381
|
settings: 'settings', ajustes: 'settings', preferences: 'settings',
|
|
334
382
|
mouse: 'mouse', raton: 'mouse', ratón: 'mouse',
|
|
335
383
|
animation: 'animation', animations: 'animation', animacion: 'animation', animación: 'animation',
|
|
384
|
+
autoupdate: 'autoupdate', 'auto-update': 'autoupdate', autoupdates: 'autoupdate', updates: 'autoupdate', autoactualizar: 'autoupdate',
|
|
336
385
|
report: 'report', informe: 'report',
|
|
337
386
|
teach: 'teach', class: 'teach', clase: 'teach',
|
|
338
387
|
undo: 'undo', deshacer: 'undo',
|
|
@@ -343,7 +392,7 @@ export const ALIAS_COMANDO = {
|
|
|
343
392
|
log: 'log', registro: 'log',
|
|
344
393
|
exit: 'exit', quit: 'exit', salir: 'exit',
|
|
345
394
|
};
|
|
346
|
-
export const ALIAS_DESDE = { strength: 2 };
|
|
395
|
+
export const ALIAS_DESDE = { strength: 2, rc: 2, phone: 3 };
|
|
347
396
|
export const ALIAS_SI_NO = {
|
|
348
397
|
on: 'si', yes: 'si', y: 'si', '1': 'si', si: 'si', 'sí': 'si',
|
|
349
398
|
off: 'no', no: 'no', n: 'no', '0': 'no',
|
|
@@ -354,7 +403,7 @@ export const USO = [
|
|
|
354
403
|
' parx "task" do the task and exit',
|
|
355
404
|
' parx --lanes "task" "task" ... 2 or 3 tasks at once, each in its own lane',
|
|
356
405
|
' parx login | logout | account',
|
|
357
|
-
' parx update
|
|
406
|
+
' parx update get the latest version now (parx also updates itself; /autoupdate off stops that)',
|
|
358
407
|
'',
|
|
359
408
|
'Options:',
|
|
360
409
|
' --mode ask|auto|read Ask (default), Auto inside the project, Read only',
|
|
@@ -366,6 +415,7 @@ export const USO = [
|
|
|
366
415
|
' --ascii plain characters only (also NO_COLOR for no color)',
|
|
367
416
|
' --no-mouse leave the mouse to the terminal (no clicks or wheel in parx)',
|
|
368
417
|
' --no-animation show answers whole, without writing them out',
|
|
418
|
+
' --remote control this session from your phone (same as /remote)',
|
|
369
419
|
' --version, --help',
|
|
370
420
|
'',
|
|
371
421
|
'Sign in:',
|
|
@@ -377,7 +427,18 @@ export const USO = [
|
|
|
377
427
|
' parx logout [--all] sign out here, or on every terminal',
|
|
378
428
|
' PARALLEL_API_KEY=par_key_… sign in with that key without saving anything (CI)',
|
|
379
429
|
'',
|
|
430
|
+
'Remote control:',
|
|
431
|
+
' /remote link and QR to control this parx from your phone or a browser',
|
|
432
|
+
' /remote always turn it on every time parx opens on this computer',
|
|
433
|
+
' /remote off turn it off here',
|
|
434
|
+
' parx service add let your phone start tasks in this folder (macOS)',
|
|
435
|
+
' parx service on keep your Mac ready at login, even with parx closed',
|
|
436
|
+
' parx service off | status stop it, or see how it is',
|
|
437
|
+
'',
|
|
380
438
|
'Updates:',
|
|
381
|
-
' parx checks npm
|
|
382
|
-
'
|
|
439
|
+
' parx checks npm every few hours, without slowing anything down, and installs new versions',
|
|
440
|
+
' itself: they are verified against npm’s signature and start with your next session.',
|
|
441
|
+
' /autoupdate off only tell me when there is one (then: parx update)',
|
|
442
|
+
' PARX_NO_AUTO_UPDATE=1 the same, from the environment',
|
|
443
|
+
' PARX_NO_UPDATE_CHECK=1 never even check',
|
|
383
444
|
].join('\n');
|
package/dist/tui.js
CHANGED
|
@@ -289,9 +289,9 @@ function teclaDeRaton(b, x, y, soltar, botonX10) {
|
|
|
289
289
|
}
|
|
290
290
|
export const RATON_SI = '\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1006h';
|
|
291
291
|
export const RATON_NO = '\x1b[?1003l\x1b[?1002l\x1b[?1000l\x1b[?1006l';
|
|
292
|
-
const CON_VALOR = new Set(['mode', 'model', 'tips', 'notify', 'teach', 'mouse', 'animation']);
|
|
292
|
+
const CON_VALOR = new Set(['mode', 'model', 'tips', 'notify', 'teach', 'mouse', 'animation', 'autoupdate', 'remote']);
|
|
293
293
|
const CON_TEXTO = new Set(['folder']);
|
|
294
|
-
const SE_MANDAN_SOLOS = new Set(['teach', 'notify', 'tips', 'folder', 'mouse', 'animation']);
|
|
294
|
+
const SE_MANDAN_SOLOS = new Set(['teach', 'notify', 'tips', 'folder', 'mouse', 'animation', 'autoupdate', 'remote']);
|
|
295
295
|
const MODOS_DEL_MENU = ['ask', 'auto', 'read', 'bypass'];
|
|
296
296
|
export function opcionesDelMenu(valor) {
|
|
297
297
|
if (!valor.startsWith('/') || valor.includes('\n'))
|
|
@@ -322,10 +322,16 @@ export function opcionesDelMenu(valor) {
|
|
|
322
322
|
? MODOS_DEL_MENU.map((k) => [k, tt(`modo.${k}.desc`)])
|
|
323
323
|
: cmd === 'model'
|
|
324
324
|
? ORDEN_DE_MODELOS.map((k) => [k, `${MODELOS[k].nombre} ${MODELOS[k].version}: ${MODELOS[k].descripcion}`])
|
|
325
|
-
:
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
325
|
+
: cmd === 'remote'
|
|
326
|
+
? [
|
|
327
|
+
['on', 'Link and QR for your phone, for this session'],
|
|
328
|
+
['always', 'Every time parx opens on this computer'],
|
|
329
|
+
['off', 'Stop remote control here'],
|
|
330
|
+
]
|
|
331
|
+
: [
|
|
332
|
+
['on', cmd === 'teach' ? 'Explain each step as it codes' : cmd === 'notify' ? 'Notify me when it finishes or needs me' : cmd === 'mouse' ? 'Click options, scroll with the wheel' : cmd === 'animation' ? 'Write answers out as they arrive' : cmd === 'autoupdate' ? 'New versions install themselves, for the next session' : 'Show them when parx opens'],
|
|
333
|
+
['off', cmd === 'teach' ? 'Back to normal' : cmd === 'notify' ? 'No desktop notifications' : cmd === 'mouse' ? 'The terminal selects and scrolls as usual' : cmd === 'animation' ? 'Show answers whole, at once' : cmd === 'autoupdate' ? 'Only tell me; I run parx update myself' : 'Don’t show them again'],
|
|
334
|
+
];
|
|
329
335
|
return valores
|
|
330
336
|
.filter(([v]) => v.startsWith(q))
|
|
331
337
|
.map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode' ? { modo: v, ...(v === 'bypass' ? { peligro: true } : {}) } : {}) }));
|
|
@@ -547,7 +553,7 @@ export function componerCarril(d, ancho, alto) {
|
|
|
547
553
|
cursor = null;
|
|
548
554
|
}
|
|
549
555
|
if (conPar)
|
|
550
|
-
filaEscribir += ` ${cabezaDePar()} `;
|
|
556
|
+
filaEscribir += ` ${cabezaDePar(d.gesto)} `;
|
|
551
557
|
const tinta = (t) => (bash ? c.bash(t) : c.violeta(t));
|
|
552
558
|
const linea = conPar ? `${tinta(carril(util - ANCHO_DE_PAR - 2))}${caraDePar(d.gesto)}${tinta(carril(2))}` : tinta(carril(util));
|
|
553
559
|
let barra;
|
|
@@ -1485,6 +1491,19 @@ export class Superficie {
|
|
|
1485
1491
|
this.ponerValor(texto);
|
|
1486
1492
|
this.enviar();
|
|
1487
1493
|
}
|
|
1494
|
+
mandarDesdeFuera(texto) {
|
|
1495
|
+
const t = /^[/!]/.test(texto.trimStart()) ? `\u2060${texto.trimStart()}` : texto;
|
|
1496
|
+
if (this.resolverLectura && !this.trabajo && !this.pregunta) {
|
|
1497
|
+
const r = this.resolverLectura;
|
|
1498
|
+
this.resolverLectura = null;
|
|
1499
|
+
this.irAlFondo();
|
|
1500
|
+
this.anadir(this.bloqueDeEnvio(t));
|
|
1501
|
+
r(t);
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
this.cola.push(t);
|
|
1505
|
+
this.mostrarAviso(this.cola.length > 1 ? tt('tui.en_cola_n', { n: this.cola.length }) : tt('tui.en_cola'));
|
|
1506
|
+
}
|
|
1488
1507
|
get libre() {
|
|
1489
1508
|
return Boolean(this.resolverLectura) && !this.trabajo && !this.pregunta;
|
|
1490
1509
|
}
|
|
@@ -1520,11 +1539,18 @@ export class Superficie {
|
|
|
1520
1539
|
actualizarCarriles() {
|
|
1521
1540
|
this.pintar();
|
|
1522
1541
|
}
|
|
1523
|
-
preguntar(texto, tipo = 'normal') {
|
|
1542
|
+
preguntar(texto, tipo = 'normal', externo) {
|
|
1524
1543
|
const o = opcionesDePregunta(tipo);
|
|
1525
1544
|
const peligro = tipo === 'bypass';
|
|
1526
1545
|
return new Promise((resolver) => {
|
|
1527
|
-
|
|
1546
|
+
let hecha = false;
|
|
1547
|
+
const contestar = (r) => {
|
|
1548
|
+
if (hecha)
|
|
1549
|
+
return;
|
|
1550
|
+
hecha = true;
|
|
1551
|
+
resolver(r);
|
|
1552
|
+
};
|
|
1553
|
+
const quitar = this.mostrarPregunta({
|
|
1528
1554
|
texto,
|
|
1529
1555
|
opciones: o.opciones,
|
|
1530
1556
|
cortas: o.cortas,
|
|
@@ -1532,7 +1558,13 @@ export class Superficie {
|
|
|
1532
1558
|
...(peligro ? { peligro: true } : {}),
|
|
1533
1559
|
indiceNo: o.valores.indexOf('no'),
|
|
1534
1560
|
siConY: o.valores[o.elegida] !== 'no' || peligro,
|
|
1535
|
-
}, (i) =>
|
|
1561
|
+
}, (i) => contestar(i === null ? 'no' : (o.valores[i] ?? 'no')));
|
|
1562
|
+
externo?.then((r) => {
|
|
1563
|
+
if (hecha || !o.valores.includes(r))
|
|
1564
|
+
return;
|
|
1565
|
+
contestar(r);
|
|
1566
|
+
quitar();
|
|
1567
|
+
});
|
|
1536
1568
|
});
|
|
1537
1569
|
}
|
|
1538
1570
|
elegir(texto, opciones, o = {}) {
|
|
@@ -1560,6 +1592,20 @@ export class Superficie {
|
|
|
1560
1592
|
this.esperando.push(mostrar);
|
|
1561
1593
|
else
|
|
1562
1594
|
mostrar();
|
|
1595
|
+
return () => {
|
|
1596
|
+
const i = this.esperando.indexOf(mostrar);
|
|
1597
|
+
if (i >= 0) {
|
|
1598
|
+
this.esperando.splice(i, 1);
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
if (this.pregunta?.resolver !== resolver)
|
|
1602
|
+
return;
|
|
1603
|
+
this.pregunta = null;
|
|
1604
|
+
this.sobre = null;
|
|
1605
|
+
this.pulsado = null;
|
|
1606
|
+
this.pintar();
|
|
1607
|
+
this.esperando.shift()?.();
|
|
1608
|
+
};
|
|
1563
1609
|
}
|
|
1564
1610
|
responder(i) {
|
|
1565
1611
|
const p = this.pregunta;
|
package/dist/ui.js
CHANGED
|
@@ -47,6 +47,7 @@ export class Pantalla {
|
|
|
47
47
|
esperaActiva = null;
|
|
48
48
|
trabajoEnLinea = null;
|
|
49
49
|
carril;
|
|
50
|
+
espejo = null;
|
|
50
51
|
tty;
|
|
51
52
|
constructor(rl, tty = Boolean(process.stdout.isTTY && process.stdin.isTTY), carril = null) {
|
|
52
53
|
this.rl = rl;
|
|
@@ -110,6 +111,8 @@ export class Pantalla {
|
|
|
110
111
|
this.pintarEnLinea();
|
|
111
112
|
}
|
|
112
113
|
escribir(linea = '', grupo = 'nota') {
|
|
114
|
+
if (linea.trim())
|
|
115
|
+
this.espejo?.evento('nota', { texto: sinColor(linea).trim() });
|
|
113
116
|
if (!linea.trim()) {
|
|
114
117
|
if (!this.terminaEnBlanco() && !this.carril)
|
|
115
118
|
this.bloque(() => [''], this.ultimoGrupo ?? 'nota');
|
|
@@ -119,6 +122,7 @@ export class Pantalla {
|
|
|
119
122
|
}
|
|
120
123
|
lecturas = null;
|
|
121
124
|
accion(verbo, objeto, nota = '') {
|
|
125
|
+
this.espejo?.evento('accion', { verbo: sinColor(verbo), objeto: sinColor(objeto), nota: sinColor(nota) });
|
|
122
126
|
if (this.superficie && verbo === t('herr.leer')) {
|
|
123
127
|
const l = this.lecturas;
|
|
124
128
|
if (l && this.superficie.ultimoBloque() === l.bloque) {
|
|
@@ -146,6 +150,7 @@ export class Pantalla {
|
|
|
146
150
|
.filter((l) => l.trim() !== '' && !RELLENO_DE_TESTS.test(l));
|
|
147
151
|
if (!lineas.length)
|
|
148
152
|
return;
|
|
153
|
+
this.espejo?.evento('salida', { lineas: lineas.slice(-6).map((l) => sinColor(l)) });
|
|
149
154
|
const ultimas = lineas.slice(-maxLineas);
|
|
150
155
|
const sobran = lineas.length - ultimas.length;
|
|
151
156
|
this.bloque((ancho) => {
|
|
@@ -160,15 +165,19 @@ export class Pantalla {
|
|
|
160
165
|
}, 'accion');
|
|
161
166
|
}
|
|
162
167
|
detalle(texto, error = false) {
|
|
168
|
+
this.espejo?.evento('detalle', { texto: sinColor(texto), error });
|
|
163
169
|
this.bloque((ancho) => [`${' '.repeat(MARGEN + sangriaDeDetalle())}${recortar(error ? c.error(`${SIMBOLOS.falla} ${texto}`) : c.gris(texto), anchoUtil(ancho) - sangriaDeDetalle())}`], 'accion');
|
|
164
170
|
}
|
|
165
171
|
aviso(texto) {
|
|
172
|
+
this.espejo?.evento('aviso', { texto: sinColor(texto) });
|
|
166
173
|
this.bloque(bloqueDeTexto(`${c.aviso('!')} ${texto}`, ' '), 'aviso');
|
|
167
174
|
}
|
|
168
175
|
error(texto) {
|
|
176
|
+
this.espejo?.evento('error', { texto: sinColor(texto) });
|
|
169
177
|
this.bloque(bloqueDeTexto(`${c.error(SIMBOLOS.falla)} ${texto}`, ' '), 'error');
|
|
170
178
|
}
|
|
171
179
|
cierre(texto) {
|
|
180
|
+
this.espejo?.evento('cierre', { texto: sinColor(texto) });
|
|
172
181
|
this.bloque(bloqueDeCierre(texto, c.ok(SIMBOLOS.hecho)), 'cierre');
|
|
173
182
|
}
|
|
174
183
|
trabajoPropio() {
|
|
@@ -205,6 +214,7 @@ export class Pantalla {
|
|
|
205
214
|
process.stdout.write(`\r\x1b[2K${' '.repeat(MARGEN)}${recortar(filaDeTrabajo(this.trabajoEnLinea, Date.now()), ancho - MARGEN - 2)}`);
|
|
206
215
|
}
|
|
207
216
|
progreso(acciones) {
|
|
217
|
+
this.espejo?.progreso(acciones);
|
|
208
218
|
if (this.carril) {
|
|
209
219
|
this.carril.trabajo.acciones = acciones;
|
|
210
220
|
this.superficie?.actualizarCarriles();
|
|
@@ -236,6 +246,10 @@ export class Pantalla {
|
|
|
236
246
|
}
|
|
237
247
|
diff(lineas, max = 40) {
|
|
238
248
|
const visibles = trozos(lineas);
|
|
249
|
+
this.espejo?.evento('diff', {
|
|
250
|
+
lineas: visibles.slice(0, 40).map((l) => (l === null ? { tipo: '⋮', texto: '' } : { tipo: l.tipo, texto: l.texto, num: l.despues ?? l.antes ?? null })),
|
|
251
|
+
mas: Math.max(0, visibles.length - 40),
|
|
252
|
+
});
|
|
239
253
|
this.bloque((ancho) => {
|
|
240
254
|
const s = sangriaDeDetalle();
|
|
241
255
|
const util = anchoUtil(ancho) - s;
|
|
@@ -270,7 +284,21 @@ export class Pantalla {
|
|
|
270
284
|
this.aviso(o.aviso);
|
|
271
285
|
const texto = this.carril ? `${t('carriles.carril', { n: this.carril.numero })}: ${pregunta}` : pregunta;
|
|
272
286
|
if (this.superficie) {
|
|
273
|
-
const
|
|
287
|
+
const op = opcionesDePregunta(tipo);
|
|
288
|
+
const remota = this.espejo?.preguntaRemota(sinColor(texto), tipo, op.opciones.map((etiqueta, i) => ({ etiqueta, valor: op.valores[i] }))) ?? null;
|
|
289
|
+
let desdeFuera = false;
|
|
290
|
+
const externo = remota?.deFuera?.then((r) => {
|
|
291
|
+
desdeFuera = true;
|
|
292
|
+
return r;
|
|
293
|
+
});
|
|
294
|
+
const r = await this.superficie.preguntar(texto, tipo, externo);
|
|
295
|
+
remota?.contestada(r, desdeFuera ? 'movil' : 'ordenador');
|
|
296
|
+
if (desdeFuera) {
|
|
297
|
+
const o2 = opcionesDePregunta(tipo);
|
|
298
|
+
const etiqueta = o2.opciones[o2.valores.indexOf(r)] ?? t('tui.no');
|
|
299
|
+
this.bloque(bloqueDeTexto(`${c.gris('?')} ${texto} ${c.gris('→')} ${r === 'no' ? c.gris(etiqueta) : c.marca(etiqueta)} ${c.gris(`· ${t('remoto.desde_el_movil')}`)}`, ' '), 'aviso');
|
|
300
|
+
return r;
|
|
301
|
+
}
|
|
274
302
|
if (r !== 'si' && tipo !== 'bypass') {
|
|
275
303
|
const o2 = opcionesDePregunta(tipo);
|
|
276
304
|
const etiqueta = o2.opciones[o2.valores.indexOf(r)] ?? t('tui.no');
|
|
@@ -280,6 +308,16 @@ export class Pantalla {
|
|
|
280
308
|
}
|
|
281
309
|
this.pausarLinea();
|
|
282
310
|
if (!this.tty || !this.rl) {
|
|
311
|
+
if (this.espejo) {
|
|
312
|
+
const op = opcionesDePregunta(tipo);
|
|
313
|
+
const remota = this.espejo.preguntaRemota(sinColor(texto), tipo, op.opciones.map((etiqueta, i) => ({ etiqueta, valor: op.valores[i] })));
|
|
314
|
+
if (remota.deFuera) {
|
|
315
|
+
const r = await remota.deFuera;
|
|
316
|
+
remota.contestada(r, 'movil');
|
|
317
|
+
return r;
|
|
318
|
+
}
|
|
319
|
+
remota.contestada('no', 'ordenador');
|
|
320
|
+
}
|
|
283
321
|
this.aviso(`${texto} → ${t('aviso.rechazado')}`);
|
|
284
322
|
return 'no';
|
|
285
323
|
}
|
|
@@ -293,6 +331,10 @@ export class Pantalla {
|
|
|
293
331
|
}
|
|
294
332
|
}
|
|
295
333
|
texto(md) {
|
|
334
|
+
this.espejo?.evento('texto', { md });
|
|
335
|
+
this.pintarTexto(md);
|
|
336
|
+
}
|
|
337
|
+
pintarTexto(md) {
|
|
296
338
|
this.terminarRevelado();
|
|
297
339
|
this.bloque(bloqueDeMarkdown(md), 'texto');
|
|
298
340
|
}
|
|
@@ -304,10 +346,11 @@ export class Pantalla {
|
|
|
304
346
|
f?.();
|
|
305
347
|
}
|
|
306
348
|
textoAnimado(md, o = {}) {
|
|
349
|
+
this.espejo?.evento('texto', { md });
|
|
307
350
|
this.terminarRevelado();
|
|
308
351
|
const conSuperficie = this.superficie !== null;
|
|
309
352
|
if (!this.animar || this.carril || !this.tty || (!conSuperficie && !process.stdout.isTTY)) {
|
|
310
|
-
this.
|
|
353
|
+
this.pintarTexto(md);
|
|
311
354
|
return Promise.resolve();
|
|
312
355
|
}
|
|
313
356
|
const completo = bloqueDeMarkdown(md);
|