@danhachuel/leadmaster 0.1.23 → 0.1.24

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 (28) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/backend/__pycache__/main.cpython-311.pyc +0 -0
  3. package/backend/services/__pycache__/__init__.cpython-311.pyc +0 -0
  4. package/backend/services/__pycache__/agents.cpython-311.pyc +0 -0
  5. package/backend/services/__pycache__/crm_agent.cpython-311.pyc +0 -0
  6. package/backend/services/__pycache__/extractors.cpython-311.pyc +0 -0
  7. package/backend/services/__pycache__/flags.cpython-311.pyc +0 -0
  8. package/backend/services/__pycache__/llm.cpython-311.pyc +0 -0
  9. package/backend/services/__pycache__/storage.cpython-311.pyc +0 -0
  10. package/backend/tests/__pycache__/conftest.cpython-311-pytest-8.4.2.pyc +0 -0
  11. package/backend/tests/__pycache__/test_agents_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  12. package/backend/tests/__pycache__/test_campaigns_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  13. package/backend/tests/__pycache__/test_cnpj_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  14. package/backend/tests/__pycache__/test_config.cpython-311-pytest-8.4.2.pyc +0 -0
  15. package/backend/tests/__pycache__/test_crm_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  16. package/backend/tests/__pycache__/test_extractors_real.cpython-311-pytest-8.4.2.pyc +0 -0
  17. package/backend/tests/__pycache__/test_funnel_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  18. package/backend/tests/__pycache__/test_instagram_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  19. package/backend/tests/__pycache__/test_launcher_protections.cpython-311-pytest-8.4.2.pyc +0 -0
  20. package/backend/tests/__pycache__/test_maps_extractor.cpython-311-pytest-8.4.2.pyc +0 -0
  21. package/backend/tests/__pycache__/test_metrics.cpython-311-pytest-8.4.2.pyc +0 -0
  22. package/backend/tests/__pycache__/test_process_flags.cpython-311-pytest-8.4.2.pyc +0 -0
  23. package/backend/tests/__pycache__/test_webhook_routes.cpython-311-pytest-8.4.2.pyc +0 -0
  24. package/backend/tests/test_launcher_protections.py +31 -0
  25. package/frontend/dist/assets/{index-Bc1EFZVI.js → index-B_SzrvJP.js} +1 -1
  26. package/frontend/dist/index.html +1 -1
  27. package/package.json +1 -1
  28. package/scripts/cli.mjs +10 -0
package/CHANGELOG.md CHANGED
@@ -37,6 +37,38 @@ normaliza para a forma canônica (ex.: `0.1.0`).
37
37
  falha se `process.stdin.resume();` desaparecer, se `.unref()` aparecer, se o
38
38
  ciclo de vida vinculado for removido ou se os handlers globais sumirem.
39
39
 
40
+ ## [0.1.24] — 2026-11-09
41
+
42
+ ### Corrigido
43
+
44
+ - **Launcher — regressão do terminal preso investigada e blindagem reforçada** —
45
+ usuário reportou o prompt do MobaXterm voltando logo após "LeadMaster no ar"
46
+ na 0.1.21 (runtime permanente). A investigação mostrou que o fluxo publicado
47
+ **mantém** as proteções (`process.stdin.resume();`, `setInterval`,
48
+ `child.on('exit')`/`close`, `process.on('exit')`, sem `.unref()`) e que uma
49
+ morte silenciosa assim — sem nenhum log do handler de saída — só ocorre por
50
+ `SIGKILL`/`taskkill /F` (ex.: outra execução `install`/`start` matando a
51
+ instância anterior pelo kill switch, ou fechamento forçado da aba). Mesmo
52
+ assim, o launcher foi reforçado e os gates agora validam o **fluxo**:
53
+ - **Rede de segurança no `cmdStart`:** `process.on('beforeExit')` re-arma o
54
+ `setInterval` se o event loop esvaziar (stdin em EOF, timer perdido,
55
+ surpresa de PTY) — o Node jamais encerra sozinho; erros do stream de
56
+ stdin (`process.stdin.on('error')`) são ignorados;
57
+ - **Gates de fluxo (`test_launcher_protections.py`):** novo helper
58
+ `_corpo_cmd_start()` extrai o corpo da função para garantir que
59
+ `spawn`, `process.stdin.resume();`, `setInterval`, `child.on('exit')`,
60
+ `child.on('close')`, `process.on('exit')` e `beforeExit` existam **dentro
61
+ do `start`** (não no `install` nem em função morta) e que **nenhum
62
+ `process.exit(`** apareça após o terminal ser preso — a saída só por ciclo
63
+ de vida do filho ou por `SIGTERM`/`SIGBREAK`;
64
+ - **AGENTS.md:** regra 2 do launcher documenta a rede de segurança e a
65
+ exigência de posição (após o spawn, no fluxo do start).
66
+ - **Diagnóstico rápido para o usuário:** com a regra acima, se o prompt voltar
67
+ sem as linhas "Encerrando LeadMaster..." (SIGTERM/SIGBREAK) ou "Servidor
68
+ local encerrou com código N" (Python caiu), a causa é externa ao launcher
69
+ (outra execução ou fechamento forçado) — o espelho
70
+ `storage/logs/launcher_console.log` mostra exatamente qual caminho ocorreu.
71
+
40
72
  ## [0.1.23] — 2026-11-09
41
73
 
42
74
  ### Adicionado
@@ -23,6 +23,15 @@ def _conteudo() -> str:
23
23
  return CAMINHO.read_text(encoding="utf-8")
24
24
 
25
25
 
26
+ def _corpo_cmd_start() -> str:
27
+ """Corpo da função cmdStart — valida o FLUXO do start (não só strings)."""
28
+ c = _conteudo()
29
+ assert "function cmdStart(" in c, "função cmdStart não encontrada"
30
+ inicio = c.index("function cmdStart(")
31
+ fim = c.index("async function cmdDoctor")
32
+ return c[inicio:fim]
33
+
34
+
26
35
  class TestLauncherProtections:
27
36
  def test_keepalivo(self):
28
37
  assert "setInterval(() => {}, 1000)" in _conteudo()
