qdd-framework 2.10.0-rc.6 → 2.10.0-rc.60
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/README.md +1 -1
- package/install.js +54 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ qdd audit # corre las pruebas y las reglas de QDD; funciona desde cualquier
|
|
|
36
36
|
- `qdd doctor`: Diagnóstico determinista de salud del entorno.
|
|
37
37
|
- `qdd report`: Reporte ejecutivo consolidado en formato Texto, Markdown o JSON para CI/CD.
|
|
38
38
|
- `qdd evolution`: Recomienda la siguiente mejora del proyecto.
|
|
39
|
-
- `qdd dashboard
|
|
39
|
+
- `qdd dashboard` (obsoleto; el panel que sigue es `qdd-tareas`): Centro de Comando Web interactivo con streaming en tiempo real (SSE) y ejecución de agentes.
|
|
40
40
|
- `qdd run`: Pipeline secuencial de comandos con rollback, o modo supervisor con auto-reparación (`qdd run --keep-alive`).
|
|
41
41
|
|
|
42
42
|
---
|
package/install.js
CHANGED
|
@@ -142,14 +142,14 @@ function pedirTurno(ruta) {
|
|
|
142
142
|
} catch (err) {
|
|
143
143
|
fallar(`no se pudo escribir en la carpeta del paquete: ${err.message}`);
|
|
144
144
|
}
|
|
145
|
-
process.on('exit', () =>
|
|
145
|
+
process.on('exit', () => borrarSinFallar(ruta));
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// carpetaDeDescarga es propia de este proceso: un postinstall y un primer uso pueden correr a la vez.
|
|
149
149
|
function carpetaDeDescarga() {
|
|
150
150
|
try {
|
|
151
151
|
const carpeta = fs.mkdtempSync(path.join(__dirname, 'descarga-'));
|
|
152
|
-
process.on('exit', () =>
|
|
152
|
+
process.on('exit', () => borrarSinFallar(carpeta));
|
|
153
153
|
return carpeta;
|
|
154
154
|
} catch (err) {
|
|
155
155
|
return fallar(`no se pudo escribir en la carpeta del paquete: ${err.message}`);
|
|
@@ -239,18 +239,55 @@ function respondeBinario(ruta) {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
242
|
+
// En Windows, un antivirus puede retener unos segundos el qdd.exe que se acaba de ejecutar (#175).
|
|
243
|
+
const OCUPADO = new Set(['EBUSY', 'EPERM']);
|
|
244
|
+
const ESPERA_OCUPADO_MS = 1000;
|
|
245
|
+
const INTENTOS_OCUPADO = 30;
|
|
246
|
+
|
|
247
|
+
function dormirSincrono(ms) {
|
|
248
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// moverBinario copia si el destino está en otro volumen (el prefijo de npm y %LOCALAPPDATA% pueden estarlo) o si el
|
|
252
|
+
// binario sigue ocupado tras unos 30 s: copiar solo necesita leerlo.
|
|
253
|
+
function moverBinario(origen, destino, renombrar = fs.renameSync, { dormir = dormirSincrono, intentos = INTENTOS_OCUPADO } = {}) {
|
|
254
|
+
for (let i = 0; ; i++) {
|
|
255
|
+
try {
|
|
256
|
+
renombrar(origen, destino);
|
|
257
|
+
return;
|
|
258
|
+
} catch (err) {
|
|
259
|
+
if (err.code === 'EXDEV') {
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
if (!OCUPADO.has(err.code)) {
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
if (i + 1 >= intentos) {
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
dormir(ESPERA_OCUPADO_MS);
|
|
250
269
|
}
|
|
251
270
|
}
|
|
252
271
|
copiarBinario(origen, destino);
|
|
253
|
-
|
|
272
|
+
borrarSinFallar(origen);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// quitarSiVacia no deja una carpeta de versión sin binario cuando la instalación falla (#175).
|
|
276
|
+
function quitarSiVacia(carpeta) {
|
|
277
|
+
try {
|
|
278
|
+
fs.rmdirSync(carpeta);
|
|
279
|
+
} catch (_) {
|
|
280
|
+
// tiene archivos (otra instalación) o ya no está: se deja.
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// borrarSinFallar: que no se pueda borrar algo temporal no rompe la instalación ni tapa su mensaje (#175).
|
|
285
|
+
function borrarSinFallar(ruta) {
|
|
286
|
+
try {
|
|
287
|
+
fs.rmSync(ruta, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error(`[QDD] No se pudo borrar ${ruta}: ${err.message}`);
|
|
290
|
+
}
|
|
254
291
|
}
|
|
255
292
|
|
|
256
293
|
// copiarBinario nunca deja un binario a medias con el nombre final.
|
|
@@ -311,7 +348,12 @@ function instalarDescarga({ os, paquete, carpeta, binaryName, binDir, env, desti
|
|
|
311
348
|
fs.chmodSync(extraido, 0o755);
|
|
312
349
|
execFileSync(extraido, ['--version'], { stdio: 'pipe', timeout: TOPE_VERSION_MS });
|
|
313
350
|
fs.mkdirSync(path.dirname(destino), { recursive: true });
|
|
314
|
-
|
|
351
|
+
try {
|
|
352
|
+
moverBinario(extraido, destino);
|
|
353
|
+
} catch (err) {
|
|
354
|
+
quitarSiVacia(path.dirname(destino));
|
|
355
|
+
throw err;
|
|
356
|
+
}
|
|
315
357
|
fs.rmSync(paquete, { force: true });
|
|
316
358
|
return destino;
|
|
317
359
|
}
|