@danhachuel/thunderbolt 0.5.73 → 0.5.75

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/cli.mjs +75 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.5.73",
3
+ "version": "0.5.75",
4
4
  "description": "Thunderbolt — interface local para operação de canais faceless e motor MoneyPrinterTurbo",
5
5
  "license": "MIT",
6
6
  "main": "scripts/cli.mjs",
package/scripts/cli.mjs CHANGED
@@ -276,14 +276,77 @@ proxy.on("error", (error) => {
276
276
  proxy.listen(publicPort, "127.0.0.1", () => {
277
277
  console.log(`Thunderbolt: interface disponível em http://localhost:${publicPort}/`);
278
278
  });
279
- // Workers contínuos só devem ser iniciados explicitamente com `worker` ou
280
- // `pipeline-worker`; o arranque normal da interface não cria processos Python
281
- // em background nem faz polling periódico.
282
- const worker = null;
283
- const pipelineWorker = null;
279
+ // Os workers são geridos pelo launcher para que um clique em Start na UI
280
+ // também active o processamento, mesmo sem automação de canal configurada.
281
+ // Cada worker só existe enquanto a respectiva fila tiver trabalho pendente.
282
+ let worker = null;
283
+ let pipelineWorker = null;
284
284
  const restartExitCode = 75;
285
285
  let shuttingDown = false;
286
286
  let child;
287
+ let workerRestartTimer = null;
288
+ let pipelineRestartTimer = null;
289
+ let workerMonitorTimer = null;
290
+
291
+ function startAutomationWorker() {
292
+ if (shuttingDown || worker || !hasScheduledAutomation()) return;
293
+ worker = spawn(python, ["-m", "hermes_ui.automation_worker"], {
294
+ cwd: root,
295
+ stdio: "inherit",
296
+ env: runtimeEnv,
297
+ windowsHide: false,
298
+ });
299
+ worker.on("error", (error) => console.error(`Thunderbolt worker: ${error.message}`));
300
+ worker.on("exit", (code, signal) => {
301
+ worker = null;
302
+ if (shuttingDown) return;
303
+ console.error(`Thunderbolt worker: terminou (código ${code ?? "-"}, sinal ${signal ?? "-"}).`);
304
+ if (hasScheduledAutomation()) {
305
+ workerRestartTimer = setTimeout(() => {
306
+ workerRestartTimer = null;
307
+ startAutomationWorker();
308
+ }, 5000);
309
+ }
310
+ });
311
+ }
312
+
313
+ function stopPipelineWorker() {
314
+ if (pipelineRestartTimer) {
315
+ clearTimeout(pipelineRestartTimer);
316
+ pipelineRestartTimer = null;
317
+ }
318
+ if (pipelineWorker && !pipelineWorker.killed) pipelineWorker.kill();
319
+ pipelineWorker = null;
320
+ }
321
+
322
+ function startPipelineWorker() {
323
+ if (shuttingDown || pipelineWorker || !hasPendingPipelineWork()) return;
324
+ pipelineWorker = spawn(python, ["-m", "hermes_ui.pipeline_worker"], {
325
+ cwd: root,
326
+ stdio: "inherit",
327
+ env: runtimeEnv,
328
+ windowsHide: false,
329
+ });
330
+ pipelineWorker.on("error", (error) => console.error(`Thunderbolt pipeline worker: ${error.message}`));
331
+ pipelineWorker.on("exit", (code, signal) => {
332
+ pipelineWorker = null;
333
+ if (shuttingDown) return;
334
+ console.error(`Thunderbolt pipeline worker: terminou (código ${code ?? "-"}, sinal ${signal ?? "-"}).`);
335
+ if (hasPendingPipelineWork()) {
336
+ pipelineRestartTimer = setTimeout(() => {
337
+ pipelineRestartTimer = null;
338
+ startPipelineWorker();
339
+ }, 5000);
340
+ }
341
+ });
342
+ }
343
+
344
+ function monitorWorkers() {
345
+ if (shuttingDown) return;
346
+ if (hasPendingPipelineWork()) startPipelineWorker();
347
+ else if (pipelineWorker) stopPipelineWorker();
348
+ startAutomationWorker();
349
+ }
287
350
 
288
351
  function startStreamlit() {
289
352
  child = spawn(python, [streamlitBootstrap, "run", main, "--server.port", String(backendPort), "--server.address", "127.0.0.1"], {
@@ -323,10 +386,14 @@ startStreamlit();
323
386
  const stopWorker = () => {
324
387
  shuttingDown = true;
325
388
  proxy.close();
389
+ if (workerRestartTimer) clearTimeout(workerRestartTimer);
390
+ if (workerMonitorTimer) clearInterval(workerMonitorTimer);
326
391
  if (worker && !worker.killed) worker.kill();
327
- if (pipelineWorker && !pipelineWorker.killed) pipelineWorker.kill();
392
+ stopPipelineWorker();
328
393
  };
329
394
  process.on("SIGINT", stopWorker);
330
395
  process.on("SIGTERM", stopWorker);
331
- worker?.on("error", (error) => console.error(`Thunderbolt worker: ${error.message}`));
332
- pipelineWorker?.on("error", (error) => console.error(`Thunderbolt pipeline worker: ${error.message}`));
396
+ monitorWorkers();
397
+ // O launcher verifica apenas os JSONs locais; não existe timer no Streamlit
398
+ // nem worker persistente quando não há tarefa pendente.
399
+ workerMonitorTimer = setInterval(monitorWorkers, 2000);