@getparallel/parx 0.4.1 → 0.4.2
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 +21 -0
- package/README.md +20 -2
- package/dist/agente.js +9 -6
- package/dist/api.js +6 -0
- package/dist/bash.js +89 -0
- package/dist/cli.js +200 -15
- package/dist/consejos.js +4 -1
- package/dist/herramientas.js +12 -8
- package/dist/informe.js +6 -0
- package/dist/marca.js +8 -0
- package/dist/textos.js +50 -2
- package/dist/tui.js +687 -138
- package/dist/ui.js +66 -22
- package/package.json +1 -1
package/dist/herramientas.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, rmSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, relative } from 'node:path';
|
|
3
3
|
import { contarCambios, diffDeLineas } from "./diff.js";
|
|
4
|
-
import { t } from "./textos.js";
|
|
4
|
+
import { cuantos, t } from "./textos.js";
|
|
5
5
|
import { c } from "./marca.js";
|
|
6
6
|
import { estaDentro, familiaDeComando, nivelDeComando, resolverRuta, rutaReal } from "./seguridad.js";
|
|
7
7
|
import { ejecutarComando, recortar } from "./shell.js";
|
|
@@ -143,8 +143,8 @@ function carpetaDe(r) {
|
|
|
143
143
|
async function preguntar(ctx, clave, pregunta, tipo, aviso = null) {
|
|
144
144
|
const r = await ctx.pantalla.preguntar(pregunta, { tipo, aviso });
|
|
145
145
|
ctx.registro.apuntar('permiso', { clave: tipo === 'credencial' ? 'credencial' : clave, respuesta: r });
|
|
146
|
-
if (r === 'no')
|
|
147
|
-
ctx.pantalla.escribir(c.gris(` ${t('aviso.rechazado')}`));
|
|
146
|
+
if (r === 'no' && !ctx.pantalla.conSuperficie)
|
|
147
|
+
ctx.pantalla.escribir(c.gris(` ${t('aviso.rechazado')}`), 'aviso');
|
|
148
148
|
return r;
|
|
149
149
|
}
|
|
150
150
|
const DECLINADO = 'The user declined this action. Do not retry it; ask them or try another approach.';
|
|
@@ -198,11 +198,14 @@ function apuntarFichero(ctx, r) {
|
|
|
198
198
|
if (!r.credencial && !ctx.hechos.ficheros.includes(r.mostrar))
|
|
199
199
|
ctx.hechos.ficheros.push(r.mostrar);
|
|
200
200
|
}
|
|
201
|
+
const ORDEN = '(?:^|[\\s;&|(])';
|
|
202
|
+
const ES_TEST = new RegExp(`${ORDEN}(?:npx\\s+|bunx\\s+|pnpm\\s+(?:exec\\s+)?)?(?:vitest|jest|pytest|mocha|rspec|phpunit|playwright\\s+test)(?=$|[\\s;&|)])|${ORDEN}(?:npm|pnpm|yarn|bun)\\s+(?:run\\s+)?test(?::[\\w:-]+)?(?=$|[\\s;&|)])|${ORDEN}(?:go|cargo|make|deno|dotnet)\\s+test\\b|${ORDEN}node\\s+--test\\b|${ORDEN}python3?\\s+-m\\s+(?:pytest|unittest)\\b`, 'i');
|
|
203
|
+
const ES_BUILD = new RegExp(`${ORDEN}(?:npm|pnpm|yarn|bun)\\s+(?:run\\s+)?build(?::[\\w:-]+)?(?=$|[\\s;&|)])|${ORDEN}(?:npx\\s+)?(?:tsc|webpack)(?=$|[\\s;&|)])|${ORDEN}(?:npx\\s+)?(?:vite|next)\\s+build\\b|${ORDEN}(?:cargo|go)\\s+build\\b|${ORDEN}make(?=$|[\\s;&|)])`, 'i');
|
|
201
204
|
export function etiquetaDeComando(comando) {
|
|
202
205
|
const c1 = comando.trim();
|
|
203
|
-
if (
|
|
206
|
+
if (ES_TEST.test(c1))
|
|
204
207
|
return t('hace.tests');
|
|
205
|
-
if (
|
|
208
|
+
if (ES_BUILD.test(c1))
|
|
206
209
|
return t('hace.build');
|
|
207
210
|
if (/\b(npm|pnpm|yarn|bun|pip3?|poetry|cargo|go)\s+(i|install|add|ci|sync|get)\b/i.test(c1))
|
|
208
211
|
return t('hace.instalar');
|
|
@@ -298,7 +301,7 @@ async function listar(ctx, ruta, prof) {
|
|
|
298
301
|
const rel = relative(r.absoluta, e.ruta).split('\\').join('/');
|
|
299
302
|
lineas.push(e.esDir ? `${rel}/` : rel);
|
|
300
303
|
}
|
|
301
|
-
ctx.pantalla.accion(t('herr.listar'), r.mostrar === '.' ? './' : mostrar(r),
|
|
304
|
+
ctx.pantalla.accion(t('herr.listar'), r.mostrar === '.' ? './' : mostrar(r), cuantos(lineas.length, 'item', 'items', 'empty'));
|
|
302
305
|
ctx.registro.apuntar('herramienta', { herramienta: 'list_files', ruta: r.credencial ? '[credential]' : r.mostrar, entradas: lineas.length });
|
|
303
306
|
return lineas.join('\n') || '(empty)';
|
|
304
307
|
}
|
|
@@ -326,7 +329,8 @@ async function leer(ctx, ruta, desde, hasta) {
|
|
|
326
329
|
out += l;
|
|
327
330
|
}
|
|
328
331
|
const leidas = n - ini;
|
|
329
|
-
|
|
332
|
+
const total = todas.length > 1 && todas[todas.length - 1] === '' ? todas.length - 1 : todas.length;
|
|
333
|
+
ctx.pantalla.accion(t('herr.leer'), mostrar(r), desde || hasta ? `lines ${ini}-${Math.min(n - 1, total)}` : cuantos(total, 'line', 'lines'));
|
|
330
334
|
ctx.registro.apuntar('herramienta', { herramienta: 'read_file', ruta: r.credencial ? '[credential]' : r.mostrar, lineas: leidas });
|
|
331
335
|
if (n <= fin)
|
|
332
336
|
out += `[… truncated at line ${n - 1} of ${todas.length}; read the rest with start_line …]\n`;
|
|
@@ -374,7 +378,7 @@ async function buscar(ctx, patron, ruta, glob) {
|
|
|
374
378
|
resultados.push(`${rel}:${i + 1}: ${lineas[i].slice(0, 300)}`);
|
|
375
379
|
}
|
|
376
380
|
}
|
|
377
|
-
ctx.pantalla.accion(t('herr.buscar'), patron,
|
|
381
|
+
ctx.pantalla.accion(t('herr.buscar'), patron, cuantos(resultados.length, 'match', 'matches', 'no matches'));
|
|
378
382
|
ctx.registro.apuntar('herramienta', { herramienta: 'search', patron: patron.slice(0, 200), resultados: resultados.length });
|
|
379
383
|
return resultados.length ? resultados.join('\n') + (resultados.length >= 200 ? '\n[… more matches omitted …]' : '') : 'No matches.';
|
|
380
384
|
}
|
package/dist/informe.js
CHANGED
|
@@ -42,6 +42,12 @@ export async function escribirInforme(servidor, token, sesion, diario, proyecto,
|
|
|
42
42
|
.trim();
|
|
43
43
|
return { texto, acciones: r.acciones.tarea, disponibles: r.acciones.disponibles };
|
|
44
44
|
}
|
|
45
|
+
export function textoParaPegar(md) {
|
|
46
|
+
return md
|
|
47
|
+
.replace(/\*\*([^*\n]+)\*\*/g, '$1')
|
|
48
|
+
.replace(/`([^`\n]+)`/g, '$1')
|
|
49
|
+
.replace(/^#{1,6}\s+/gm, '');
|
|
50
|
+
}
|
|
45
51
|
export function copiarAlPortapapeles(texto, plataforma = process.platform) {
|
|
46
52
|
const intentos = plataforma === 'darwin'
|
|
47
53
|
? [['pbcopy', []]]
|
package/dist/marca.js
CHANGED
|
@@ -90,7 +90,15 @@ export const c = {
|
|
|
90
90
|
peligro: (t) => pintar('peligro', t),
|
|
91
91
|
negrita: (t) => (caps.color ? `\x1b[1m${t}\x1b[22m` : t),
|
|
92
92
|
tenue: (t) => (caps.color ? `\x1b[2m${t}\x1b[22m` : t),
|
|
93
|
+
boton: (t, peligro = false) => fondo(peligro ? 'peligro' : 'violeta', t),
|
|
93
94
|
};
|
|
95
|
+
function fondo(nombre, texto) {
|
|
96
|
+
const { color } = caps;
|
|
97
|
+
if (color === 0)
|
|
98
|
+
return texto;
|
|
99
|
+
const bg = color === 3 ? `\x1b[48;2;${PALETA[nombre].join(';')}m` : color === 2 ? `\x1b[48;5;${ANSI256[nombre]}m` : `\x1b[${ANSI16[nombre] + 10}m`;
|
|
100
|
+
return `${bg}\x1b[1;97m${texto}\x1b[22;39;49m`;
|
|
101
|
+
}
|
|
94
102
|
export { sinColor } from "./texto.js";
|
|
95
103
|
export function logo() {
|
|
96
104
|
const filas = caps.unicode
|
package/dist/textos.js
CHANGED
|
@@ -4,6 +4,7 @@ export const TEXTOS = {
|
|
|
4
4
|
'tui.parar': 'esc to stop',
|
|
5
5
|
'tui.salir_otra': 'Press Ctrl+C again to exit',
|
|
6
6
|
'tui.en_cola': 'Queued: sent when this finishes',
|
|
7
|
+
'tui.en_cola_n': '{n} tasks queued, in order',
|
|
7
8
|
'tui.hola': 'Hi, {nombre}.',
|
|
8
9
|
'tui.hola_sin_nombre': 'Hi.',
|
|
9
10
|
'tui.pegado': 'Pasted · {n} lines',
|
|
@@ -18,7 +19,40 @@ export const TEXTOS = {
|
|
|
18
19
|
'tui.si_ediciones': 'Yes, allow all edits',
|
|
19
20
|
'tui.si_ediciones_corto': 'All edits',
|
|
20
21
|
'tui.una_vez': 'Yes, this once',
|
|
21
|
-
'tui.atajos': 'Shift+Tab mode · ↑ ↓ history · Esc stops a task · Ctrl+C twice exits · Ctrl+L redraws',
|
|
22
|
+
'tui.atajos': 'Shift+Tab mode · ↑ ↓ history · ! runs a shell command · Esc stops a task · Ctrl+C twice exits · Ctrl+L redraws',
|
|
23
|
+
'tui.atajos_raton': 'Click any option or button · wheel or PgUp/PgDn scrolls · End jumps to the bottom · Shift+drag selects text (Option in iTerm2, Fn in Terminal) · /mouse off gives the mouse back to the terminal',
|
|
24
|
+
'tui.al_fondo': 'Jump to bottom',
|
|
25
|
+
'tui.nuevas': '{n} new',
|
|
26
|
+
'bash.ejemplo': 'A shell command, run in the project folder',
|
|
27
|
+
'bash.etiqueta': 'bash',
|
|
28
|
+
'bash.intro': 'Enter runs it',
|
|
29
|
+
'bash.solo_lectura': 'Read only: shell commands are off. /mode to change it.',
|
|
30
|
+
'bash.sin_salida': 'no output',
|
|
31
|
+
'bash.mas': '… {n} more lines',
|
|
32
|
+
'bash.no_compartido': 'Kept out of the conversation: it touches credentials.',
|
|
33
|
+
'bash.corriendo': 'Running {comando}',
|
|
34
|
+
'raton.on': 'Mouse on: click options, scroll with the wheel. Shift+drag selects text.',
|
|
35
|
+
'raton.off': 'Mouse off: the terminal selects and scrolls as usual. /mouse on to turn it back on.',
|
|
36
|
+
'bandeja.esperando': '{n} waiting',
|
|
37
|
+
'bandeja.recomendada': 'Best',
|
|
38
|
+
'bandeja.titulo': 'Waiting for you',
|
|
39
|
+
'bandeja.mirando': 'Checking your missions',
|
|
40
|
+
'bandeja.nada': 'Nothing waiting for you.',
|
|
41
|
+
'bandeja.todo': 'All answered.',
|
|
42
|
+
'bandeja.volver': 'Back',
|
|
43
|
+
'bandeja.escribe': 'What should change? (empty cancels)',
|
|
44
|
+
'bandeja.nota': 'A note for the agents (optional)',
|
|
45
|
+
'bandeja.cancelado': 'Not sent.',
|
|
46
|
+
'bandeja.hecho_aprobado': 'Approved',
|
|
47
|
+
'bandeja.hecho_rechazado': 'Rejected',
|
|
48
|
+
'bandeja.hecho_cambios': 'Sent to the agent',
|
|
49
|
+
'bandeja.hecho_paso': 'Marked as done',
|
|
50
|
+
'bandeja.hecho_saltado': 'Skipped',
|
|
51
|
+
'bandeja.ya': 'Already answered somewhere else.',
|
|
52
|
+
'bandeja.no_existe': 'That is no longer waiting.',
|
|
53
|
+
'bandeja.despacio': 'Too many answers at once. Try again in a minute.',
|
|
54
|
+
'bandeja.no_disponible': 'Your missions are not reachable from parx yet.',
|
|
55
|
+
'bandeja.abrir': 'Open in the browser: {url}',
|
|
22
56
|
'modo.ask': 'Ask',
|
|
23
57
|
'modo.auto': 'Auto',
|
|
24
58
|
'modo.read': 'Read only',
|
|
@@ -83,7 +117,7 @@ export const TEXTOS = {
|
|
|
83
117
|
'aviso.credenciales': 'Credentials: {que}. Its contents would go to Parallel to work on it, never to the log.',
|
|
84
118
|
'aviso.solo_lectura': 'Read only: nothing changed (/mode to change it).',
|
|
85
119
|
'aviso.fuera': 'outside the project',
|
|
86
|
-
'aviso.riesgo': 'Careful:
|
|
120
|
+
'aviso.riesgo': 'Careful: {motivo}.',
|
|
87
121
|
'estado.hecho': 'Done',
|
|
88
122
|
'estado.interrumpido': 'Stopped.',
|
|
89
123
|
'estado.acciones': '{n} Actions',
|
|
@@ -164,6 +198,7 @@ export const TEXTOS = {
|
|
|
164
198
|
'mision.creada': 'Mission on its way. Follow it at {url}',
|
|
165
199
|
'mision.plan': 'Planning it now. It launches on its own when the plan is ready; you can close parx.',
|
|
166
200
|
'mision.lanzada': 'Launched. Parallel is working on it.',
|
|
201
|
+
'mision.aqui': 'Your mission: {url}',
|
|
167
202
|
'mision.cerradas': 'New missions are paused for maintenance. Try again later.',
|
|
168
203
|
'mision.limite': 'Your plan or your Actions do not cover this mission. See getparallel.net/settings/billing',
|
|
169
204
|
'mision.no_disponible': 'Missions are not available right now.',
|
|
@@ -197,7 +232,15 @@ export const TEXTOS = {
|
|
|
197
232
|
'tip.informe': 'A plain summary of what was done, ready to paste',
|
|
198
233
|
'tip.ensenar': 'Explains each step as it codes, like a teacher',
|
|
199
234
|
'tip.mision': 'Keeps the work going on Parallel after you close parx',
|
|
235
|
+
'tip.bash': 'Runs a shell command right here; parx sees the output',
|
|
236
|
+
'tip.bandeja': 'Answer what your missions are waiting for',
|
|
237
|
+
'tip.raton': 'Click options; Shift+drag selects text',
|
|
200
238
|
};
|
|
239
|
+
export function cuantos(n, uno, varios, ninguno) {
|
|
240
|
+
if (n === 0 && ninguno)
|
|
241
|
+
return ninguno;
|
|
242
|
+
return `${n.toLocaleString('en-US')} ${n === 1 ? uno : varios}`;
|
|
243
|
+
}
|
|
201
244
|
export function t(clave, datos = {}) {
|
|
202
245
|
const plantilla = TEXTOS[clave] ?? clave;
|
|
203
246
|
return plantilla.replace(/\{(\w+)\}/g, (m, k) => (k in datos ? String(datos[k]) : m));
|
|
@@ -209,6 +252,7 @@ export const COMANDOS = [
|
|
|
209
252
|
['folder', 'Let parx work in another folder'],
|
|
210
253
|
['lanes', 'Run 2 or 3 tasks at once'],
|
|
211
254
|
['mission', 'Keep it running on Parallel, phone alert when done'],
|
|
255
|
+
['inbox', 'Answer what your missions are waiting for'],
|
|
212
256
|
['report', 'Plain summary to paste in email or WhatsApp'],
|
|
213
257
|
['teach', 'Explain each step, like a teacher'],
|
|
214
258
|
['undo', 'Undo the last change to a file'],
|
|
@@ -216,6 +260,7 @@ export const COMANDOS = [
|
|
|
216
260
|
['balance', 'Your account and your Actions'],
|
|
217
261
|
['notify', 'Desktop notifications: on or off'],
|
|
218
262
|
['tips', 'Tips when it opens: on or off'],
|
|
263
|
+
['mouse', 'Clicks and wheel in parx: on or off'],
|
|
219
264
|
['log', 'Where the log of what it does is kept'],
|
|
220
265
|
['exit', 'Leave parx'],
|
|
221
266
|
];
|
|
@@ -226,6 +271,8 @@ export const ALIAS_COMANDO = {
|
|
|
226
271
|
folder: 'folder', 'add-folder': 'folder', carpeta: 'folder', dir: 'folder',
|
|
227
272
|
lanes: 'lanes', carriles: 'lanes',
|
|
228
273
|
mission: 'mission', mision: 'mission', misión: 'mission',
|
|
274
|
+
inbox: 'inbox', bandeja: 'inbox', approvals: 'inbox', waiting: 'inbox',
|
|
275
|
+
mouse: 'mouse', raton: 'mouse', ratón: 'mouse',
|
|
229
276
|
report: 'report', informe: 'report',
|
|
230
277
|
teach: 'teach', class: 'teach', clase: 'teach',
|
|
231
278
|
undo: 'undo', deshacer: 'undo',
|
|
@@ -256,6 +303,7 @@ export const USO = [
|
|
|
256
303
|
' --sandbox on macOS, run commands in a sandbox (writes only in the project)',
|
|
257
304
|
' --dir <folder> the project folder (default: current)',
|
|
258
305
|
' --ascii plain characters only (also NO_COLOR for no color)',
|
|
306
|
+
' --no-mouse leave the mouse to the terminal (no clicks or wheel in parx)',
|
|
259
307
|
' --version, --help',
|
|
260
308
|
'',
|
|
261
309
|
'Sign in:',
|