@@ -44,6 +53,28 @@ class TestLauncherProtections:
44
53
  # Avisar que já existe instância no ar é proibido (impede atualizações).
45
54
  assert "já está rodando" not in c
46
55
 
56
+ def test_keepalive_no_fluxo_do_start(self):
57
+ # Gate de FLUXO (regressão da 0.1.21): as proteções precisam existir
58
+ # dentro do cmdStart — no install, em função morta ou em bloco errado
59
+ # não valem. A morte prematura do Node devolve o prompt do MobaXterm.
60
+ corpo = _corpo_cmd_start()
61
+ assert "spawn(" in corpo # worker Python é spawnado no start
62
+ assert "process.stdin.resume();" in corpo # terminal preso
63
+ assert "setInterval(() => {}, 1000)" in corpo # keep-alive
64
+ assert "beforeExit" in corpo # rede de segurança do event loop
65
+ assert "child.on('exit'" in corpo or 'child.on("exit"' in corpo
66
+ assert "child.on('close'" in corpo or 'child.on("close"' in corpo
67
+ assert "process.on('exit'" in corpo or 'process.on("exit"' in corpo
68
+
69
+ def test_start_nunca_chama_exit_apos_terminal_preso(self):
70
+ # Após o terminal ser preso, nenhum caminho de sucesso chama
71
+ # process.exit — a saída só ocorre pelo ciclo de vida do filho
72
+ # (child exit/close) ou por sinais de parada legítima.
73
+ corpo = _corpo_cmd_start()
74
+ pos = corpo.index("process.stdin.resume();")
75
+ fim_iife = corpo.index("})().catch(") # catch de erro fatal fica de fora
76
+ assert "process.exit(" not in corpo[pos:fim_iife]
77
+
47
78
  def test_ciclo_de_vida_vinculado(self):
48
79
  c = _conteudo()
49
80
  assert "child.on('exit'" in c or "child.on(\"exit\"" in c
@@ -64,7 +64,7 @@ Error generating stack: `+i.message+`
64
64
  * LICENSE.md file in the root directory of this source tree.
65
65
  *
66
66
  * @license MIT
