@danhachuel/thunderbolt 0.5.90 → 0.5.92

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/app/main.py CHANGED
@@ -4874,12 +4874,16 @@ def _render_video_task_state(task: dict[str, Any]) -> None:
4874
4874
  st.caption(f"Manifesto: {task.get('video_result')}")
4875
4875
 
4876
4876
 
4877
- def _start_pipeline_task(task_id: str, state: str) -> None:
4877
+ def _start_pipeline_task(task_id: str, state: str) -> bool:
4878
4878
  """Start or retry a video task from any platform automation card."""
4879
4879
  if state in {"blocked", "failed"}:
4880
- retry_task_with_current_settings(task_id)
4880
+ updated = retry_task_with_current_settings(task_id)
4881
4881
  else:
4882
- transition_task(task_id, "doing")
4882
+ updated = transition_task(task_id, "doing")
4883
+ if not updated:
4884
+ st.error("Não foi possível iniciar este vídeo: a tarefa já não existe na fila.")
4885
+ return False
4886
+ return True
4883
4887
 
4884
4888
 
4885
4889
  def render_videos():
@@ -5386,11 +5390,8 @@ def _render_youtube_automation_cards():
5386
5390
  start_col, stop_col, delete_col = st.columns(3)
5387
5391
  with start_col:
5388
5392
  if st.button("Start", key=f"automation_start_{task['id']}", use_container_width=True, disabled=state not in {"to_do", "blocked", "failed"}):
5389
- if state in {"failed", "blocked"}:
5390
- retry_task_with_current_settings(task["id"])
5391
- else:
5392
- transition_task(task["id"], "doing")
5393
- st.rerun()
5393
+ if _start_pipeline_task(str(task["id"]), state):
5394
+ st.rerun()
5394
5395
  with stop_col:
5395
5396
  if st.button("Stop", key=f"automation_stop_{task['id']}", use_container_width=True, disabled=state != "doing"):
5396
5397
  stop_task_by_user(task["id"])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.5.90",
3
+ "version": "0.5.92",
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
@@ -26,7 +26,8 @@ const venvPython = platform() === "win32" ? join(venvDir, "Scripts", "python.exe
26
26
  const python = process.env.THUNDERBOLT_PYTHON || process.env.HERMES_PYTHON || (existsSync(venvPython) ? venvPython : (platform() === "win32" ? "python" : "python3"));
27
27
  const main = resolve(root, "app", "main.py");
28
28
  const streamlitBootstrap = resolve(root, "scripts", "streamlit_bootstrap.py");
29
- const settingsPath = join(thunderboltHome, "storage", "state", "settings.json");
29
+ const storageDir = process.env.THUNDERBOLT_STORAGE_DIR || join(thunderboltHome, "storage");
30
+ const settingsPath = join(storageDir, "state", "settings.json");
30
31
  const pythonEnvironment = { ...process.env, PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1", PYTHONLEGACYWINDOWSSTDIO: "1", CLICK_NO_WIN_CONSOLE: "1" };
31
32
 
32
33
  function run(command, commandArgs, label = "comando", environment = process.env) {
@@ -68,7 +69,7 @@ function configuredMoneyPrinterPath() {
68
69
  }
69
70
 
70
71
  function readStateJson(filename, fallback = []) {
71
- try { return JSON.parse(readFileSync(join(thunderboltHome, "storage", "state", filename), "utf8")); }
72
+ try { return JSON.parse(readFileSync(join(storageDir, "state", filename), "utf8")); }
72
73
  catch { return fallback; }
73
74
  }
74
75
 
@@ -85,7 +86,7 @@ function hasPendingPipelineWork() {
85
86
  }
86
87
 
87
88
  function ensureRuntimeStorage() {
88
- const storageRoot = process.env.THUNDERBOLT_STORAGE_DIR || join(thunderboltHome, "storage");
89
+ const storageRoot = storageDir;
89
90
  const directories = [
90
91
  storageRoot,
91
92
  join(storageRoot, "state"),
@@ -168,7 +169,6 @@ if (!existsSync(main)) {
168
169
  process.exit(1);
169
170
  }
170
171
  ensureRuntimeStorage();
171
- const storageDir = process.env.THUNDERBOLT_STORAGE_DIR || join(thunderboltHome, "storage");
172
172
  const runtimeEnv = {
173
173
  ...process.env,
174
174
  PYTHONIOENCODING: "utf-8",
@@ -322,7 +322,7 @@ function stopPipelineWorker() {
322
322
  }
323
323
 
324
324
  function startPipelineWorker() {
325
- if (shuttingDown || pipelineWorker || !hasPendingPipelineWork()) return;
325
+ if (shuttingDown || pipelineWorker) return;
326
326
  pipelineWorker = spawn(python, ["-m", "hermes_ui.pipeline_worker"], {
327
327
  cwd: root,
328
328
  stdio: "inherit",
@@ -334,19 +334,16 @@ function startPipelineWorker() {
334
334
  pipelineWorker = null;
335
335
  if (shuttingDown) return;
336
336
  console.error(`Thunderbolt pipeline worker: terminou (código ${code ?? "-"}, sinal ${signal ?? "-"}).`);
337
- if (hasPendingPipelineWork()) {
338
- pipelineRestartTimer = setTimeout(() => {
339
- pipelineRestartTimer = null;
340
- startPipelineWorker();
341
- }, 5000);
342
- }
337
+ pipelineRestartTimer = setTimeout(() => {
338
+ pipelineRestartTimer = null;
339
+ startPipelineWorker();
340
+ }, 5000);
343
341
  });
344
342
  }
345
343
 
346
344
  function monitorWorkers() {
347
345
  if (shuttingDown) return;
348
- if (hasPendingPipelineWork()) startPipelineWorker();
349
- else if (pipelineWorker) stopPipelineWorker();
346
+ startPipelineWorker();
350
347
  startAutomationWorker();
351
348
  }
352
349
 
@@ -396,6 +393,6 @@ const stopWorker = () => {
396
393
  process.on("SIGINT", stopWorker);
397
394
  process.on("SIGTERM", stopWorker);
398
395
  monitorWorkers();
399
- // O launcher verifica apenas os JSONs locais; não existe timer no Streamlit
400
- // nem worker persistente quando não há tarefa pendente.
396
+ // O pipeline worker permanece disponível para recolher imediatamente tarefas
397
+ // colocadas em `doing` pelo botão Start, mesmo quando a fila estava vazia.
401
398
  workerMonitorTimer = setInterval(monitorWorkers, 2000);