@getparallel/parx 0.5.0 → 0.6.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 +8 -0
- package/README.md +11 -5
- package/dist/actualizar.js +2 -1
- package/dist/agente.js +82 -2
- package/dist/api.js +14 -0
- package/dist/cli.js +193 -34
- package/dist/config.js +4 -0
- package/dist/estimacion.js +118 -0
- package/dist/firmas.js +55 -0
- package/dist/marca.js +56 -19
- package/dist/par.js +355 -0
- package/dist/remoto.js +284 -0
- package/dist/tar.js +99 -0
- package/dist/textos.js +44 -7
- package/dist/tui.js +56 -10
- package/dist/ui.js +35 -2
- package/dist/versiones.js +341 -0
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -47,6 +47,7 @@ export class Pantalla {
|
|
|
47
47
|
esperaActiva = null;
|
|
48
48
|
trabajoEnLinea = null;
|
|
49
49
|
carril;
|
|
50
|
+
espejo = null;
|
|
50
51
|
tty;
|
|
51
52
|
constructor(rl, tty = Boolean(process.stdout.isTTY && process.stdin.isTTY), carril = null) {
|
|
52
53
|
this.rl = rl;
|
|
@@ -110,6 +111,8 @@ export class Pantalla {
|
|
|
110
111
|
this.pintarEnLinea();
|
|
111
112
|
}
|
|
112
113
|
escribir(linea = '', grupo = 'nota') {
|
|
114
|
+
if (linea.trim())
|
|
115
|
+
this.espejo?.evento('nota', { texto: sinColor(linea).trim() });
|
|
113
116
|
if (!linea.trim()) {
|
|
114
117
|
if (!this.terminaEnBlanco() && !this.carril)
|
|
115
118
|
this.bloque(() => [''], this.ultimoGrupo ?? 'nota');
|
|
@@ -119,6 +122,7 @@ export class Pantalla {
|
|
|
119
122
|
}
|
|
120
123
|
lecturas = null;
|
|
121
124
|
accion(verbo, objeto, nota = '') {
|
|
125
|
+
this.espejo?.evento('accion', { verbo: sinColor(verbo), objeto: sinColor(objeto), nota: sinColor(nota) });
|
|
122
126
|
if (this.superficie && verbo === t('herr.leer')) {
|
|
123
127
|
const l = this.lecturas;
|
|
124
128
|
if (l && this.superficie.ultimoBloque() === l.bloque) {
|
|
@@ -146,6 +150,7 @@ export class Pantalla {
|
|
|
146
150
|
.filter((l) => l.trim() !== '' && !RELLENO_DE_TESTS.test(l));
|
|
147
151
|
if (!lineas.length)
|
|
148
152
|
return;
|
|
153
|
+
this.espejo?.evento('salida', { lineas: lineas.slice(-6).map((l) => sinColor(l)) });
|
|
149
154
|
const ultimas = lineas.slice(-maxLineas);
|
|
150
155
|
const sobran = lineas.length - ultimas.length;
|
|
151
156
|
this.bloque((ancho) => {
|
|
@@ -160,15 +165,19 @@ export class Pantalla {
|
|
|
160
165
|
}, 'accion');
|
|
161
166
|
}
|
|
162
167
|
detalle(texto, error = false) {
|
|
168
|
+
this.espejo?.evento('detalle', { texto: sinColor(texto), error });
|
|
163
169
|
this.bloque((ancho) => [`${' '.repeat(MARGEN + sangriaDeDetalle())}${recortar(error ? c.error(`${SIMBOLOS.falla} ${texto}`) : c.gris(texto), anchoUtil(ancho) - sangriaDeDetalle())}`], 'accion');
|
|
164
170
|
}
|
|
165
171
|
aviso(texto) {
|
|
172
|
+
this.espejo?.evento('aviso', { texto: sinColor(texto) });
|
|
166
173
|
this.bloque(bloqueDeTexto(`${c.aviso('!')} ${texto}`, ' '), 'aviso');
|
|
167
174
|
}
|
|
168
175
|
error(texto) {
|
|
176
|
+
this.espejo?.evento('error', { texto: sinColor(texto) });
|
|
169
177
|
this.bloque(bloqueDeTexto(`${c.error(SIMBOLOS.falla)} ${texto}`, ' '), 'error');
|
|
170
178
|
}
|
|
171
179
|
cierre(texto) {
|
|
180
|
+
this.espejo?.evento('cierre', { texto: sinColor(texto) });
|
|
172
181
|
this.bloque(bloqueDeCierre(texto, c.ok(SIMBOLOS.hecho)), 'cierre');
|
|
173
182
|
}
|
|
174
183
|
trabajoPropio() {
|
|
@@ -205,6 +214,7 @@ export class Pantalla {
|
|
|
205
214
|
process.stdout.write(`\r\x1b[2K${' '.repeat(MARGEN)}${recortar(filaDeTrabajo(this.trabajoEnLinea, Date.now()), ancho - MARGEN - 2)}`);
|
|
206
215
|
}
|
|
207
216
|
progreso(acciones) {
|
|
217
|
+
this.espejo?.progreso(acciones);
|
|
208
218
|
if (this.carril) {
|
|
209
219
|
this.carril.trabajo.acciones = acciones;
|
|
210
220
|
this.superficie?.actualizarCarriles();
|
|
@@ -236,6 +246,10 @@ export class Pantalla {
|
|
|
236
246
|
}
|
|
237
247
|
diff(lineas, max = 40) {
|
|
238
248
|
const visibles = trozos(lineas);
|
|
249
|
+
this.espejo?.evento('diff', {
|
|
250
|
+
lineas: visibles.slice(0, 40).map((l) => (l === null ? { tipo: '⋮', texto: '' } : { tipo: l.tipo, texto: l.texto, num: l.despues ?? l.antes ?? null })),
|
|
251
|
+
mas: Math.max(0, visibles.length - 40),
|
|
252
|
+
});
|
|
239
253
|
this.bloque((ancho) => {
|
|
240
254
|
const s = sangriaDeDetalle();
|
|
241
255
|
const util = anchoUtil(ancho) - s;
|
|
@@ -270,7 +284,21 @@ export class Pantalla {
|
|
|
270
284
|
this.aviso(o.aviso);
|
|
271
285
|
const texto = this.carril ? `${t('carriles.carril', { n: this.carril.numero })}: ${pregunta}` : pregunta;
|
|
272
286
|
if (this.superficie) {
|
|
273
|
-
const
|
|
287
|
+
const op = opcionesDePregunta(tipo);
|
|
288
|
+
const remota = this.espejo?.preguntaRemota(sinColor(texto), tipo, op.opciones.map((etiqueta, i) => ({ etiqueta, valor: op.valores[i] }))) ?? null;
|
|
289
|
+
let desdeFuera = false;
|
|
290
|
+
const externo = remota?.deFuera?.then((r) => {
|
|
291
|
+
desdeFuera = true;
|
|
292
|
+
return r;
|
|
293
|
+
});
|
|
294
|
+
const r = await this.superficie.preguntar(texto, tipo, externo);
|
|
295
|
+
remota?.contestada(r, desdeFuera ? 'movil' : 'ordenador');
|
|
296
|
+
if (desdeFuera) {
|
|
297
|
+
const o2 = opcionesDePregunta(tipo);
|
|
298
|
+
const etiqueta = o2.opciones[o2.valores.indexOf(r)] ?? t('tui.no');
|
|
299
|
+
this.bloque(bloqueDeTexto(`${c.gris('?')} ${texto} ${c.gris('→')} ${r === 'no' ? c.gris(etiqueta) : c.marca(etiqueta)} ${c.gris(`· ${t('remoto.desde_el_movil')}`)}`, ' '), 'aviso');
|
|
300
|
+
return r;
|
|
301
|
+
}
|
|
274
302
|
if (r !== 'si' && tipo !== 'bypass') {
|
|
275
303
|
const o2 = opcionesDePregunta(tipo);
|
|
276
304
|
const etiqueta = o2.opciones[o2.valores.indexOf(r)] ?? t('tui.no');
|
|
@@ -293,6 +321,10 @@ export class Pantalla {
|
|
|
293
321
|
}
|
|
294
322
|
}
|
|
295
323
|
texto(md) {
|
|
324
|
+
this.espejo?.evento('texto', { md });
|
|
325
|
+
this.pintarTexto(md);
|
|
326
|
+
}
|
|
327
|
+
pintarTexto(md) {
|
|
296
328
|
this.terminarRevelado();
|
|
297
329
|
this.bloque(bloqueDeMarkdown(md), 'texto');
|
|
298
330
|
}
|
|
@@ -304,10 +336,11 @@ export class Pantalla {
|
|
|
304
336
|
f?.();
|
|
305
337
|
}
|
|
306
338
|
textoAnimado(md, o = {}) {
|
|
339
|
+
this.espejo?.evento('texto', { md });
|
|
307
340
|
this.terminarRevelado();
|
|
308
341
|
const conSuperficie = this.superficie !== null;
|
|
309
342
|
if (!this.animar || this.carril || !this.tty || (!conSuperficie && !process.stdout.isTTY)) {
|
|
310
|
-
this.
|
|
343
|
+
this.pintarTexto(md);
|
|
311
344
|
return Promise.resolve();
|
|
312
345
|
}
|
|
313
346
|
const completo = bloqueDeMarkdown(md);
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { execFile } from 'node:child_process';
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { pathToFileURL } from 'node:url';
|
|
13
|
+
import { carpetaDeConfiguracion, leerAjustes, VERSION } from "./config.js";
|
|
14
|
+
import { comprobacionApagada, esMasNueva, ordenDeActualizar, PAQUETE, PAQUETE_EN_URL, partes, rutaDelCli } from "./actualizar.js";
|
|
15
|
+
import { clavesDeConfianza, firmaValida, integridadCoincide } from "./firmas.js";
|
|
16
|
+
import { escribirFicheros, leerTgz } from "./tar.js";
|
|
17
|
+
export const CARPETA = 'versiones';
|
|
18
|
+
const ESTADO = 'estado.json';
|
|
19
|
+
const MAX_TGZ = 20 * 1024 * 1024;
|
|
20
|
+
const PLAZO_DESCARGA_MS = 60_000;
|
|
21
|
+
const PLAZO_ARRANQUE_MS = 20_000;
|
|
22
|
+
const GUARDAR = 2;
|
|
23
|
+
export function carpetaDeVersiones(dir = carpetaDeConfiguracion()) {
|
|
24
|
+
return join(dir, CARPETA);
|
|
25
|
+
}
|
|
26
|
+
export function leerEstado(dir = carpetaDeConfiguracion()) {
|
|
27
|
+
try {
|
|
28
|
+
const e = JSON.parse(readFileSync(join(carpetaDeVersiones(dir), ESTADO), 'utf8'));
|
|
29
|
+
const candidatas = {};
|
|
30
|
+
for (const [v, c] of Object.entries(e.candidatas ?? {})) {
|
|
31
|
+
if (!partes(v) || !c || typeof c !== 'object')
|
|
32
|
+
continue;
|
|
33
|
+
const x = c;
|
|
34
|
+
candidatas[v] = {
|
|
35
|
+
descargada: typeof x.descargada === 'string' ? x.descargada : '',
|
|
36
|
+
probada: x.probada === true,
|
|
37
|
+
intentos: typeof x.intentos === 'number' && x.intentos >= 0 ? Math.floor(x.intentos) : 0,
|
|
38
|
+
arranca: x.arranca === true,
|
|
39
|
+
anunciada: x.anunciada === true,
|
|
40
|
+
...(typeof x.mala === 'string' ? { mala: x.mala } : {}),
|
|
41
|
+
...(typeof x.novedad === 'string' ? { novedad: x.novedad } : {}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { candidatas };
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { candidatas: {} };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function guardarEstado(e, dir = carpetaDeConfiguracion()) {
|
|
51
|
+
try {
|
|
52
|
+
const carpeta = carpetaDeVersiones(dir);
|
|
53
|
+
if (!existsSync(carpeta))
|
|
54
|
+
mkdirSync(carpeta, { recursive: true, mode: 0o700 });
|
|
55
|
+
writeFileSync(join(carpeta, ESTADO), JSON.stringify(e, null, 2), { mode: 0o600 });
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function autoactualizarApagada(env = process.env, ajustes = leerAjustes()) {
|
|
61
|
+
const si = (x) => Boolean(x && x !== '0' && x.toLowerCase() !== 'false');
|
|
62
|
+
return comprobacionApagada(env) || si(env.PARX_NO_AUTO_UPDATE) || ajustes.autoactualizar === false;
|
|
63
|
+
}
|
|
64
|
+
export function gestorPermiteAutoactualizar(gestor) {
|
|
65
|
+
return gestor !== 'npx' && gestor !== 'desarrollo';
|
|
66
|
+
}
|
|
67
|
+
export function rutaDeLaVersion(version, dir = carpetaDeConfiguracion()) {
|
|
68
|
+
const carpeta = join(carpetaDeVersiones(dir), version);
|
|
69
|
+
return { carpeta, cli: join(carpeta, 'dist', 'cli.js') };
|
|
70
|
+
}
|
|
71
|
+
export function novedadDelChangelog(texto, version) {
|
|
72
|
+
const re = new RegExp(`^## ${version.replace(/\./g, '\\.')}\\b[^\\n]*\\n([\\s\\S]*?)(?=^## |(?![\\s\\S]))`, 'm');
|
|
73
|
+
const m = re.exec(texto);
|
|
74
|
+
if (!m)
|
|
75
|
+
return null;
|
|
76
|
+
const linea = m[1].split('\n').map((l) => l.trim()).find((l) => /^[-*]\s+\S/.test(l));
|
|
77
|
+
if (!linea)
|
|
78
|
+
return null;
|
|
79
|
+
const limpia = linea
|
|
80
|
+
.replace(/^[-*]\s+/, '')
|
|
81
|
+
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
82
|
+
.replace(/`([^`]+)`/g, '$1')
|
|
83
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
84
|
+
.replace(/\s+/g, ' ')
|
|
85
|
+
.trim();
|
|
86
|
+
if (!limpia)
|
|
87
|
+
return null;
|
|
88
|
+
const frase = (/^(.{20,}?\.)\s/.exec(limpia)?.[1] ?? limpia).replace(/[;:,]$/, '');
|
|
89
|
+
if (frase.length <= 140)
|
|
90
|
+
return frase;
|
|
91
|
+
const corte = frase.slice(0, 139);
|
|
92
|
+
const espacio = corte.lastIndexOf(' ');
|
|
93
|
+
return `${(espacio > 80 ? corte.slice(0, espacio) : corte).replace(/[\s;:,.]+$/, '')}…`;
|
|
94
|
+
}
|
|
95
|
+
function registroDe(opts) {
|
|
96
|
+
return (opts.registro ?? opts.env?.PARX_REGISTRY ?? process.env.PARX_REGISTRY ?? 'https://registry.npmjs.org').replace(/\/+$/, '');
|
|
97
|
+
}
|
|
98
|
+
export async function manifiestoDe(version, opts = {}) {
|
|
99
|
+
const registro = registroDe(opts);
|
|
100
|
+
try {
|
|
101
|
+
const r = await (opts.fetch ?? fetch)(`${registro}/${PAQUETE_EN_URL}/${version}`, {
|
|
102
|
+
headers: { accept: 'application/json', 'user-agent': `parx/${VERSION}` },
|
|
103
|
+
signal: AbortSignal.timeout(opts.plazoMs ?? 10_000),
|
|
104
|
+
});
|
|
105
|
+
if (!r.ok)
|
|
106
|
+
return null;
|
|
107
|
+
const j = (await r.json());
|
|
108
|
+
if (j.version !== version || !j.dist || typeof j.dist.integrity !== 'string' || typeof j.dist.tarball !== 'string')
|
|
109
|
+
return null;
|
|
110
|
+
return { version, integrity: j.dist.integrity, tarball: j.dist.tarball, firmas: j.dist.signatures };
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function tarballDelRegistro(tarball, registro) {
|
|
117
|
+
try {
|
|
118
|
+
const t = new URL(tarball);
|
|
119
|
+
const r = new URL(registro);
|
|
120
|
+
if (t.host !== r.host)
|
|
121
|
+
return false;
|
|
122
|
+
if (t.protocol !== r.protocol)
|
|
123
|
+
return false;
|
|
124
|
+
return t.protocol === 'https:' || t.hostname === '127.0.0.1' || t.hostname === 'localhost';
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function bajar(url, opts) {
|
|
131
|
+
try {
|
|
132
|
+
const r = await (opts.fetch ?? fetch)(url, { headers: { 'user-agent': `parx/${VERSION}` }, signal: AbortSignal.timeout(opts.plazoMs ?? PLAZO_DESCARGA_MS) });
|
|
133
|
+
if (!r.ok)
|
|
134
|
+
return null;
|
|
135
|
+
const largo = Number(r.headers.get('content-length') ?? 0);
|
|
136
|
+
if (largo > MAX_TGZ)
|
|
137
|
+
return null;
|
|
138
|
+
const b = Buffer.from(await r.arrayBuffer());
|
|
139
|
+
return b.length > MAX_TGZ ? null : b;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export function probarQueArranca(cli, version, opts = {}) {
|
|
146
|
+
const env = { ...(opts.env ?? process.env), PARX_LANZADO_DESDE: 'prueba', PARX_NO_UPDATE_CHECK: '1' };
|
|
147
|
+
delete env.PARX_PRUEBAS;
|
|
148
|
+
return new Promise((resolver) => {
|
|
149
|
+
execFile(opts.node ?? process.execPath, [cli, '--version'], { env, timeout: opts.plazoMs ?? PLAZO_ARRANQUE_MS, windowsHide: true }, (error, stdout) => {
|
|
150
|
+
resolver(!error && String(stdout).trim() === `parx ${version}`);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
export async function prepararVersion(version, opts = {}) {
|
|
155
|
+
const dir = opts.dir ?? carpetaDeConfiguracion();
|
|
156
|
+
if (!partes(version))
|
|
157
|
+
return { ok: false, motivo: 'manifiesto' };
|
|
158
|
+
const estado = leerEstado(dir);
|
|
159
|
+
const ya = estado.candidatas[version];
|
|
160
|
+
const { carpeta, cli } = rutaDeLaVersion(version, dir);
|
|
161
|
+
if (ya?.probada && !ya.mala && existsSync(cli))
|
|
162
|
+
return { ok: true, version, novedad: ya.novedad ?? null, yaEstaba: true };
|
|
163
|
+
const registro = registroDe(opts);
|
|
164
|
+
const m = await manifiestoDe(version, opts);
|
|
165
|
+
if (!m)
|
|
166
|
+
return { ok: false, motivo: 'manifiesto' };
|
|
167
|
+
if (!tarballDelRegistro(m.tarball, registro))
|
|
168
|
+
return { ok: false, motivo: 'manifiesto' };
|
|
169
|
+
const claves = opts.claves ?? clavesDeConfianza(opts.env ?? process.env);
|
|
170
|
+
if (!firmaValida({ nombre: PAQUETE, version, integrity: m.integrity, firmas: m.firmas }, claves))
|
|
171
|
+
return { ok: false, motivo: 'firma' };
|
|
172
|
+
const tgz = await bajar(m.tarball, opts);
|
|
173
|
+
if (!tgz)
|
|
174
|
+
return { ok: false, motivo: 'descarga' };
|
|
175
|
+
if (!integridadCoincide(tgz, m.integrity))
|
|
176
|
+
return { ok: false, motivo: 'integridad' };
|
|
177
|
+
let ficheros;
|
|
178
|
+
try {
|
|
179
|
+
ficheros = leerTgz(tgz);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { ok: false, motivo: 'contenido' };
|
|
183
|
+
}
|
|
184
|
+
const pkg = ficheros.find((f) => f.ruta === 'package.json');
|
|
185
|
+
let manifiesto = {};
|
|
186
|
+
try {
|
|
187
|
+
manifiesto = pkg ? JSON.parse(pkg.contenido.toString('utf8')) : {};
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
}
|
|
191
|
+
if (manifiesto.name !== PAQUETE || manifiesto.version !== version || !ficheros.some((f) => f.ruta === 'dist/cli.js'))
|
|
192
|
+
return { ok: false, motivo: 'contenido' };
|
|
193
|
+
const temporal = `${carpeta}.tmp`;
|
|
194
|
+
try {
|
|
195
|
+
rmSync(temporal, { recursive: true, force: true });
|
|
196
|
+
rmSync(carpeta, { recursive: true, force: true });
|
|
197
|
+
mkdirSync(temporal, { recursive: true, mode: 0o700 });
|
|
198
|
+
escribirFicheros(ficheros, temporal);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
rmSync(temporal, { recursive: true, force: true });
|
|
202
|
+
return { ok: false, motivo: 'disco' };
|
|
203
|
+
}
|
|
204
|
+
const arranca = await probarQueArranca(join(temporal, 'dist', 'cli.js'), version, { node: opts.node, env: opts.env });
|
|
205
|
+
if (!arranca) {
|
|
206
|
+
rmSync(temporal, { recursive: true, force: true });
|
|
207
|
+
const e = leerEstado(dir);
|
|
208
|
+
e.candidatas[version] = { descargada: new Date(opts.ahora ?? Date.now()).toISOString(), probada: false, intentos: 0, arranca: false, anunciada: false, mala: 'no_arranca' };
|
|
209
|
+
guardarEstado(e, dir);
|
|
210
|
+
return { ok: false, motivo: 'no_arranca' };
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
renameSync(temporal, carpeta);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
rmSync(temporal, { recursive: true, force: true });
|
|
217
|
+
return { ok: false, motivo: 'disco' };
|
|
218
|
+
}
|
|
219
|
+
const changelog = ficheros.find((f) => f.ruta === 'CHANGELOG.md');
|
|
220
|
+
const novedad = changelog ? novedadDelChangelog(changelog.contenido.toString('utf8'), version) : null;
|
|
221
|
+
const e = leerEstado(dir);
|
|
222
|
+
e.candidatas[version] = { descargada: new Date(opts.ahora ?? Date.now()).toISOString(), probada: true, intentos: 0, arranca: false, anunciada: false, ...(novedad ? { novedad } : {}) };
|
|
223
|
+
guardarEstado(e, dir);
|
|
224
|
+
limpiarVersiones(dir);
|
|
225
|
+
return { ok: true, version, novedad, yaEstaba: false };
|
|
226
|
+
}
|
|
227
|
+
export function limpiarVersiones(dir = carpetaDeConfiguracion()) {
|
|
228
|
+
const e = leerEstado(dir);
|
|
229
|
+
const carpeta = carpetaDeVersiones(dir);
|
|
230
|
+
const buenas = Object.entries(e.candidatas)
|
|
231
|
+
.filter(([, c]) => c.probada && !c.mala)
|
|
232
|
+
.map(([v]) => v)
|
|
233
|
+
.sort((a, b) => (esMasNueva(a, b) ? -1 : esMasNueva(b, a) ? 1 : 0));
|
|
234
|
+
const quedarse = new Set(buenas.slice(0, GUARDAR));
|
|
235
|
+
let entradas = [];
|
|
236
|
+
try {
|
|
237
|
+
entradas = readdirSync(carpeta);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
for (const nombre of entradas) {
|
|
243
|
+
if (nombre === ESTADO)
|
|
244
|
+
continue;
|
|
245
|
+
if (!quedarse.has(nombre)) {
|
|
246
|
+
rmSync(join(carpeta, nombre), { recursive: true, force: true });
|
|
247
|
+
if (e.candidatas[nombre] && !e.candidatas[nombre].mala)
|
|
248
|
+
delete e.candidatas[nombre];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
guardarEstado(e, dir);
|
|
252
|
+
}
|
|
253
|
+
export function marcarMala(version, motivo, dir = carpetaDeConfiguracion()) {
|
|
254
|
+
const e = leerEstado(dir);
|
|
255
|
+
const c = e.candidatas[version];
|
|
256
|
+
if (c)
|
|
257
|
+
c.mala = motivo;
|
|
258
|
+
else
|
|
259
|
+
e.candidatas[version] = { descargada: '', probada: false, intentos: 0, arranca: false, anunciada: false, mala: motivo };
|
|
260
|
+
guardarEstado(e, dir);
|
|
261
|
+
rmSync(rutaDeLaVersion(version, dir).carpeta, { recursive: true, force: true });
|
|
262
|
+
}
|
|
263
|
+
export function elegirVersionParaArrancar(opts = {}) {
|
|
264
|
+
const dir = opts.dir ?? carpetaDeConfiguracion();
|
|
265
|
+
const actual = opts.actual ?? VERSION;
|
|
266
|
+
const e = leerEstado(dir);
|
|
267
|
+
let retirada = null;
|
|
268
|
+
let cambios = false;
|
|
269
|
+
for (const [v, c] of Object.entries(e.candidatas)) {
|
|
270
|
+
if (!esMasNueva(v, actual)) {
|
|
271
|
+
rmSync(rutaDeLaVersion(v, dir).carpeta, { recursive: true, force: true });
|
|
272
|
+
delete e.candidatas[v];
|
|
273
|
+
cambios = true;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (c.probada && !c.mala && !c.arranca && c.intentos >= 2) {
|
|
277
|
+
c.mala = 'no_confirmo';
|
|
278
|
+
rmSync(rutaDeLaVersion(v, dir).carpeta, { recursive: true, force: true });
|
|
279
|
+
retirada = v;
|
|
280
|
+
cambios = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const validas = Object.entries(e.candidatas)
|
|
284
|
+
.filter(([v, c]) => c.probada && !c.mala && existsSync(rutaDeLaVersion(v, dir).cli))
|
|
285
|
+
.map(([v]) => v)
|
|
286
|
+
.sort((a, b) => (esMasNueva(a, b) ? -1 : 1));
|
|
287
|
+
const version = validas[0];
|
|
288
|
+
if (version) {
|
|
289
|
+
e.candidatas[version].intentos++;
|
|
290
|
+
cambios = true;
|
|
291
|
+
}
|
|
292
|
+
if (cambios)
|
|
293
|
+
guardarEstado(e, dir);
|
|
294
|
+
return { elegida: version ? { version, cli: rutaDeLaVersion(version, dir).cli } : null, retirada };
|
|
295
|
+
}
|
|
296
|
+
export function confirmarArranque(opts = {}) {
|
|
297
|
+
const env = opts.env ?? process.env;
|
|
298
|
+
const desde = env.PARX_LANZADO_DESDE ?? '';
|
|
299
|
+
if (!partes(desde))
|
|
300
|
+
return null;
|
|
301
|
+
const dir = opts.dir ?? carpetaDeConfiguracion();
|
|
302
|
+
const actual = opts.actual ?? VERSION;
|
|
303
|
+
const e = leerEstado(dir);
|
|
304
|
+
const c = e.candidatas[actual];
|
|
305
|
+
if (!c)
|
|
306
|
+
return null;
|
|
307
|
+
const primera = !c.anunciada;
|
|
308
|
+
c.arranca = true;
|
|
309
|
+
c.intentos = 0;
|
|
310
|
+
c.anunciada = true;
|
|
311
|
+
guardarEstado(e, dir);
|
|
312
|
+
return primera ? { version: actual, novedad: c.novedad ?? null } : null;
|
|
313
|
+
}
|
|
314
|
+
export async function lanzarLaMasNueva(opts = {}) {
|
|
315
|
+
const env = opts.env ?? process.env;
|
|
316
|
+
if (env.PARX_LANZADO_DESDE)
|
|
317
|
+
return { lanzada: false, retirada: null };
|
|
318
|
+
if (autoactualizarApagada(env, opts.ajustes ?? leerAjustes(opts.dir)))
|
|
319
|
+
return { lanzada: false, retirada: null };
|
|
320
|
+
const gestor = opts.gestor ?? ordenDeActualizar(rutaDelCli()).gestor;
|
|
321
|
+
if (!gestorPermiteAutoactualizar(gestor))
|
|
322
|
+
return { lanzada: false, retirada: null };
|
|
323
|
+
let retirada = null;
|
|
324
|
+
for (let intento = 0; intento < 3; intento++) {
|
|
325
|
+
const eleccion = elegirVersionParaArrancar({ dir: opts.dir, actual: opts.actual });
|
|
326
|
+
retirada = eleccion.retirada ?? retirada;
|
|
327
|
+
if (!eleccion.elegida)
|
|
328
|
+
return { lanzada: false, retirada };
|
|
329
|
+
env.PARX_LANZADO_DESDE = opts.actual ?? VERSION;
|
|
330
|
+
try {
|
|
331
|
+
await (opts.importar ?? ((u) => import(__rewriteRelativeImportExtension(u))))(pathToFileURL(eleccion.elegida.cli).href);
|
|
332
|
+
return { lanzada: true, version: eleccion.elegida.version };
|
|
333
|
+
}
|
|
334
|
+
catch (e) {
|
|
335
|
+
delete env.PARX_LANZADO_DESDE;
|
|
336
|
+
marcarMala(eleccion.elegida.version, `import: ${e instanceof Error ? e.message.slice(0, 200) : String(e)}`, opts.dir);
|
|
337
|
+
retirada = eleccion.elegida.version;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return { lanzada: false, retirada };
|
|
341
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getparallel/parx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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",
|