@getparallel/parx 0.0.0-stage → 0.4.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/dist/ui.js ADDED
@@ -0,0 +1,287 @@
1
+ import { animacion, c, capacidades, SIMBOLOS } from "./marca.js";
2
+ import { t } from "./textos.js";
3
+ import { trozos } from "./diff.js";
4
+ import { anchoDe, envolver, recortar, recortarMedio, rellenar, sinColor } from "./texto.js";
5
+ import { anchoUtil, bloqueDeCierre, bloqueDeLinea, bloqueDeTexto, filaDeTrabajo, MARGEN, nuevoTrabajo, opcionesDePregunta, ponerTextoDeTrabajo, } from "./tui.js";
6
+ export function leerRespuesta(texto, tipo = 'normal') {
7
+ const r = texto.trim().toLowerCase();
8
+ const o = opcionesDePregunta(tipo);
9
+ if (r === '' || r === 'n' || r === 'no')
10
+ return 'no';
11
+ const n = Number(r);
12
+ if (Number.isInteger(n) && n >= 1 && n <= o.valores.length)
13
+ return o.valores[n - 1];
14
+ if ((r === 'y' || r === 'yes') && tipo !== 'credencial')
15
+ return 'si';
16
+ if ((r === 'a' || r === 'always') && o.valores.includes('siempre'))
17
+ return 'siempre';
18
+ return null;
19
+ }
20
+ function anchoDeVerbo() {
21
+ return Math.max(...['herr.leer', 'herr.listar', 'herr.buscar', 'herr.escribir', 'herr.editar', 'herr.ejecutar'].map((k) => anchoDe(t(k)))) + 2;
22
+ }
23
+ function sangriaDeDetalle() {
24
+ return 2 + anchoDeVerbo();
25
+ }
26
+ export function bloqueDeAccion(verbo, objeto, nota = '') {
27
+ objeto = objeto.replace(/\s*\r?\n\s*/g, ' ↵ ');
28
+ return (ancho) => {
29
+ const util = anchoUtil(ancho);
30
+ const v = rellenar(c.claro(verbo), anchoDeVerbo());
31
+ const punto = c.violeta(SIMBOLOS.punto);
32
+ const notaW = nota ? anchoDe(nota) + 2 : 0;
33
+ const libre = util - 2 - anchoDeVerbo();
34
+ const conNota = libre - notaW >= Math.min(16, anchoDe(objeto));
35
+ const espacio = conNota ? libre - notaW : libre;
36
+ const obj = anchoDe(objeto) > espacio ? (/[\\/]/.test(sinColor(objeto)) && !/\s/.test(sinColor(objeto)) ? recortarMedio(sinColor(objeto), espacio) : recortar(objeto, espacio)) : objeto;
37
+ return [`${' '.repeat(MARGEN)}${punto} ${v}${obj}${conNota && nota ? ` ${c.gris(nota)}` : ''}`];
38
+ };
39
+ }
40
+ export class Pantalla {
41
+ rl;
42
+ superficie = null;
43
+ esperaActiva = null;
44
+ trabajoEnLinea = null;
45
+ carril;
46
+ tty;
47
+ constructor(rl, tty = Boolean(process.stdout.isTTY && process.stdin.isTTY), carril = null) {
48
+ this.rl = rl;
49
+ this.tty = tty;
50
+ this.carril = carril;
51
+ }
52
+ fijarLectora(rl) {
53
+ this.rl = rl;
54
+ }
55
+ fijarSuperficie(s) {
56
+ this.superficie = s;
57
+ }
58
+ conCarril(b) {
59
+ const k = this.carril;
60
+ if (!k)
61
+ return b;
62
+ return (ancho) => {
63
+ const marca = `${c.claro(String(k.numero))}${c.violeta(capacidades().unicode ? '│' : '|')}`;
64
+ return b(Math.max(20, ancho - 3))
65
+ .filter((l) => l.trim() !== '')
66
+ .map((l) => `${' '.repeat(MARGEN)}${marca} ${l.startsWith(' '.repeat(MARGEN)) ? l.slice(MARGEN) : l}`);
67
+ };
68
+ }
69
+ bloque(b) {
70
+ const bc = this.conCarril(b);
71
+ if (this.superficie) {
72
+ this.superficie.anadir(bc);
73
+ return;
74
+ }
75
+ const enLinea = this.esperaActiva !== null;
76
+ if (enLinea)
77
+ process.stdout.write('\r\x1b[2K');
78
+ const ancho = Math.max(20, process.stdout.columns || capacidades().ancho || 80);
79
+ for (const l of bc(ancho))
80
+ process.stdout.write(`${l}\n`);
81
+ if (enLinea)
82
+ this.pintarEnLinea();
83
+ }
84
+ escribir(linea = '') {
85
+ this.bloque(bloqueDeTexto(linea.replace(/^ {1,2}/, '')));
86
+ }
87
+ lecturas = null;
88
+ accion(verbo, objeto, nota = '') {
89
+ if (this.superficie && verbo === t('herr.leer')) {
90
+ const l = this.lecturas;
91
+ if (l && this.superficie.ultimoBloque() === l.bloque) {
92
+ l.objetos.push(objeto);
93
+ const b = this.conCarril(bloqueDeAccion(verbo, l.objetos.join(', '), `${l.objetos.length} files`));
94
+ l.bloque = b;
95
+ this.superficie.reemplazarUltimo(b);
96
+ return;
97
+ }
98
+ const b = this.conCarril(bloqueDeAccion(verbo, objeto, nota));
99
+ this.lecturas = { bloque: b, objetos: [objeto] };
100
+ this.superficie.anadir(b);
101
+ return;
102
+ }
103
+ this.bloque(bloqueDeAccion(verbo, objeto, nota));
104
+ }
105
+ salidaDeComando(salida, maxLineas = 3) {
106
+ const lineas = salida.replace(/\r/g, '').trimEnd().split('\n').filter((l) => l.trim() !== '');
107
+ if (!lineas.length)
108
+ return;
109
+ const ultimas = lineas.slice(-maxLineas);
110
+ const sobran = lineas.length - ultimas.length;
111
+ this.bloque((ancho) => {
112
+ const s = sangriaDeDetalle();
113
+ const util = anchoUtil(ancho) - s;
114
+ const out = [];
115
+ if (sobran > 0)
116
+ out.push(`${' '.repeat(MARGEN + s)}${c.tenue(c.gris(`… ${sobran.toLocaleString('en-US')} +`))}`);
117
+ for (const l of ultimas)
118
+ out.push(`${' '.repeat(MARGEN + s)}${c.tenue(recortar(sinColor(l).replace(/\t/g, ' '), util))}`);
119
+ return out;
120
+ });
121
+ }
122
+ detalle(texto, error = false) {
123
+ this.bloque((ancho) => [`${' '.repeat(MARGEN + sangriaDeDetalle())}${recortar(error ? c.error(`${SIMBOLOS.falla} ${texto}`) : c.gris(texto), anchoUtil(ancho) - sangriaDeDetalle())}`]);
124
+ }
125
+ aviso(texto) {
126
+ this.bloque(bloqueDeTexto(`${c.aviso('!')} ${texto}`, ' '));
127
+ }
128
+ error(texto) {
129
+ this.bloque(bloqueDeTexto(`${c.error(SIMBOLOS.falla)} ${texto}`, ' '));
130
+ }
131
+ cierre(texto) {
132
+ this.bloque(bloqueDeCierre(texto, c.ok(SIMBOLOS.hecho)));
133
+ }
134
+ trabajoPropio() {
135
+ return this.carril ? this.carril.trabajo : this.trabajoEnLinea;
136
+ }
137
+ espera(texto = null, anim = 'ruta', vivo = anim === 'tren') {
138
+ if (this.carril) {
139
+ ponerTextoDeTrabajo(this.carril.trabajo, texto, anim, vivo);
140
+ this.superficie?.actualizarCarriles();
141
+ return;
142
+ }
143
+ if (this.superficie) {
144
+ this.superficie.textoDeTrabajo(texto, anim, vivo);
145
+ return;
146
+ }
147
+ if (!this.tty)
148
+ return;
149
+ this.trabajoEnLinea ??= nuevoTrabajo();
150
+ ponerTextoDeTrabajo(this.trabajoEnLinea, texto, anim, vivo);
151
+ if (!this.esperaActiva) {
152
+ this.pintarEnLinea();
153
+ this.esperaActiva = setInterval(() => {
154
+ if (this.trabajoEnLinea)
155
+ this.trabajoEnLinea.paso++;
156
+ this.pintarEnLinea();
157
+ }, 110);
158
+ this.esperaActiva.unref?.();
159
+ }
160
+ }
161
+ pintarEnLinea() {
162
+ if (!this.trabajoEnLinea)
163
+ return;
164
+ const ancho = Math.max(20, process.stdout.columns || 80);
165
+ process.stdout.write(`\r\x1b[2K${' '.repeat(MARGEN)}${recortar(filaDeTrabajo(this.trabajoEnLinea, Date.now()), ancho - MARGEN - 2)}`);
166
+ }
167
+ progreso(acciones) {
168
+ if (this.carril) {
169
+ this.carril.trabajo.acciones = acciones;
170
+ this.superficie?.actualizarCarriles();
171
+ return;
172
+ }
173
+ if (this.superficie) {
174
+ this.superficie.progreso(acciones);
175
+ return;
176
+ }
177
+ if (this.trabajoEnLinea)
178
+ this.trabajoEnLinea.acciones = acciones;
179
+ }
180
+ pararEspera() {
181
+ if (this.superficie || this.carril)
182
+ return;
183
+ if (this.esperaActiva) {
184
+ clearInterval(this.esperaActiva);
185
+ this.esperaActiva = null;
186
+ process.stdout.write('\r\x1b[2K');
187
+ }
188
+ this.trabajoEnLinea = null;
189
+ }
190
+ pausarLinea() {
191
+ if (this.esperaActiva) {
192
+ clearInterval(this.esperaActiva);
193
+ this.esperaActiva = null;
194
+ process.stdout.write('\r\x1b[2K');
195
+ }
196
+ }
197
+ diff(lineas, max = 40) {
198
+ const visibles = trozos(lineas);
199
+ this.bloque((ancho) => {
200
+ const s = sangriaDeDetalle();
201
+ const util = anchoUtil(ancho) - s;
202
+ const pre = ' '.repeat(MARGEN + s);
203
+ const out = [];
204
+ let pintadas = 0;
205
+ for (const l of visibles) {
206
+ if (pintadas >= max) {
207
+ out.push(`${pre}${c.tenue(`… ${visibles.length - max} +`)}`);
208
+ break;
209
+ }
210
+ pintadas++;
211
+ if (l === null) {
212
+ out.push(`${pre}${c.tenue('⋮')}`);
213
+ continue;
214
+ }
215
+ const num = String(l.despues ?? l.antes ?? '').padStart(4);
216
+ const texto = recortar(l.texto.replace(/\t/g, ' '), Math.max(4, util - 7));
217
+ if (l.tipo === '+')
218
+ out.push(`${pre}${c.tenue(num)} ${c.mas(`+ ${texto}`)}`);
219
+ else if (l.tipo === '-')
220
+ out.push(`${pre}${c.tenue(num)} ${c.menos(`- ${texto}`)}`);
221
+ else
222
+ out.push(`${pre}${c.tenue(num)} ${c.tenue(texto)}`);
223
+ }
224
+ return out;
225
+ });
226
+ }
227
+ async preguntar(pregunta, o = {}) {
228
+ const tipo = o.tipo ?? 'normal';
229
+ if (o.aviso)
230
+ this.aviso(o.aviso);
231
+ const texto = this.carril ? `${t('carriles.carril', { n: this.carril.numero })}: ${pregunta}` : pregunta;
232
+ if (this.superficie)
233
+ return this.superficie.preguntar(texto, tipo);
234
+ this.pausarLinea();
235
+ if (!this.tty || !this.rl) {
236
+ this.aviso(`${texto} → ${t('aviso.rechazado')}`);
237
+ return 'no';
238
+ }
239
+ const opciones = opcionesDePregunta(tipo);
240
+ const lista = opciones.opciones.map((e, i) => `${i + 1} ${e}`).join(' · ');
241
+ for (;;) {
242
+ const r = leerRespuesta(await this.rl.question(`${' '.repeat(MARGEN)}${c.marca(texto)} ${c.gris(lista)} ${c.claro(SIMBOLOS.flecha)} `), tipo);
243
+ if (r)
244
+ return r;
245
+ this.escribir(c.gris(t('pregunta.respuesta')));
246
+ }
247
+ }
248
+ texto(md) {
249
+ const lineas = md.replace(/\r/g, '').split('\n');
250
+ this.bloque((ancho) => {
251
+ const util = anchoUtil(ancho);
252
+ const pre = ' '.repeat(MARGEN);
253
+ const out = [];
254
+ let enBloque = false;
255
+ for (const linea of lineas) {
256
+ if (/^```/.test(linea.trim())) {
257
+ enBloque = !enBloque;
258
+ continue;
259
+ }
260
+ if (enBloque) {
261
+ out.push(`${pre} ${c.marca(recortar(linea.replace(/\t/g, ' '), util - 2))}`);
262
+ continue;
263
+ }
264
+ const titulo = /^#{1,6}\s+(.*)$/.exec(linea);
265
+ if (titulo) {
266
+ for (const l of envolver(c.negrita(titulo[1]), util))
267
+ out.push(`${pre}${l}`);
268
+ continue;
269
+ }
270
+ let l = linea;
271
+ let sangria = '';
272
+ const lista = /^(\s*)([-*]|\d+[.)])\s+/.exec(l);
273
+ if (lista) {
274
+ const marca = /\d/.test(lista[2]) ? lista[2] : SIMBOLOS.punto === '●' ? '·' : '-';
275
+ l = `${lista[1]}${c.claro(marca)} ${l.slice(lista[0].length)}`;
276
+ sangria = ' '.repeat(anchoDe(lista[1]) + anchoDe(marca) + 1);
277
+ }
278
+ l = l.replace(/\*\*([^*]+)\*\*/g, (_m, x) => c.negrita(x));
279
+ l = l.replace(/`([^`]+)`/g, (_m, x) => c.marca(x));
280
+ for (const p of envolver(l, util, sangria))
281
+ out.push(`${pre}${p}`);
282
+ }
283
+ return out;
284
+ });
285
+ }
286
+ }
287
+ export { bloqueDeLinea };
package/package.json CHANGED
@@ -1,6 +1,62 @@
1
1
  {
2
2
  "name": "@getparallel/parx",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.4.0",
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
+ "keywords": [
6
+ "parx",
7
+ "parallel",
8
+ "getparallel",
9
+ "ai",
10
+ "agent",
11
+ "coding-agent",
12
+ "cli",
13
+ "terminal",
14
+ "developer-tools",
15
+ "automation"
16
+ ],
17
+ "homepage": "https://getparallel.net/docs/apps/parx",
18
+ "bugs": {
19
+ "url": "https://getparallel.net/docs/apps/parx"
20
+ },
21
+ "author": "Parallel (https://getparallel.net)",
22
+ "license": "UNLICENSED",
23
+ "type": "module",
24
+ "bin": {
25
+ "parx": "dist/cli.js",
26
+ "parallel-code": "dist/cli.js",
27
+ "pcode": "dist/cli.js"
28
+ },
29
+ "files": [
30
+ "dist/**/*.js",
31
+ "README.md",
32
+ "LICENSE",
33
+ "CHANGELOG.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "os": [
39
+ "darwin",
40
+ "linux",
41
+ "win32"
42
+ ],
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "registry": "https://registry.npmjs.org/"
46
+ },
47
+ "scripts": {
48
+ "build": "node scripts/limpiar.mjs && tsc -p tsconfig.json && node scripts/ejecutable.mjs",
49
+ "typecheck": "tsc -p tsconfig.json --noEmit",
50
+ "test": "node --test --experimental-strip-types --no-warnings test/*.test.ts",
51
+ "verify": "npm run typecheck && npm run test && npm run build",
52
+ "prepack": "npm run verify",
53
+ "release": "node scripts/release.mjs",
54
+ "release:dry": "node scripts/release.mjs --dry-run",
55
+ "instaladores": "node scripts/instaladores.mjs",
56
+ "formula": "node scripts/formula.mjs"
57
+ },
58
+ "devDependencies": {
59
+ "typescript": "^5.9.3",
60
+ "@types/node": "^22.10.7"
61
+ }
62
+ }