67
- */function Fl(){return Fl=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var s in n)({}).hasOwnProperty.call(n,s)&&(t[s]=n[s])}return t},Fl.apply(null,arguments)}function my(t,e){if(t==null)return{};var n={};for(var s in t)if({}.hasOwnProperty.call(t,s)){if(e.indexOf(s)!==-1)continue;n[s]=t[s]}return n}function QS(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function KS(t,e){return t.button===0&&(!e||e==="_self")&&!QS(t)}const YS=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],XS=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],qS="6";try{window.__reactRouterVersion=qS}catch{}const GS=S.createContext({isTransitioning:!1}),JS="startTransition",Kp=lb[JS];function ZS(t){let{basename:e,children:n,future:s,window:r}=t,i=S.useRef();i.current==null&&(i.current=rS({window:r,v5Compat:!0}));let o=i.current,[a,l]=S.useState({action:o.action,location:o.location}),{v7_startTransition:c}=s||{},d=S.useCallback(f=>{c&&Kp?Kp(()=>l(f)):l(f)},[l,c]);return S.useLayoutEffect(()=>o.listen(d),[o,d]),S.useEffect(()=>WS(s),[s]),S.createElement(HS,{basename:e,children:n,location:a.location,navigationType:a.action,navigator:o,future:s})}const e_=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",t_=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,n_=S.forwardRef(function(e,n){let{onClick:s,relative:r,reloadDocument:i,replace:o,state:a,target:l,to:c,preventScrollReset:d,viewTransition:f}=e,h=my(e,YS),{basename:p}=S.useContext(Rs),v,x=!1;if(typeof c=="string"&&t_.test(c)&&(v=c,e_))try{let g=new URL(window.location.href),_=c.startsWith("//")?new URL(g.protocol+c):new URL(c),b=pi(_.pathname,p);_.origin===g.origin&&b!=null?c=b+_.search+_.hash:x=!0}catch{}let w=ES(c,{relative:r}),y=r_(c,{replace:o,state:a,target:l,preventScrollReset:d,relative:r,viewTransition:f});function m(g){s&&s(g),g.defaultPrevented||y(g)}return S.createElement("a",Fl({},h,{href:v||w,onClick:x||i?s:m,ref:n,target:l}))}),xy=S.forwardRef(function(e,n){let{"aria-current":s="page",caseSensitive:r=!1,className:i="",end:o=!1,style:a,to:l,viewTransition:c,children:d}=e,f=my(e,XS),h=bc(l,{relative:f.relative}),p=fr(),v=S.useContext(uy),{navigator:x,basename:w}=S.useContext(Rs),y=v!=null&&i_(h)&&c===!0,m=x.encodeLocation?x.encodeLocation(h).pathname:h.pathname,g=p.pathname,_=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;r||(g=g.toLowerCase(),_=_?_.toLowerCase():null,m=m.toLowerCase()),_&&w&&(_=pi(_,w)||_);const b=m!=="/"&&m.endsWith("/")?m.length-1:m.length;let k=g===m||!o&&g.startsWith(m)&&g.charAt(b)==="/",C=_!=null&&(_===m||!o&&_.startsWith(m)&&_.charAt(m.length)==="/"),j={isActive:k,isPending:C,isTransitioning:y},P=k?s:void 0,M;typeof i=="function"?M=i(j):M=[i,k?"active":null,C?"pending":null,y?"transitioning":null].filter(Boolean).join(" ");let E=typeof a=="function"?a(j):a;return S.createElement(n_,Fl({},f,{"aria-current":P,className:M,ref:n,style:E,to:l,viewTransition:c}),typeof d=="function"?d(j):d)});var Td;(function(t){t.UseScrollRestoration="useScrollRestoration",t.UseSubmit="useSubmit",t.UseSubmitFetcher="useSubmitFetcher",t.UseFetcher="useFetcher",t.useViewTransitionState="useViewTransitionState"})(Td||(Td={}));var Yp;(function(t){t.UseFetcher="useFetcher",t.UseFetchers="useFetchers",t.UseScrollRestoration="useScrollRestoration"})(Yp||(Yp={}));function s_(t){let e=S.useContext(yc);return e||Ne(!1),e}function r_(t,e){let{target:n,replace:s,state:r,preventScrollReset:i,relative:o,viewTransition:a}=e===void 0?{}:e,l=ra(),c=fr(),d=bc(t,{relative:o});return S.useCallback(f=>{if(KS(f,n)){f.preventDefault();let h=s!==void 0?s:Il(c)===Il(d);l(t,{replace:h,state:r,preventScrollReset:i,relative:o,viewTransition:a})}},[c,l,d,s,r,n,t,i,o,a])}function i_(t,e){e===void 0&&(e={});let n=S.useContext(GS);n==null&&Ne(!1);let{basename:s}=s_(Td.useViewTransitionState),r=bc(t,{relative:e.relative});if(!n.isTransitioning)return!1;let i=pi(n.currentLocation.pathname,s)||n.currentLocation.pathname,o=pi(n.nextLocation.pathname,s)||n.nextLocation.pathname;return Rd(r.pathname,o)!=null||Rd(r.pathname,i)!=null}const o_="/api";class yy extends Error{constructor(n,s){super(s);$(this,"status");this.status=n,this.name="ApiError"}}async function W(t,e={}){const n=await fetch(o_+t,{...e,headers:e.body?{"Content-Type":"application/json",...e.headers||{}}:e.headers});if(!n.ok){let s=`Erro HTTP ${n.status}`;try{const r=await n.json();s=String(r.detail||r.mensagem||s)}catch{}throw new yy(n.status,s)}if(n.status!==204)return n.json()}const Ce=t=>({method:"POST",body:JSON.stringify(t)}),H={health:()=>W("/health"),doctor:()=>W("/doctor"),shutdown:()=>W("/shutdown",Ce({})),metricas:()=>W("/metrics"),leads:{listar:()=>W("/leads"),criar:t=>W("/leads",Ce(t)),atualizar:(t,e)=>W(`/leads/${t}`,{method:"PATCH",body:JSON.stringify(e)}),remover:t=>W(`/leads/${t}`,{method:"DELETE"}),importar:t=>W("/leads/import",Ce({leads:t})),enriquecer:t=>W(`/leads/${t}/enrich`,Ce({}))},crm:{leadsListar:()=>W("/crm/leads"),criarLead:t=>W("/crm/leads",Ce(t)),moverLead:(t,e)=>W(`/crm/leads/${t}/etapa`,{method:"PUT",body:JSON.stringify({etapa:e})}),sugestoes:()=>W("/crm/sugestoes"),aplicar:(t,e)=>W("/crm/sugestoes/aplicar",Ce({lead_id:t,para:e}))},campanhas:{listar:()=>W("/campaigns"),criar:t=>W("/campaigns",Ce(t)),status:(t,e)=>W(`/campaigns/${t}/status`,{method:"PUT",body:JSON.stringify({status:e})}),iniciar:t=>W(`/campaigns/${t}/start`,Ce({})),pausar:t=>W(`/campaigns/${t}/pause`,Ce({})),parar:t=>W(`/campaigns/${t}/stop`,Ce({})),remover:t=>W(`/campaigns/${t}`,{method:"DELETE"})},extrair:{maps:t=>W("/extractors/maps",Ce(t)),instagram:(t,e)=>W("/extractors/instagram",Ce({profile_url:t,limit:e})),cnpj:t=>W("/extract/cnpj",Ce({cnpj:t})),cnpjBusca:t=>W("/extract/cnpj/search",Ce(t)),cnpjExtract:t=>W("/extractors/cnpj",Ce(t))},config:{obter:()=>W("/config"),salvar:t=>W("/config",{method:"PUT",body:JSON.stringify(t)}),testarLlm:()=>W("/config/test/llm",Ce({})),testarIntegracao:t=>W("/config/test/integracao",Ce({url:t}))},integracoes:()=>W("/integrations/status"),agentes:{listar:()=>W("/agents"),status:(t,e)=>W(`/agents/${t}/status`,Ce({status:e})),salvarPrompt:(t,e)=>W(`/agents/${t}/prompt`,Ce({prompt:e})),templates:()=>W("/agents/templates"),salvarTemplates:t=>W("/agents/templates",{method:"PUT",body:JSON.stringify(t)}),testarTemplate:(t,e)=>W("/agents/templates/test",Ce({template:t,lead_id:e})),chat:t=>W("/agents/attendance/chat",Ce({mensagens:t}))},funil:()=>W("/funnel"),webhook:{obter:()=>W("/webhook"),salvar:t=>W("/webhook",{method:"PUT",body:JSON.stringify(t)}),testar:t=>W("/webhook/test",Ce({url:t}))}};function U(...t){return t.filter(Boolean).join(" ")}function a_(t){return(t||"?").trim().charAt(0).toUpperCase()||"?"}function zo(t){if(!t)return"—";try{return new Date(t).toLocaleString("pt-BR",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"})}catch{return t}}function ia(t){const e=(t||"").replace(/\D/g,"");return e?e.length===11?`(${e.slice(0,2)}) ${e.slice(2,7)}-${e.slice(7)}`:e.length===10?`(${e.slice(0,2)}) ${e.slice(2,6)}-${e.slice(6)}`:t||"—":"—"}function l_(t){const e=["nome","telefone","email","empresa","cidade","observacoes"],n=e.filter(s=>String(t[s]||"").trim().length>0);return Math.round(n.length/e.length*100)}function c_(t){const e={nome:"nome",telefone:"telefone",email:"e-mail",empresa:"empresa",cidade:"cidade",observacoes:"observações"};return["nome","telefone","email","empresa","cidade","observacoes"].filter(s=>String(t[s]||"").trim().length===0).map(s=>e[s])}function u_(t,e){if(t>=100)return"Lead 100% completo — excelente! 🎉";const n=e.slice(0,2).join(" e ");return`Faltam ${100-t}% (${n}${e.length>2?"...":""}) para o lead ficar completo`}function d_(t,e){const n=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=e,r.click(),URL.revokeObjectURL(s)}const f_={md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function qt({aberto:t,onFechar:e,titulo:n,children:s,icone:r="fas fa-circle-info",largura:i="md"}){return S.useEffect(()=>{const o=a=>{a.key==="Escape"&&e()};return t&&window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[t,e]),t?u.jsx("div",{className:"fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4",onMouseDown:o=>{o.target===o.currentTarget&&e()},children:u.jsxs("div",{className:U("bg-white rounded-2xl shadow-xl w-full",f_[i]),children:[u.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[u.jsxs("h3",{className:"text-base font-semibold text-gray-800 flex items-center gap-2",children:[u.jsx("i",{className:U(r,"text-indigo-500")})," ",n]}),u.jsx("button",{onClick:e,className:"text-gray-400 hover:text-gray-600","aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]}),u.jsx("div",{className:"px-6 py-5 max-h-[70vh] overflow-y-auto",children:s})]})}):null}const h_=[{icone:"fas fa-users",texto:"Cadastre leads manualmente ou importe pelos Extratores (Maps, Instagram, CNPJ)."},{icone:"fas fa-columns",texto:"Arraste os cards no CRM conforme avança no funil (Leads → Em contato → Proposta → Fechado)."},{icone:"fas fa-bullhorn",texto:"Monte campanhas de disparo com seus templates e acompanhe as taxas no Painel."},{icone:"fas fa-robot",texto:"Use os Agentes (disparo e atendimento) e configure o LLM em Ferramentas para turbiná-los."}];function p_({titulo:t,nomeUsuario:e}){const[n,s]=S.useState(!1);return u.jsxs("header",{className:"bg-white shadow-sm px-8 py-4 flex items-center justify-between shrink-0",children:[u.jsx("div",{children:u.jsx("h2",{className:"text-lg font-semibold text-gray-800",children:t})}),u.jsxs("div",{className:"flex items-center space-x-4",children:[u.jsxs("button",{onClick:()=>s(!0),className:"text-sm text-indigo-600 hover:text-indigo-800 font-medium",children:[u.jsx("i",{className:"fas fa-play-circle mr-1"})," Ver tutorial"]}),u.jsx("div",{className:"w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 font-bold text-sm",children:a_(e)}),u.jsx("span",{className:"text-sm font-medium text-gray-700",children:e})]}),u.jsxs(qt,{aberto:n,onFechar:()=>s(!1),titulo:"Tutorial rápido",icone:"fas fa-graduation-cap",children:[u.jsx("ol",{className:"space-y-4",children:h_.map((r,i)=>u.jsxs("li",{className:"flex gap-3 items-start",children:[u.jsx("span",{className:"w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center shrink-0",children:u.jsx("i",{className:r.icone})}),u.jsx("p",{className:"text-sm text-gray-600 pt-1.5",children:r.texto})]},i))}),u.jsx("p",{className:"text-xs text-gray-400 mt-5",children:"Dica: o LLM (para enriquecimento e agentes) é configurado em Ferramentas."})]})]})}const g_=[{itens:[{para:"/",icone:"fas fa-chart-pie text-indigo-300",rotulo:"Painel",fim:!0}]},{secao:"Conexões",itens:[{para:"/leads",icone:"fas fa-users",rotulo:"Leads"},{para:"/agentes",icone:"fas fa-robot",rotulo:"Agentes"},{para:"/ferramentas",icone:"fas fa-tools",rotulo:"Ferramentas"}]},{itens:[{para:"/extrator-maps",icone:"fas fa-map-marked-alt",rotulo:"Extrator Maps"},{para:"/extrator-instagram",icone:"fab fa-instagram",rotulo:"Extrator Instagram"},{para:"/extrator-cnpj",icone:"fas fa-building",rotulo:"Extrator CNPJ"}]},{secao:"Gestão",itens:[{para:"/disparos",icone:"fas fa-bullhorn",rotulo:"Disparos"},{para:"/crm",icone:"fas fa-columns",rotulo:"CRM"},{para:"/funil",icone:"fas fa-filter",rotulo:"Funil de Prospecção"}]},{secao:"Integrações",itens:[{para:"/webhook",icone:"fas fa-link",rotulo:"Webhook"},{para:"/suporte",icone:"fas fa-headset",rotulo:"Suporte"}]}];function m_({onSair:t}){const e=fr(),[n,s]=S.useState(!1);S.useEffect(()=>{e.pathname==="/agentes"&&s(!0)},[e.pathname]);const r=i=>{if(i.rotulo==="Agentes")return e.pathname==="/agentes";const[o,a]=i.para.split("?");return a?e.pathname===o&&e.search.includes(a):i.fim?e.pathname===o:e.pathname.startsWith(o)};return u.jsxs("aside",{className:"w-64 bg-[#1e1b4b] text-white flex flex-col shrink-0 h-screen sticky top-0",children:[u.jsx("div",{className:"p-6 border-b border-gray-700",children:u.jsxs("h1",{className:"text-2xl font-bold tracking-tight flex items-center gap-2",children:[u.jsx("span",{className:"text-2xl",children:"⚡"}),"LeadMaster",u.jsxs("span",{className:"text-[10px] font-medium text-indigo-300 border border-indigo-400/40 rounded-md px-1.5 py-0.5",children:["v","0.1.23"]})]})}),u.jsx("nav",{className:"flex-1 overflow-y-auto py-4",children:u.jsx("ul",{className:"space-y-1",children:g_.map((i,o)=>u.jsx("li",{children:u.jsxs("ul",{children:[i.secao&&u.jsx("li",{className:"px-6 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider list-none",children:i.secao}),i.itens.map(a=>a.rotulo==="Agentes"?u.jsxs("li",{children:[u.jsxs("button",{type:"button",onClick:()=>s(l=>!l),className:U("sidebar-link w-full flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:U(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo}),u.jsx("i",{className:U("fas fa-chevron-down ml-auto text-xs text-gray-400 transition-transform",n&&"rotate-180")})]}),n&&u.jsxs("ul",{className:"pl-12 space-y-1 mt-1",children:[u.jsx("li",{children:u.jsx(Xp,{para:"/agentes?tab=disparo",rotulo:"Agente de Disparo",ativo:e.pathname==="/agentes"&&e.search.includes("disparo")})}),u.jsx("li",{children:u.jsx(Xp,{para:"/agentes?tab=atendimento",rotulo:"Agente de Atendimento",ativo:e.pathname==="/agentes"&&e.search.includes("atendimento")})})]})]},"agentes"):u.jsx("li",{children:u.jsxs(xy,{to:a.para,className:U("sidebar-link flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:U(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo})]})},a.para))]})},o))})}),u.jsx("div",{className:"p-4 border-t border-gray-700",children:u.jsxs("button",{onClick:t,className:"w-full flex items-center justify-center px-4 py-2.5 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-lg text-sm font-medium hover:opacity-90 transition",children:[u.jsx("i",{className:"fas fa-sign-out-alt mr-2"})," Sair"]})})]})}function Xp({para:t,rotulo:e,ativo:n}){return u.jsx(xy,{to:t,className:U("sidebar-link block px-4 py-2 text-xs text-gray-300 rounded",n&&"active"),children:e})}const vy=S.createContext({toast:()=>{}});function tn(){return S.useContext(vy)}const x_={sucesso:"bg-green-600",erro:"bg-red-600",info:"bg-indigo-600"},y_={sucesso:"fas fa-check-circle",erro:"fas fa-exclamation-circle",info:"fas fa-info-circle"};function v_({children:t}){const[e,n]=S.useState([]),s=S.useRef(0),r=S.useCallback((i,o)=>{const a=++s.current;n(l=>[...l,{id:a,tipo:i,mensagem:o}]),setTimeout(()=>n(l=>l.filter(c=>c.id!==a)),4500)},[]);return u.jsxs(vy.Provider,{value:{toast:r},children:[t,u.jsx("div",{className:"fixed top-4 right-4 z-[100] space-y-2 w-80",children:e.map(i=>u.jsxs("div",{className:U(x_[i.tipo],"text-white text-sm rounded-lg shadow-lg px-4 py-3 flex items-start gap-2 animate-pulse-once"),role:"status",children:[u.jsx("i",{className:U(y_[i.tipo],"mt-0.5")}),u.jsx("span",{className:"flex-1",children:i.mensagem}),u.jsx("button",{className:"opacity-70 hover:opacity-100",onClick:()=>n(o=>o.filter(a=>a.id!==i.id)),"aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]},i.id))})]})}function Oa({rotulo:t,valor:e,subtitulo:n,children:s,icone:r}){return u.jsxs("div",{className:"bg-white rounded-xl shadow-sm p-5 border border-gray-100",children:[u.jsxs("div",{className:"flex items-center justify-between",children:[u.jsx("p",{className:"text-sm text-gray-500 font-medium",children:t}),r&&u.jsx("i",{className:`${r} text-indigo-300`})]}),s??u.jsxs(u.Fragment,{children:[u.jsx("p",{className:"text-2xl font-bold text-gray-800 mt-1",children:e}),n&&u.jsx("p",{className:"text-xs text-gray-400 mt-0.5",children:n})]})]})}/*!
67
+ */function Fl(){return Fl=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var s in n)({}).hasOwnProperty.call(n,s)&&(t[s]=n[s])}return t},Fl.apply(null,arguments)}function my(t,e){if(t==null)return{};var n={};for(var s in t)if({}.hasOwnProperty.call(t,s)){if(e.indexOf(s)!==-1)continue;n[s]=t[s]}return n}function QS(t){return!!(t.metaKey||t.altKey||t.ctrlKey||t.shiftKey)}function KS(t,e){return t.button===0&&(!e||e==="_self")&&!QS(t)}const YS=["onClick","relative","reloadDocument","replace","state","target","to","preventScrollReset","viewTransition"],XS=["aria-current","caseSensitive","className","end","style","to","viewTransition","children"],qS="6";try{window.__reactRouterVersion=qS}catch{}const GS=S.createContext({isTransitioning:!1}),JS="startTransition",Kp=lb[JS];function ZS(t){let{basename:e,children:n,future:s,window:r}=t,i=S.useRef();i.current==null&&(i.current=rS({window:r,v5Compat:!0}));let o=i.current,[a,l]=S.useState({action:o.action,location:o.location}),{v7_startTransition:c}=s||{},d=S.useCallback(f=>{c&&Kp?Kp(()=>l(f)):l(f)},[l,c]);return S.useLayoutEffect(()=>o.listen(d),[o,d]),S.useEffect(()=>WS(s),[s]),S.createElement(HS,{basename:e,children:n,location:a.location,navigationType:a.action,navigator:o,future:s})}const e_=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u",t_=/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i,n_=S.forwardRef(function(e,n){let{onClick:s,relative:r,reloadDocument:i,replace:o,state:a,target:l,to:c,preventScrollReset:d,viewTransition:f}=e,h=my(e,YS),{basename:p}=S.useContext(Rs),v,x=!1;if(typeof c=="string"&&t_.test(c)&&(v=c,e_))try{let g=new URL(window.location.href),_=c.startsWith("//")?new URL(g.protocol+c):new URL(c),b=pi(_.pathname,p);_.origin===g.origin&&b!=null?c=b+_.search+_.hash:x=!0}catch{}let w=ES(c,{relative:r}),y=r_(c,{replace:o,state:a,target:l,preventScrollReset:d,relative:r,viewTransition:f});function m(g){s&&s(g),g.defaultPrevented||y(g)}return S.createElement("a",Fl({},h,{href:v||w,onClick:x||i?s:m,ref:n,target:l}))}),xy=S.forwardRef(function(e,n){let{"aria-current":s="page",caseSensitive:r=!1,className:i="",end:o=!1,style:a,to:l,viewTransition:c,children:d}=e,f=my(e,XS),h=bc(l,{relative:f.relative}),p=fr(),v=S.useContext(uy),{navigator:x,basename:w}=S.useContext(Rs),y=v!=null&&i_(h)&&c===!0,m=x.encodeLocation?x.encodeLocation(h).pathname:h.pathname,g=p.pathname,_=v&&v.navigation&&v.navigation.location?v.navigation.location.pathname:null;r||(g=g.toLowerCase(),_=_?_.toLowerCase():null,m=m.toLowerCase()),_&&w&&(_=pi(_,w)||_);const b=m!=="/"&&m.endsWith("/")?m.length-1:m.length;let k=g===m||!o&&g.startsWith(m)&&g.charAt(b)==="/",C=_!=null&&(_===m||!o&&_.startsWith(m)&&_.charAt(m.length)==="/"),j={isActive:k,isPending:C,isTransitioning:y},P=k?s:void 0,M;typeof i=="function"?M=i(j):M=[i,k?"active":null,C?"pending":null,y?"transitioning":null].filter(Boolean).join(" ");let E=typeof a=="function"?a(j):a;return S.createElement(n_,Fl({},f,{"aria-current":P,className:M,ref:n,style:E,to:l,viewTransition:c}),typeof d=="function"?d(j):d)});var Td;(function(t){t.UseScrollRestoration="useScrollRestoration",t.UseSubmit="useSubmit",t.UseSubmitFetcher="useSubmitFetcher",t.UseFetcher="useFetcher",t.useViewTransitionState="useViewTransitionState"})(Td||(Td={}));var Yp;(function(t){t.UseFetcher="useFetcher",t.UseFetchers="useFetchers",t.UseScrollRestoration="useScrollRestoration"})(Yp||(Yp={}));function s_(t){let e=S.useContext(yc);return e||Ne(!1),e}function r_(t,e){let{target:n,replace:s,state:r,preventScrollReset:i,relative:o,viewTransition:a}=e===void 0?{}:e,l=ra(),c=fr(),d=bc(t,{relative:o});return S.useCallback(f=>{if(KS(f,n)){f.preventDefault();let h=s!==void 0?s:Il(c)===Il(d);l(t,{replace:h,state:r,preventScrollReset:i,relative:o,viewTransition:a})}},[c,l,d,s,r,n,t,i,o,a])}function i_(t,e){e===void 0&&(e={});let n=S.useContext(GS);n==null&&Ne(!1);let{basename:s}=s_(Td.useViewTransitionState),r=bc(t,{relative:e.relative});if(!n.isTransitioning)return!1;let i=pi(n.currentLocation.pathname,s)||n.currentLocation.pathname,o=pi(n.nextLocation.pathname,s)||n.nextLocation.pathname;return Rd(r.pathname,o)!=null||Rd(r.pathname,i)!=null}const o_="/api";class yy extends Error{constructor(n,s){super(s);$(this,"status");this.status=n,this.name="ApiError"}}async function W(t,e={}){const n=await fetch(o_+t,{...e,headers:e.body?{"Content-Type":"application/json",...e.headers||{}}:e.headers});if(!n.ok){let s=`Erro HTTP ${n.status}`;try{const r=await n.json();s=String(r.detail||r.mensagem||s)}catch{}throw new yy(n.status,s)}if(n.status!==204)return n.json()}const Ce=t=>({method:"POST",body:JSON.stringify(t)}),H={health:()=>W("/health"),doctor:()=>W("/doctor"),shutdown:()=>W("/shutdown",Ce({})),metricas:()=>W("/metrics"),leads:{listar:()=>W("/leads"),criar:t=>W("/leads",Ce(t)),atualizar:(t,e)=>W(`/leads/${t}`,{method:"PATCH",body:JSON.stringify(e)}),remover:t=>W(`/leads/${t}`,{method:"DELETE"}),importar:t=>W("/leads/import",Ce({leads:t})),enriquecer:t=>W(`/leads/${t}/enrich`,Ce({}))},crm:{leadsListar:()=>W("/crm/leads"),criarLead:t=>W("/crm/leads",Ce(t)),moverLead:(t,e)=>W(`/crm/leads/${t}/etapa`,{method:"PUT",body:JSON.stringify({etapa:e})}),sugestoes:()=>W("/crm/sugestoes"),aplicar:(t,e)=>W("/crm/sugestoes/aplicar",Ce({lead_id:t,para:e}))},campanhas:{listar:()=>W("/campaigns"),criar:t=>W("/campaigns",Ce(t)),status:(t,e)=>W(`/campaigns/${t}/status`,{method:"PUT",body:JSON.stringify({status:e})}),iniciar:t=>W(`/campaigns/${t}/start`,Ce({})),pausar:t=>W(`/campaigns/${t}/pause`,Ce({})),parar:t=>W(`/campaigns/${t}/stop`,Ce({})),remover:t=>W(`/campaigns/${t}`,{method:"DELETE"})},extrair:{maps:t=>W("/extractors/maps",Ce(t)),instagram:(t,e)=>W("/extractors/instagram",Ce({profile_url:t,limit:e})),cnpj:t=>W("/extract/cnpj",Ce({cnpj:t})),cnpjBusca:t=>W("/extract/cnpj/search",Ce(t)),cnpjExtract:t=>W("/extractors/cnpj",Ce(t))},config:{obter:()=>W("/config"),salvar:t=>W("/config",{method:"PUT",body:JSON.stringify(t)}),testarLlm:()=>W("/config/test/llm",Ce({})),testarIntegracao:t=>W("/config/test/integracao",Ce({url:t}))},integracoes:()=>W("/integrations/status"),agentes:{listar:()=>W("/agents"),status:(t,e)=>W(`/agents/${t}/status`,Ce({status:e})),salvarPrompt:(t,e)=>W(`/agents/${t}/prompt`,Ce({prompt:e})),templates:()=>W("/agents/templates"),salvarTemplates:t=>W("/agents/templates",{method:"PUT",body:JSON.stringify(t)}),testarTemplate:(t,e)=>W("/agents/templates/test",Ce({template:t,lead_id:e})),chat:t=>W("/agents/attendance/chat",Ce({mensagens:t}))},funil:()=>W("/funnel"),webhook:{obter:()=>W("/webhook"),salvar:t=>W("/webhook",{method:"PUT",body:JSON.stringify(t)}),testar:t=>W("/webhook/test",Ce({url:t}))}};function U(...t){return t.filter(Boolean).join(" ")}function a_(t){return(t||"?").trim().charAt(0).toUpperCase()||"?"}function zo(t){if(!t)return"—";try{return new Date(t).toLocaleString("pt-BR",{day:"2-digit",month:"2-digit",year:"2-digit",hour:"2-digit",minute:"2-digit"})}catch{return t}}function ia(t){const e=(t||"").replace(/\D/g,"");return e?e.length===11?`(${e.slice(0,2)}) ${e.slice(2,7)}-${e.slice(7)}`:e.length===10?`(${e.slice(0,2)}) ${e.slice(2,6)}-${e.slice(6)}`:t||"—":"—"}function l_(t){const e=["nome","telefone","email","empresa","cidade","observacoes"],n=e.filter(s=>String(t[s]||"").trim().length>0);return Math.round(n.length/e.length*100)}function c_(t){const e={nome:"nome",telefone:"telefone",email:"e-mail",empresa:"empresa",cidade:"cidade",observacoes:"observações"};return["nome","telefone","email","empresa","cidade","observacoes"].filter(s=>String(t[s]||"").trim().length===0).map(s=>e[s])}function u_(t,e){if(t>=100)return"Lead 100% completo — excelente! 🎉";const n=e.slice(0,2).join(" e ");return`Faltam ${100-t}% (${n}${e.length>2?"...":""}) para o lead ficar completo`}function d_(t,e){const n=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),r=document.createElement("a");r.href=s,r.download=e,r.click(),URL.revokeObjectURL(s)}const f_={md:"max-w-lg",lg:"max-w-2xl",xl:"max-w-4xl"};function qt({aberto:t,onFechar:e,titulo:n,children:s,icone:r="fas fa-circle-info",largura:i="md"}){return S.useEffect(()=>{const o=a=>{a.key==="Escape"&&e()};return t&&window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[t,e]),t?u.jsx("div",{className:"fixed inset-0 z-50 bg-black/40 flex items-center justify-center p-4",onMouseDown:o=>{o.target===o.currentTarget&&e()},children:u.jsxs("div",{className:U("bg-white rounded-2xl shadow-xl w-full",f_[i]),children:[u.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b border-gray-100",children:[u.jsxs("h3",{className:"text-base font-semibold text-gray-800 flex items-center gap-2",children:[u.jsx("i",{className:U(r,"text-indigo-500")})," ",n]}),u.jsx("button",{onClick:e,className:"text-gray-400 hover:text-gray-600","aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]}),u.jsx("div",{className:"px-6 py-5 max-h-[70vh] overflow-y-auto",children:s})]})}):null}const h_=[{icone:"fas fa-users",texto:"Cadastre leads manualmente ou importe pelos Extratores (Maps, Instagram, CNPJ)."},{icone:"fas fa-columns",texto:"Arraste os cards no CRM conforme avança no funil (Leads → Em contato → Proposta → Fechado)."},{icone:"fas fa-bullhorn",texto:"Monte campanhas de disparo com seus templates e acompanhe as taxas no Painel."},{icone:"fas fa-robot",texto:"Use os Agentes (disparo e atendimento) e configure o LLM em Ferramentas para turbiná-los."}];function p_({titulo:t,nomeUsuario:e}){const[n,s]=S.useState(!1);return u.jsxs("header",{className:"bg-white shadow-sm px-8 py-4 flex items-center justify-between shrink-0",children:[u.jsx("div",{children:u.jsx("h2",{className:"text-lg font-semibold text-gray-800",children:t})}),u.jsxs("div",{className:"flex items-center space-x-4",children:[u.jsxs("button",{onClick:()=>s(!0),className:"text-sm text-indigo-600 hover:text-indigo-800 font-medium",children:[u.jsx("i",{className:"fas fa-play-circle mr-1"})," Ver tutorial"]}),u.jsx("div",{className:"w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600 font-bold text-sm",children:a_(e)}),u.jsx("span",{className:"text-sm font-medium text-gray-700",children:e})]}),u.jsxs(qt,{aberto:n,onFechar:()=>s(!1),titulo:"Tutorial rápido",icone:"fas fa-graduation-cap",children:[u.jsx("ol",{className:"space-y-4",children:h_.map((r,i)=>u.jsxs("li",{className:"flex gap-3 items-start",children:[u.jsx("span",{className:"w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center shrink-0",children:u.jsx("i",{className:r.icone})}),u.jsx("p",{className:"text-sm text-gray-600 pt-1.5",children:r.texto})]},i))}),u.jsx("p",{className:"text-xs text-gray-400 mt-5",children:"Dica: o LLM (para enriquecimento e agentes) é configurado em Ferramentas."})]})]})}const g_=[{itens:[{para:"/",icone:"fas fa-chart-pie text-indigo-300",rotulo:"Painel",fim:!0}]},{secao:"Conexões",itens:[{para:"/leads",icone:"fas fa-users",rotulo:"Leads"},{para:"/agentes",icone:"fas fa-robot",rotulo:"Agentes"},{para:"/ferramentas",icone:"fas fa-tools",rotulo:"Ferramentas"}]},{itens:[{para:"/extrator-maps",icone:"fas fa-map-marked-alt",rotulo:"Extrator Maps"},{para:"/extrator-instagram",icone:"fab fa-instagram",rotulo:"Extrator Instagram"},{para:"/extrator-cnpj",icone:"fas fa-building",rotulo:"Extrator CNPJ"}]},{secao:"Gestão",itens:[{para:"/disparos",icone:"fas fa-bullhorn",rotulo:"Disparos"},{para:"/crm",icone:"fas fa-columns",rotulo:"CRM"},{para:"/funil",icone:"fas fa-filter",rotulo:"Funil de Prospecção"}]},{secao:"Integrações",itens:[{para:"/webhook",icone:"fas fa-link",rotulo:"Webhook"},{para:"/suporte",icone:"fas fa-headset",rotulo:"Suporte"}]}];function m_({onSair:t}){const e=fr(),[n,s]=S.useState(!1);S.useEffect(()=>{e.pathname==="/agentes"&&s(!0)},[e.pathname]);const r=i=>{if(i.rotulo==="Agentes")return e.pathname==="/agentes";const[o,a]=i.para.split("?");return a?e.pathname===o&&e.search.includes(a):i.fim?e.pathname===o:e.pathname.startsWith(o)};return u.jsxs("aside",{className:"w-64 bg-[#1e1b4b] text-white flex flex-col shrink-0 h-screen sticky top-0",children:[u.jsx("div",{className:"p-6 border-b border-gray-700",children:u.jsxs("h1",{className:"text-2xl font-bold tracking-tight flex items-center gap-2",children:[u.jsx("span",{className:"text-2xl",children:"⚡"}),"LeadMaster",u.jsxs("span",{className:"text-[10px] font-medium text-indigo-300 border border-indigo-400/40 rounded-md px-1.5 py-0.5",children:["v","0.1.24"]})]})}),u.jsx("nav",{className:"flex-1 overflow-y-auto py-4",children:u.jsx("ul",{className:"space-y-1",children:g_.map((i,o)=>u.jsx("li",{children:u.jsxs("ul",{children:[i.secao&&u.jsx("li",{className:"px-6 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider list-none",children:i.secao}),i.itens.map(a=>a.rotulo==="Agentes"?u.jsxs("li",{children:[u.jsxs("button",{type:"button",onClick:()=>s(l=>!l),className:U("sidebar-link w-full flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:U(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo}),u.jsx("i",{className:U("fas fa-chevron-down ml-auto text-xs text-gray-400 transition-transform",n&&"rotate-180")})]}),n&&u.jsxs("ul",{className:"pl-12 space-y-1 mt-1",children:[u.jsx("li",{children:u.jsx(Xp,{para:"/agentes?tab=disparo",rotulo:"Agente de Disparo",ativo:e.pathname==="/agentes"&&e.search.includes("disparo")})}),u.jsx("li",{children:u.jsx(Xp,{para:"/agentes?tab=atendimento",rotulo:"Agente de Atendimento",ativo:e.pathname==="/agentes"&&e.search.includes("atendimento")})})]})]},"agentes"):u.jsx("li",{children:u.jsxs(xy,{to:a.para,className:U("sidebar-link flex items-center px-6 py-2.5 text-sm",r(a)&&"active"),children:[u.jsx("i",{className:U(a.icone,"w-5 text-gray-400")}),u.jsx("span",{className:"ml-3",children:a.rotulo})]})},a.para))]})},o))})}),u.jsx("div",{className:"p-4 border-t border-gray-700",children:u.jsxs("button",{onClick:t,className:"w-full flex items-center justify-center px-4 py-2.5 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-lg text-sm font-medium hover:opacity-90 transition",children:[u.jsx("i",{className:"fas fa-sign-out-alt mr-2"})," Sair"]})})]})}function Xp({para:t,rotulo:e,ativo:n}){return u.jsx(xy,{to:t,className:U("sidebar-link block px-4 py-2 text-xs text-gray-300 rounded",n&&"active"),children:e})}const vy=S.createContext({toast:()=>{}});function tn(){return S.useContext(vy)}const x_={sucesso:"bg-green-600",erro:"bg-red-600",info:"bg-indigo-600"},y_={sucesso:"fas fa-check-circle",erro:"fas fa-exclamation-circle",info:"fas fa-info-circle"};function v_({children:t}){const[e,n]=S.useState([]),s=S.useRef(0),r=S.useCallback((i,o)=>{const a=++s.current;n(l=>[...l,{id:a,tipo:i,mensagem:o}]),setTimeout(()=>n(l=>l.filter(c=>c.id!==a)),4500)},[]);return u.jsxs(vy.Provider,{value:{toast:r},children:[t,u.jsx("div",{className:"fixed top-4 right-4 z-[100] space-y-2 w-80",children:e.map(i=>u.jsxs("div",{className:U(x_[i.tipo],"text-white text-sm rounded-lg shadow-lg px-4 py-3 flex items-start gap-2 animate-pulse-once"),role:"status",children:[u.jsx("i",{className:U(y_[i.tipo],"mt-0.5")}),u.jsx("span",{className:"flex-1",children:i.mensagem}),u.jsx("button",{className:"opacity-70 hover:opacity-100",onClick:()=>n(o=>o.filter(a=>a.id!==i.id)),"aria-label":"Fechar",children:u.jsx("i",{className:"fas fa-times"})})]},i.id))})]})}function Oa({rotulo:t,valor:e,subtitulo:n,children:s,icone:r}){return u.jsxs("div",{className:"bg-white rounded-xl shadow-sm p-5 border border-gray-100",children:[u.jsxs("div",{className:"flex items-center justify-between",children:[u.jsx("p",{className:"text-sm text-gray-500 font-medium",children:t}),r&&u.jsx("i",{className:`${r} text-indigo-300`})]}),s??u.jsxs(u.Fragment,{children:[u.jsx("p",{className:"text-2xl font-bold text-gray-800 mt-1",children:e}),n&&u.jsx("p",{className:"text-xs text-gray-400 mt-0.5",children:n})]})]})}/*!
68
68
  * @kurkle/color v0.3.4
