@danhachuel/leadmaster 0.1.10 → 0.1.12

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 (24) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/backend/__pycache__/main.cpython-311.pyc +0 -0
  3. package/backend/main.py +45 -10
  4. package/backend/services/__pycache__/__init__.cpython-311.pyc +0 -0
  5. package/backend/services/__pycache__/agents.cpython-311.pyc +0 -0
  6. package/backend/services/__pycache__/crm_agent.cpython-311.pyc +0 -0
  7. package/backend/services/__pycache__/extractors.cpython-311.pyc +0 -0
  8. package/backend/services/__pycache__/flags.cpython-311.pyc +0 -0
  9. package/backend/services/__pycache__/llm.cpython-311.pyc +0 -0
  10. package/backend/services/__pycache__/storage.cpython-311.pyc +0 -0
  11. package/backend/services/extractors.py +49 -0
  12. package/backend/tests/__pycache__/conftest.cpython-311-pytest-8.4.2.pyc +0 -0
  13. package/backend/tests/__pycache__/test_crm_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  14. package/backend/tests/__pycache__/test_instagram_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  15. package/backend/tests/__pycache__/test_launcher_protections.cpython-311-pytest-8.4.2.pyc +0 -0
  16. package/backend/tests/__pycache__/test_maps_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  17. package/backend/tests/__pycache__/test_process_flags.cpython-311-pytest-8.4.2.pyc +0 -0
  18. package/backend/tests/test_instagram_extractor.py +51 -0
  19. package/backend/tests/test_launcher_protections.py +17 -3
  20. package/frontend/dist/assets/{index-lA_S1NDH.js → index-CLRV7oRl.js} +18 -18
  21. package/frontend/dist/assets/{index-D53_Dmef.css → index-D6u6-7Rs.css} +1 -1
  22. package/frontend/dist/index.html +2 -2
  23. package/package.json +1 -1
  24. package/scripts/cli.mjs +61 -2
package/scripts/cli.mjs CHANGED
@@ -30,6 +30,21 @@ import path from 'node:path';
30
30
  import { fileURLToPath } from 'node:url';
31
31
  import http from 'node:http';
32
32
 
33
+ // ---------------------------------------------------------------------------
34
+ // Erros globais (blindagem anti-encerramento silencioso)
35
+ // Rejeições e exceções não tratadas são APENAS LOGADAS — nunca devem derrubar
36
+ // o launcher sem explicação (era assim que o MobaXterm perdia o processo sem
37
+ // deixar rastro). O launcher só termina pelo fluxo normal: erro acionável,
38
+ // parada legítima (SIGTERM/SIGBREAK) ou morte do servidor Python filho.
39
+ // NUNCA REMOVER (regra inviolável do AGENTS.md).
40
+ // ---------------------------------------------------------------------------
41
+ process.on('unhandledRejection', (reason) => {
42
+ console.error('Unhandled Rejection:', reason);
43
+ });
44
+ process.on('uncaughtException', (err) => {
45
+ console.error('Uncaught Exception:', err);
46
+ });
47
+
33
48
  const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
34
49
 
35
50
  // Porta padrão da UI/API local; se estiver ocupada, o launcher avança
@@ -372,6 +387,10 @@ function cmdStart(args) {
372
387
  const url = `http://127.0.0.1:${porta}`;
373
388
  if (jaRodando) {
374
389
  console.log(`ℹ LeadMaster já está rodando em ${url} — abra o endereço no navegador.`);
390
+ // Saída INFORMATIVA (antes de qualquer inicialização própria): não há
391
+ // servidor filho para supervisionar nem terminal para prender — o
392
+ // launcher não deve chamar process.exit(0) no caminho de SUCESSO da
393
+ // inicialização (regra inviolável do AGENTS.md).
375
394
  process.exit(0);
376
395
  return;
377
396
  }
@@ -438,6 +457,28 @@ function cmdStart(args) {
438
457
  process.exit(code === null ? 1 : code);
439
458
  });
440
459
 
460
+ // Ciclo de vida vinculado (regra inviolável do AGENTS.md): se o Python
461
+ // cai, o launcher cai junto — nunca fica preso ao terminal sem servidor.
462
+ // O worker nunca é desreferenciado do event loop: o pai não pode morrer
463
+ // sozinho enquanto o filho vive.
464
+ child.on('close', (code) => {
465
+ console.log('Servidor encerrado');
466
+ process.exit(code === null ? 1 : code);
467
+ });
468
+
469
+ // Launcher morrendo encerra o worker e vice-versa (regra inviolável):
470
+ // qualquer caminho de saída (erro inesperado, falha de health, sinais)
471
+ // leva o worker Python junto — nada de processos órfãos na máquina.
472
+ process.on('exit', () => {
473
+ if (child && child.pid) {
474
+ if (platform() === 'win32') {
475
+ spawnSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { windowsHide: true });
476
+ } else {
477
+ child.kill('SIGTERM');
478
+ }
479
+ }
480
+ });
481
+
441
482
  const stop = () => {
442
483
  console.log('\nEncerrando LeadMaster...');
443
484
  if (platform() === 'win32' && child.pid) {
@@ -447,6 +488,16 @@ function cmdStart(args) {
447
488
  }
448
489
  };
449
490
 
491
+ // Morte do launcher → morte do filho (e vice-versa, via close acima):
492
+ // o uvicorn nunca fica órfão no terminal quando o Node é encerrado.
493
+ process.on('exit', () => {
494
+ try {
495
+ child.kill('SIGTERM');
496
+ } catch {
497
+ /* filho já encerrou — nada a fazer */
498
+ }
499
+ });
500
+
450
501
  console.log(`→ Subindo servidor local em ${url} ...`);
451
502
  const health = await waitForHealth(porta, 120000);
452
503
  if (!health) {
@@ -476,10 +527,18 @@ function cmdStart(args) {
476
527
  process.on('SIGBREAK', naoAbsorver);
477
528
  }
478
529
 
479
- // Keep-alive: mantém o event loop ativo mesmo sem I/O de console (MobaXterm
480
- // minimizado / sem stream ativo) — evita o encerramento silencioso.
530
+ // Keep-alive (regra inviolável do AGENTS.md): mantém o event loop ativo
531
+ // mesmo sem I/O de console (MobaXterm minimizado / sem stream ativo).
481
532
  setInterval(() => {}, 1000);
482
533
 
534
+ // Terminal preso (regra inviolável do AGENTS.md) — SOLUÇÃO DEFINITIVA:
535
+ // ao retomar a entrada padrão IMEDIATAMENTE antes das mensagens finais
536
+ // de sucesso, o Node permanece vivo indefinidamente aguardando qualquer
537
+ // digitação do usuário. O prompt do MobaXterm NUNCA é devolvido e a PTY
538
+ // (e com ela o uvicorn) não é fechada. Esta linha NÃO depende de timers
539
+ // nem de npx — NUNCA REMOVER.
540
+ process.stdin.resume();
541
+
483
542
  console.log(`✓ LeadMaster no ar em ${url} (dados: ${home})`);
484
543
  console.log('');
485
544
  console.log(`ℹ Abra ${url} no navegador quando quiser — o LeadMaster nunca abre janelas sozinho.`);