@getparallel/parx 0.7.0 → 0.9.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 CHANGED
@@ -6,6 +6,14 @@ changes). Entries are generated by `npm run release` from the git history of `ap
6
6
 
7
7
  <!-- Notes written under «## Unreleased» are used as the next entry instead of the git log. -->
8
8
 
9
+ ## 0.9.0 (2026-10-18)
10
+
11
+ - Al acabar una tarea que cambia la web, la abre, enseña los enlaces y pregunta si la publica
12
+
13
+ ## 0.8.0 (2026-10-18)
14
+
15
+ - Publicar desde parx (t464): la web construida con parx sale en <nombre>.getparallel.net o en su dominio
16
+
9
17
  ## 0.7.0 (2026-10-18)
10
18
 
11
19
  - Un paso corto ya no tumba el plan; «Llévalo a tu negocio» lleva a la misión en marcha y sin palabras que disparen la plantilla de clientes
package/dist/api.js CHANGED
@@ -131,6 +131,9 @@ export function ordenesRemotas(servidor, token, id, esperaMs, señal) {
131
131
  export function subirVistaRemota(servidor, token, id, cuerpo) {
132
132
  return llamar(servidor, `/api/terminal/remoto/${encodeURIComponent(id)}/vista`, { token, cuerpo, plazoMs: 60_000 });
133
133
  }
134
+ export function publicarWebRemota(servidor, token, id) {
135
+ return llamar(servidor, `/api/terminal/remoto/${encodeURIComponent(id)}/publicar`, { token, cuerpo: {}, plazoMs: 90_000 });
136
+ }
134
137
  export function cerrarRemoto(servidor, token, id, plazoMs = 3000) {
135
138
  return llamar(servidor, `/api/terminal/remoto/${encodeURIComponent(id)}`, { token, metodo: 'DELETE', plazoMs });
136
139
  }
package/dist/cli.js CHANGED
@@ -2,14 +2,15 @@
2
2
  import { createInterface } from 'node:readline/promises';
3
3
  import { existsSync, statSync } from 'node:fs';
4
4
  import { homedir, hostname } from 'node:os';
5
- import { basename, resolve } from 'node:path';
5
+ import { basename, join, resolve } from 'node:path';
6
+ import { pathToFileURL } from 'node:url';
6
7
  import { parseArgs } from 'node:util';
7
8
  import { randomUUID } from 'node:crypto';
8
9
  import { ALIAS_COMANDO, ALIAS_SI_NO, COMANDOS, t, USO } from "./textos.js";
9
10
  import { c, capacidades, colorDeModo, fijarCapacidades, sep, signo, sinColor, SIMBOLOS } from "./marca.js";
10
11
  import { guardarAjustes, leerAjustes, migrarCarpetaVieja, VERSION } from "./config.js";
11
12
  import { MODELO_POR_DEFECTO, MODELOS, modeloDe, nombreDeModelo } from "./modelos.js";
12
- import { cicloDeMision, compartirMision, correoVisible, crearMision, equipo, ErrorDeParallel, leerBandeja, leerConexiones, leerCuenta, leerMisionDeLaCuenta, leerMisiones, leerPlantillas, quienEs, responderBandeja, verMision, } from "./api.js";
13
+ import { cicloDeMision, compartirMision, correoVisible, crearMision, equipo, ErrorDeParallel, leerBandeja, leerConexiones, leerCuenta, leerMisionDeLaCuenta, leerMisiones, leerPlantillas, quienEs, responderBandeja, verMision, publicarWebRemota, } from "./api.js";
13
14
  import { abrirNavegador, comoHasEntrado, credencialesActivas, entrar, formaDeLaOpcion, salir } from "./cuenta.js";
14
15
  import { accionesDeUnaMision, filtrarPorTitulo, hace } from "./comandos.js";
15
16
  import { hacerTarea, mensajeDeError, nuevaSesion, reiniciarConversacion } from "./agente.js";
@@ -17,7 +18,7 @@ import { deshacerUltimo, permitirCarpeta } from "./herramientas.js";
17
18
  import { Registro } from "./registro.js";
18
19
  import { Pantalla } from "./ui.js";
19
20
  import { Remoto } from "./remoto.js";
20
- import { VistaPrevia } from "./vista.js";
21
+ import { VistaPrevia, raizWeb, recogerWeb } from "./vista.js";
21
22
  import { anadirCarpeta, carpetasDelServicio, instalarServicio, quitarCarpeta, quitarServicio, reiniciarServicio, rutaDelRegistro, servicioEnMarcha, servicioInstalado, servir } from "./servicio.js";
22
23
  import { qrEnTexto } from "./qr.js";
23
24
  import { acciones, bloqueDeBienvenida, bloqueDeLaPersona, bloqueDeTabla, duracion, Superficie } from "./tui.js";
@@ -381,6 +382,60 @@ async function principal() {
381
382
  return { error: e instanceof ErrorDeParallel ? e.codigo : 'red' };
382
383
  }
383
384
  };
385
+ const webDelProyecto = () => {
386
+ const w = raizWeb(raiz);
387
+ if (!w)
388
+ return null;
389
+ const lista = recogerWeb(w.abs);
390
+ if (!lista.some((a) => a.ruta === 'index.html'))
391
+ return null;
392
+ return { ...w, huella: lista.map((a) => `${a.ruta}:${a.hash}`).join('\n') };
393
+ };
394
+ let huellaWeb = webDelProyecto()?.huella ?? null;
395
+ let webPublicada = null;
396
+ const publicarLaWeb = async () => {
397
+ if (!remoto?.encendido)
398
+ await encenderRemoto(false);
399
+ const r0 = remoto;
400
+ if (!r0?.encendido || !r0.id) {
401
+ pantalla.escribir(t('publicar.sin_remoto'));
402
+ return;
403
+ }
404
+ const subida = await actualizarVista(true);
405
+ if (!subida) {
406
+ pantalla.escribir(t('vista.sin_web'));
407
+ return;
408
+ }
409
+ if ('error' in subida) {
410
+ pantalla.error(t('vista.no_subida', { motivo: subida.error }));
411
+ return;
412
+ }
413
+ try {
414
+ const p = await publicarWebRemota(cred.servidor, cred.token, r0.id);
415
+ webPublicada = { url: p.url };
416
+ pantalla.escribir(t('publicar.lista', { url: c.marca(p.url) }));
417
+ abrirNavegador(p.url);
418
+ }
419
+ catch (e) {
420
+ pantalla.error(t('publicar.error', { motivo: e instanceof ErrorDeParallel ? `${e.codigo}${e.detalle ? ` ${e.detalle}` : ''}` : 'red' }));
421
+ }
422
+ };
423
+ const ofrecerLaWeb = async (w) => {
424
+ const local = pathToFileURL(join(w.abs, 'index.html')).href;
425
+ abrirNavegador(local);
426
+ soloAqui(() => pantalla.escribir(t('web.lista', { url: c.marca(local) })));
427
+ if (remoto?.encendido) {
428
+ const r = await actualizarVista(true);
429
+ if (r && !('error' in r))
430
+ soloAqui(() => pantalla.escribir(c.gris(t('web.en_el_movil', { url: r.url }))));
431
+ }
432
+ const r = await pantalla.preguntar(webPublicada ? t('web.publicar_otra_vez', { url: webPublicada.url }) : t('web.publicar_pregunta'), { tipo: 'dos' });
433
+ if (r === 'no') {
434
+ soloAqui(() => pantalla.escribir(c.gris(t('web.luego'))));
435
+ return;
436
+ }
437
+ await publicarLaWeb();
438
+ };
384
439
  let bienvenida;
385
440
  let consejosDeEntrada = [];
386
441
  const confirmarNuevaEnMarcha = async () => {
@@ -476,8 +531,14 @@ async function principal() {
476
531
  superficie?.descansar();
477
532
  remoto?.fijarEstado('libre', null);
478
533
  }
479
- if (remoto?.encendido)
534
+ const web = superficie ? webDelProyecto() : null;
535
+ if (web && web.huella !== huellaWeb) {
536
+ huellaWeb = web.huella;
537
+ await ofrecerLaWeb(web);
538
+ }
539
+ else if (remoto?.encendido) {
480
540
  void actualizarVista();
541
+ }
481
542
  if (!sugeridaMision && sesion.diario.some((d) => d.ficheros.length) && superficie) {
482
543
  sugeridaMision = true;
483
544
  soloAqui(() => pantalla.escribir(c.gris(t('mision.sugerencia'))));
@@ -1341,6 +1402,8 @@ async function principal() {
1341
1402
  break;
1342
1403
  }
1343
1404
  case 'preview': {
1405
+ if (!remoto?.encendido)
1406
+ await encenderRemoto(false);
1344
1407
  if (!remoto?.encendido) {
1345
1408
  pantalla.escribir(t('vista.sin_remoto'));
1346
1409
  break;
@@ -1354,6 +1417,10 @@ async function principal() {
1354
1417
  pantalla.escribir(t('vista.lista', { url: c.marca(r.url) }));
1355
1418
  break;
1356
1419
  }
1420
+ case 'publish': {
1421
+ await publicarLaWeb();
1422
+ break;
1423
+ }
1357
1424
  case 'autoupdate': {
1358
1425
  const si = ALIAS_SI_NO[arg] ?? (autoactualizarApagada() ? 'si' : 'no');
1359
1426
  guardarAjustes({ autoactualizar: si === 'si' });
package/dist/textos.js CHANGED
@@ -238,10 +238,18 @@ export const TEXTOS = {
238
238
  'remoto.parado': 'Stopped from your phone.',
239
239
  'remoto.solo_interactiva': 'Remote control works in an interactive session: run parx and then /remote.',
240
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}',
241
+ 'vista.lista': 'Preview on your phone (updates after each task): {url} · /publish puts it online.',
242
242
  'vista.sin_remoto': 'Turn on /remote first: the preview opens from your phone.',
243
243
  'vista.sin_web': 'No web to preview: there is no index.html here or in dist/, build/ or out/.',
244
244
  'vista.no_subida': 'The preview could not be uploaded: {motivo}.',
245
+ 'publicar.lista': 'Live at {url} · the same address every time you /publish. Your own domain: from Sessions on your phone.',
246
+ 'publicar.sin_remoto': 'Publishing needs /remote (your Parallel account) and it could not be turned on.',
247
+ 'publicar.error': 'Could not publish: {motivo}.',
248
+ 'web.lista': 'Your web is ready and open in your browser: {url}',
249
+ 'web.en_el_movil': 'On your phone: {url}',
250
+ 'web.publicar_pregunta': 'Publish it online? It gets an address like name.getparallel.net, with HTTPS.',
251
+ 'web.publicar_otra_vez': 'Publish the new version at {url}?',
252
+ 'web.luego': 'Not published. Whenever you want: /publish.',
245
253
  '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
254
  'servicio.off': 'The service is off. Your phone can no longer start tasks on this Mac.',
247
255
  'servicio.anadida': 'Added {ruta}. Your phone can start tasks there.',
@@ -345,6 +353,7 @@ export const COMANDOS = [
345
353
  ['lanes', 'Run 2 or 3 tasks at once'],
346
354
  ['remote', 'Control this parx from your phone'],
347
355
  ['preview', 'See the web it is building on your phone'],
356
+ ['publish', 'Put the web online at name.getparallel.net'],
348
357
  ['mission', 'Keep it running on Parallel, phone alert when done'],
349
358
  ['missions', 'Pick a mission and control it from here'],
350
359
  ['inbox', 'Answer what your missions are waiting for'],
@@ -373,6 +382,7 @@ export const ALIAS_COMANDO = {
373
382
  lanes: 'lanes', carriles: 'lanes',
374
383
  remote: 'remote', 'remote-control': 'remote', rc: 'remote', remoto: 'remote', phone: 'remote',
375
384
  preview: 'preview', vista: 'preview', previa: 'preview',
385
+ publish: 'publish', publica: 'publish', publicar: 'publish', deploy: 'publish', online: 'publish',
376
386
  mission: 'mission', mision: 'mission', misión: 'mission',
377
387
  missions: 'missions', misiones: 'missions',
378
388
  inbox: 'inbox', bandeja: 'inbox', approvals: 'inbox', waiting: 'inbox',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getparallel/parx",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "parx: the coding agent of Parallel in your terminal. Reads and edits your project, runs commands and tests, and does coding tasks end to end. Mac, Windows and Linux.",
5
5
  "keywords": [
6
6
  "parx",