@danhachuel/thunderbolt 0.4.70 → 0.4.72

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
@@ -1856,7 +1856,7 @@ def format_metric_number(value: Any) -> str:
1856
1856
 
1857
1857
 
1858
1858
  def classify_channel_platform(channel: Any) -> str:
1859
- """Return the persisted platform, or unknown when it is not explicit."""
1859
+ """Classify channels while keeping legacy YouTube records visible."""
1860
1860
  if not isinstance(channel, dict):
1861
1861
  return "unknown"
1862
1862
  value = str(channel.get("platform") or "").strip().casefold().replace(" ", "")
@@ -1864,7 +1864,14 @@ def classify_channel_platform(channel: Any) -> str:
1864
1864
  return "youtube"
1865
1865
  if value in {"tiktok", "tik-tok", "tt"}:
1866
1866
  return "tiktok"
1867
- return "unknown"
1867
+ def has_tiktok_marker(item: Any) -> bool:
1868
+ if isinstance(item, dict):
1869
+ return any(has_tiktok_marker(key) or has_tiktok_marker(value) for key, value in item.items())
1870
+ if isinstance(item, (list, tuple, set)):
1871
+ return any(has_tiktok_marker(value) for value in item)
1872
+ normalized = str(item or "").strip().casefold().replace(" ", "")
1873
+ return "tiktok" in normalized or normalized == "tik-tok"
1874
+ return "tiktok" if has_tiktok_marker(channel) else "youtube"
1868
1875
 
1869
1876
 
1870
1877
  def _tiktok_channel_records() -> list[dict[str, Any]]:
@@ -18,6 +18,7 @@ import requests
18
18
  PACKAGE_NAME = "@danhachuel/thunderbolt"
19
19
  REGISTRY_URL = "https://registry.npmjs.org/@danhachuel/thunderbolt/latest"
20
20
  UPDATE_TIMEOUT_SECONDS = 20 * 60
21
+ LAUNCHER_RESTART_EXIT_CODE = 75
21
22
 
22
23
 
23
24
  @dataclass(frozen=True)
@@ -44,7 +45,9 @@ class UpdateResult:
44
45
 
45
46
 
46
47
  def restart_current_process(*, exec_fn: Callable[..., Any] = os.execv) -> None:
47
- """Replace the running Streamlit process with the same command line."""
48
+ """Ask the launcher to restart Streamlit, or re-exec standalone callers."""
49
+ if os.environ.get("THUNDERBOLT_LAUNCHER_RESTART") == "1":
50
+ raise SystemExit(LAUNCHER_RESTART_EXIT_CODE)
48
51
  executable = sys.executable
49
52
  exec_fn(executable, [executable, *sys.argv])
50
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/thunderbolt",
3
- "version": "0.4.70",
3
+ "version": "0.4.72",
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
@@ -242,23 +242,49 @@ const pipelineWorker = spawn(python, ["-m", "hermes_ui.pipeline_worker"], {
242
242
  env: runtimeEnv,
243
243
  windowsHide: false,
244
244
  });
245
- const child = spawn(python, ["-m", "streamlit", "run", main, "--server.port", String(backendPort), "--server.address", "127.0.0.1"], {
246
- cwd: root,
247
- stdio: "ignore",
248
- env: runtimeEnv,
249
- windowsHide: false,
250
- });
245
+ const restartExitCode = 75;
246
+ let shuttingDown = false;
247
+ let child;
248
+
249
+ function startStreamlit() {
250
+ child = spawn(python, ["-m", "streamlit", "run", main, "--server.port", String(backendPort), "--server.address", "127.0.0.1"], {
251
+ cwd: root,
252
+ stdio: "ignore",
253
+ env: { ...runtimeEnv, THUNDERBOLT_LAUNCHER_RESTART: "1" },
254
+ windowsHide: false,
255
+ });
256
+ child.on("exit", (code, signal) => {
257
+ if (shuttingDown) {
258
+ stopWorker();
259
+ process.exit(code ?? (signal ? 1 : 0));
260
+ }
261
+ if (code === restartExitCode) {
262
+ const executable = platform() === "win32" ? "npx.cmd" : "npx";
263
+ const replacement = spawn(executable, ["--yes", "--prefer-online", "@danhachuel/thunderbolt"], {
264
+ cwd: userHome,
265
+ env: process.env,
266
+ detached: true,
267
+ stdio: "ignore",
268
+ windowsHide: false,
269
+ });
270
+ replacement.unref();
271
+ stopWorker();
272
+ process.exit(0);
273
+ }
274
+ stopWorker();
275
+ process.exit(code ?? (signal ? 1 : 0));
276
+ });
277
+ }
278
+
279
+ startStreamlit();
251
280
 
252
281
  const stopWorker = () => {
282
+ shuttingDown = true;
253
283
  proxy.close();
254
284
  if (!worker.killed) worker.kill();
255
285
  if (!pipelineWorker.killed) pipelineWorker.kill();
256
286
  };
257
287
  process.on("SIGINT", stopWorker);
258
288
  process.on("SIGTERM", stopWorker);
259
- child.on("exit", (code, signal) => {
260
- stopWorker();
261
- process.exit(code ?? (signal ? 1 : 0));
262
- });
263
289
  worker.on("error", (error) => console.error(`Thunderbolt worker: ${error.message}`));
264
290
  pipelineWorker.on("error", (error) => console.error(`Thunderbolt pipeline worker: ${error.message}`));