@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.
@@ -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 (/\b(test|tests|vitest|jest|pytest|mocha|playwright|go test|cargo test|rspec|phpunit)\b/i.test(c1))
206
+ if (ES_TEST.test(c1))
204
207
  return t('hace.tests');
205
- if (/\b(build|tsc|webpack|vite build|next build|cargo build|make)\b/i.test(c1))
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), String(lineas.length));
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
- ctx.pantalla.accion(t('herr.leer'), mostrar(r), desde || hasta ? `${ini}-${n - 1}` : `${todas.length}`);
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, `${resultados.length}`);
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: this command may have effects outside the project ({motivo}).',
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:',