@getparallel/parx 0.4.2 → 0.4.3

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,10 @@ 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.4.3 (2026-10-11)
10
+
11
+ - Each permission mode has its own colour, from least to most freedom: Read only teal, Ask violet, Auto orange, Bypass red. It shows in the status row, the `/mode` menu, the `/mode` confirmation, `/help` and the `╱╱` input marker; bash mode keeps its amber.
12
+
9
13
  ## 0.4.2 (2026-10-11)
10
14
 
11
15
  - Bash mode: type `!` first and the input turns amber with a `bash` label; Enter runs the command in the project folder, its output streams into the conversation with the exit code, and the agent sees it next turn. Read only refuses, «Careful» commands ask first, credentials stay out of the conversation, Esc or Ctrl+C stops it.
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ 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, fijarCapacidades, sep, signo, SIMBOLOS } from "./marca.js";
9
+ import { c, colorDeModo, fijarCapacidades, sep, signo, 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
12
  import { correoVisible, crearMision, ErrorDeParallel, leerBandeja, leerCuenta, quienEs, responderBandeja, verMision } from "./api.js";
@@ -85,8 +85,12 @@ export function modoDe(texto) {
85
85
  return tabla[v] ?? null;
86
86
  }
87
87
  export const SIGUIENTE_MODO = { ask: 'auto', auto: 'read', read: 'ask', bypass: 'ask' };
88
+ export function modosEnColor() {
89
+ const nombres = ['read', 'ask', 'auto', 'bypass'].map((m) => colorDeModo(m)(nombreDeModo(m)));
90
+ return `${nombres.slice(0, 3).join(', ')} or ${nombres[3]}`;
91
+ }
88
92
  function ayudaDeComandos() {
89
- return bloqueDeTabla([['!', t('tip.bash')], ...COMANDOS.map(([k, d]) => [`/${k}`, d])], { pie: `${t('tui.atajos')}\n${t('tui.atajos_raton')}` });
93
+ return bloqueDeTabla([['!', t('tip.bash')], ...COMANDOS.map(([k, d]) => [`/${k}`, k === 'mode' ? modosEnColor() : d])], { pie: `${t('tui.atajos')}\n${t('tui.atajos_raton')}` });
90
94
  }
91
95
  async function cuentaOError(cred, pantalla) {
92
96
  try {
@@ -393,6 +397,7 @@ async function principal() {
393
397
  saldo: saldo(),
394
398
  saldoCorto: saldoCorto(),
395
399
  peligro: sesion.ctx.modo === 'bypass',
400
+ clave: sesion.ctx.modo,
396
401
  extra: sesion.ensenar ? 'Teach' : undefined,
397
402
  esperando: esperandoEnBandeja ?? 0,
398
403
  });
@@ -662,7 +667,7 @@ async function principal() {
662
667
  guardarAjustes({ modo: m });
663
668
  registro.apuntar('modo', { modo: m });
664
669
  }
665
- pantalla.escribir(t('modo.ahora', { modo: nombreDeModo(sesion.ctx.modo), desc: t(`modo.${sesion.ctx.modo}.desc`) }));
670
+ pantalla.escribir(t('modo.ahora', { modo: colorDeModo(sesion.ctx.modo)(c.negrita(nombreDeModo(sesion.ctx.modo))), desc: t(`modo.${sesion.ctx.modo}.desc`) }));
666
671
  superficie?.pintar();
667
672
  break;
668
673
  }
package/dist/marca.js CHANGED
@@ -40,6 +40,10 @@ const PALETA = {
40
40
  verdeDiff: [80, 200, 120],
41
41
  rojoDiff: [240, 100, 100],
42
42
  peligro: [255, 69, 58],
43
+ modoRead: [29, 161, 181],
44
+ modoAsk: [139, 112, 255],
45
+ modoAuto: [242, 107, 29],
46
+ bash: [245, 166, 35],
43
47
  };
44
48
  const ANSI256 = {
45
49
  violeta: 99,
@@ -52,6 +56,10 @@ const ANSI256 = {
52
56
  verdeDiff: 78,
53
57
  rojoDiff: 203,
54
58
  peligro: 196,
59
+ modoRead: 37,
60
+ modoAsk: 99,
61
+ modoAuto: 202,
62
+ bash: 214,
55
63
  };
56
64
  const ANSI16 = {
57
65
  violeta: 35,
@@ -64,6 +72,10 @@ const ANSI16 = {
64
72
  verdeDiff: 32,
65
73
  rojoDiff: 31,
66
74
  peligro: 91,
75
+ modoRead: 36,
76
+ modoAsk: 35,
77
+ modoAuto: 33,
78
+ bash: 93,
67
79
  };
68
80
  function pintar(nombre, texto) {
69
81
  const { color } = caps;
@@ -88,10 +100,16 @@ export const c = {
88
100
  mas: (t) => pintar('verdeDiff', t),
89
101
  menos: (t) => pintar('rojoDiff', t),
90
102
  peligro: (t) => pintar('peligro', t),
103
+ bash: (t) => pintar('bash', t),
91
104
  negrita: (t) => (caps.color ? `\x1b[1m${t}\x1b[22m` : t),
92
105
  tenue: (t) => (caps.color ? `\x1b[2m${t}\x1b[22m` : t),
93
106
  boton: (t, peligro = false) => fondo(peligro ? 'peligro' : 'violeta', t),
94
107
  };
108
+ const TINTA_DE_MODO = { read: 'modoRead', ask: 'modoAsk', auto: 'modoAuto', bypass: 'peligro' };
109
+ export function colorDeModo(modo) {
110
+ const nombre = TINTA_DE_MODO[modo];
111
+ return (t) => pintar(nombre, t);
112
+ }
95
113
  function fondo(nombre, texto) {
96
114
  const { color } = caps;
97
115
  if (color === 0)
package/dist/tui.js CHANGED
@@ -1,4 +1,4 @@
1
- import { animacion, c, capacidades, sep, cabezaDePar, caraDePar, carril, fijarCapacidades, signo, ANCHO_DE_PAR, SIMBOLOS } from "./marca.js";
1
+ import { animacion, c, capacidades, colorDeModo, sep, cabezaDePar, caraDePar, carril, fijarCapacidades, signo, ANCHO_DE_PAR, SIMBOLOS } from "./marca.js";
2
2
  import { anchoDe, envolver, puntos, recortar, rellenar } from "./texto.js";
3
3
  import { ALIAS_COMANDO, COMANDOS, t as tt } from "./textos.js";
4
4
  import { MODELOS, ORDEN_DE_MODELOS } from "./modelos.js";
@@ -138,13 +138,13 @@ export function bloqueDeCierre(texto, marca) {
138
138
  export function bloqueDeBash(comando) {
139
139
  return (ancho) => {
140
140
  const util = anchoUtil(ancho);
141
- return ['', ...envolver(comando, util - 2).map((l, i) => `${m}${i === 0 ? c.aviso(c.negrita('!')) : ' '} ${l}`)];
141
+ return ['', ...envolver(comando, util - 2).map((l, i) => `${m}${i === 0 ? c.bash(c.negrita('!')) : ' '} ${l}`)];
142
142
  };
143
143
  }
144
144
  export function bloqueDeSalidaDeBash(lineas) {
145
145
  return (ancho) => {
146
146
  const util = anchoUtil(ancho);
147
- const raya = c.tenue(c.aviso(capacidades().unicode ? '│' : '|'));
147
+ const raya = c.tenue(c.bash(capacidades().unicode ? '│' : '|'));
148
148
  return lineas.map((l) => `${m}${raya} ${recortar(l.replace(/\t/g, ' '), util - 2)}`);
149
149
  };
150
150
  }
@@ -152,7 +152,7 @@ export function bloqueDeFinDeBash(bien, texto) {
152
152
  return (ancho) => {
153
153
  const u = capacidades().unicode;
154
154
  const marca = bien ? c.ok(u ? '✓' : 'v') : c.error(u ? '✗' : 'x');
155
- return [`${m}${c.tenue(c.aviso(u ? '╰' : '`'))} ${marca} ${recortar(c.gris(texto), anchoUtil(ancho) - 4)}`];
155
+ return [`${m}${c.tenue(c.bash(u ? '╰' : '`'))} ${marca} ${recortar(c.gris(texto), anchoUtil(ancho) - 4)}`];
156
156
  };
157
157
  }
158
158
  export function trocearTeclas(datos, estado) {
@@ -326,7 +326,7 @@ export function opcionesDelMenu(valor) {
326
326
  ];
327
327
  return valores
328
328
  .filter(([v]) => v.startsWith(q))
329
- .map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode' && v === 'bypass' ? { peligro: true } : {}) }));
329
+ .map(([v, d]) => ({ nombre: v, descripcion: d, completar: `${base}${v}`, enviar: true, ...(cmd === 'mode' ? { modo: v, ...(v === 'bypass' ? { peligro: true } : {}) } : {}) }));
330
330
  }
331
331
  export function componerBarra(e, util) {
332
332
  return componerBarraConZonas(e, util).texto;
@@ -334,7 +334,8 @@ export function componerBarra(e, util) {
334
334
  export function componerBarraConZonas(e, util) {
335
335
  const u = capacidades().unicode;
336
336
  const punto = c.gris(sep());
337
- const modo = e.peligro ? c.aviso(c.negrita(`${u ? '▲' : '!'} ${e.modo}`)) : c.gris(e.modo);
337
+ const tinta = e.clave ? colorDeModo(e.clave) : e.peligro ? c.peligro : c.gris;
338
+ const modo = e.peligro ? tinta(c.negrita(`${u ? '▲' : '!'} ${e.modo}`)) : tinta(e.modo);
338
339
  const extra = e.extra ? `${punto}${c.marca(e.extra)}` : '';
339
340
  const n = e.esperando ?? 0;
340
341
  const espera = n ? c.aviso(`${u ? '●' : '*'} ${tt('bandeja.esperando', { n })}`) : '';
@@ -515,8 +516,8 @@ export function componerCarril(d, ancho, alto) {
515
516
  const anchoEscribir = util - (conPar ? huecoPar + 1 : 0);
516
517
  {
517
518
  const libre = Math.max(4, anchoEscribir - signoW);
518
- const color = d.trabajo || d.pregunta ? c.gris : c.claro;
519
- const marca = bash ? c.aviso(c.negrita('!')) : color(signo());
519
+ const color = d.trabajo || d.pregunta ? c.gris : d.estado.clave ? colorDeModo(d.estado.clave) : c.claro;
520
+ const marca = bash ? c.bash(c.negrita('!')) : color(signo());
520
521
  const unidades = bash ? d.unidades.slice(1) : d.unidades;
521
522
  const enCursor = bash ? Math.max(0, d.cursor - 1) : d.cursor;
522
523
  if (!unidades.length) {
@@ -534,7 +535,7 @@ export function componerCarril(d, ancho, alto) {
534
535
  }
535
536
  if (conPar)
536
537
  filaEscribir += ` ${cabezaDePar()} `;
537
- const tinta = (t) => (bash ? c.aviso(t) : c.violeta(t));
538
+ const tinta = (t) => (bash ? c.bash(t) : c.violeta(t));
538
539
  const linea = conPar ? `${tinta(carril(util - ANCHO_DE_PAR - 2))}${caraDePar(d.gesto)}${tinta(carril(2))}` : tinta(carril(util));
539
540
  let barra;
540
541
  let zonasBarra = [];
@@ -553,7 +554,7 @@ export function componerCarril(d, ancho, alto) {
553
554
  barra = izquierdaYDerecha(c.aviso(recortar(d.aviso, util)), '', util);
554
555
  }
555
556
  else if (bash) {
556
- const etiqueta = c.aviso(c.negrita(tt('bash.etiqueta')));
557
+ const etiqueta = c.bash(c.negrita(tt('bash.etiqueta')));
557
558
  const largo = `${etiqueta}${c.gris(`${sep()}${tt('bash.intro')}`)}`;
558
559
  barra = izquierdaYDerecha(anchoDe(largo) + anchoDe(d.estado.saldoCorto ?? '') + 2 <= util ? largo : etiqueta, c.gris(d.estado.saldoCorto ?? ''), util);
559
560
  }
@@ -641,7 +642,8 @@ export function componerCarril(d, ancho, alto) {
641
642
  const sel = i === d.menu.elegida;
642
643
  const sobre = d.sobre === `menu:${i}`;
643
644
  zonasEncima.push({ fila: k, desde: MARGEN, hasta: MARGEN + util, id: `menu:${i}` });
644
- const marca = sel ? (o.peligro ? c.peligro : c.claro)(u ? '▌' : '>') : ' ';
645
+ const tinta = o.modo ? colorDeModo(o.modo) : o.peligro ? c.peligro : c.claro;
646
+ const marca = sel ? tinta(u ? '▌' : '>') : ' ';
645
647
  const resto = Math.max(0, util - 2 - anchoNombre);
646
648
  const desc = recortar(o.descripcion, resto);
647
649
  if (o.peligro) {
@@ -649,6 +651,8 @@ export function componerCarril(d, ancho, alto) {
649
651
  return `${m}${rellenar(`${marca} ${sel || sobre ? c.negrita(c.peligro(nombre)) : c.peligro(nombre)}${sel ? c.peligro(desc) : c.tenue(c.peligro(desc))}`, util)}`;
650
652
  }
651
653
  const nombre = rellenar(recortar(o.nombre, anchoNombre - 1), anchoNombre);
654
+ if (o.modo)
655
+ return `${m}${rellenar(`${marca} ${sel || sobre ? c.negrita(tinta(nombre)) : tinta(nombre)}${sel || sobre ? desc : c.tenue(c.gris(desc))}`, util)}`;
652
656
  return `${m}${rellenar(`${marca} ${sel ? c.negrita(c.marca(nombre)) : sobre ? c.marca(nombre) : c.gris(nombre)}${sel || sobre ? desc : c.tenue(c.gris(desc))}`, util)}`;
653
657
  });
654
658
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getparallel/parx",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
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",