69
69
  * https://github.com/kurkle/color#readme
70
70
  * (c) 2024 Jukka Kurkela
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>LeadMaster — Painel</title>
8
- <script type="module" crossorigin src="/assets/index-Bc1EFZVI.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-B_SzrvJP.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-ViDiQGJH.css">
10
10
  </head>
11
11
  <body class="bg-gray-100 min-h-screen">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danhachuel/leadmaster",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "SaaS local de prospecção e automação: CRM, extratores de leads e agentes de IA — 100% local.",
5
5
  "license": "MIT",
6
6
  "author": "Dan Hachuel",
package/scripts/cli.mjs CHANGED
@@ -690,6 +690,16 @@ function cmdStart(args) {
690
690
  // nem de npx — NUNCA REMOVER.
691
691
  process.stdin.resume();
692
692
 
693
+ // Rede de segurança (regra inviolável do AGENTS.md): se o event loop
694
+ // esvaziar (stdin em EOF, timer perdido, qualquer surpresa do terminal/
695
+ // PTY do MobaXterm), o Node re-ativa o keep-alive no 'beforeExit' em vez
696
+ // de encerrar — o prompt NUNCA é devolvido e o uvicorn não fica órfão.
697
+ // Erros no stream de stdin também nunca derrubam o launcher.
698
+ process.stdin.on('error', () => {});
699
+ process.on('beforeExit', () => {
700
+ setInterval(() => {}, 1000);
701
+ });
702
+
693
703
  console.log(`✓ LeadMaster no ar em ${url} (dados: ${home})`);
694
704
  console.log('');
695
705
  console.log(`ℹ Abra ${url} no navegador quando quiser — o LeadMaster nunca abre janelas sozinho.`);